场景问题
dubbo超时机制导致的雪崩连接
异常描述
1. 中台Dubbo服务提供者(provider)出现无法获取Dubbo服务处理线程异常 2. 后台出现无法获取数据库连接池的异常 3. 前台响应时间异常飙高 4. 系统处理能力下降,核心基础服务无法提供正常服务模拟场景
1. dubbo服务DemoService/** * dubboDemoService */ public class DemoServiceImpl implements DemoService { public String sayHello(String name) { System.out.println("[" + newSimpleDateFormat("HH:mm:ss").format(new Date()) + "] Hello " + name + ",request from consumer: " + RpcContext.getContext().getRemoteAddress()); return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); } /** * DemoServiceprintUUID * @param uuid * @return */ public String printUUID(String uuid) { System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + "] UUID:" + uuid + ",request from consumer: " + RpcContext.getContext().getRemoteAddress()); try { Thread.sleep(30000); // 睡30s } catch (InterruptedException e) { e.printStackTrace(); } return "UUID " + uuid + ", response from provider: " + RpcContext.getContext().getLocalAddress(); } }
2. 服务提供者用Spring xml配置声明暴露服务
3. 服务消费者通过Spring配置引用远程服务
4. 服务消费者创建多线程调用100次dubbo服务
public class DemoAction { private DemoService demoService; public void setDemoService(DemoService demoService) { this.demoService = demoService; } /** * 100 DemoService * @throws Exception */ public void start() throws Exception { for (int i = 0; i模拟结果
1. dubbo服务提供者报错日志分析: dubbo线程池耗尽 ;从日志中我们可以看到线程池的大小为200 问题:我们服务消费者只创建了100个线程调用dubbo服务,为什么会导致线程超过200?2. dubbo服务消费者报错日志分析:从日志中可以看出调用执行DemoService的printUUID方法超时(timeout默认5000ms)。由于我们 的dubbo重试机制,如果调用一直超时,dubbo框架会默认再创建线程重试调用3次,所以如果没有dubbo线程池的限制以及一直调用服务超时的问题,消费者会一共调用400次,这就解答了问题1中dubbo服务提供者的线程池耗尽的异常了。
问题分析以及解决方案
方案1. 将dubbo的线程池设置为更大值,处理高并发调用服务的问题
方案2. 关闭dubbo消费端重试机制,防止服务调用超时后重试机制导致的耗费dubbo线程池的问题以及后台数据库连接池的耗费。
方案3、也可以同时给服务提供者和消费者的配置中都增加超时时间,出现问题后快速熔断,超时频发时并告警通知到研发人员