BUG作者: 许晓
Bug 标题: Dubbo超时机制导致的雪崩连接
Bug 影响: Dubbo 服务提供者出现无法获取 Dubbo 服务处理线程异常,后端 DB爆出拿不到数据库连接池,导致前端响应时间异常飙高,系统处理能力下降,核心基础服务无法提供正常服务。
Bug 发现过程:
线 上,对于高并发的服务化接口应用,时常会出现Dubbo连接池爆满情况,通常,我们理所应当的认为,这是客户端并发连接过高所致,一方面调整连接池大小, 一方面考虑去增加服务接口的机器,当然也会考虑去优化服务接口的应用。很自然的,当我们在线上压测一个营销页面(为大促服务,具备高并发)时,我们遇到了 这种情况。而通过不断的深入研究,我发现了一个特别的情况。
场景描述:
压力从Jmeter压至前端web应用marketingfront,场景是批量获取30个产品的信息。wsproductreadserver有一个批量接口,会循环从tair中获取产品信息,若缓存不存在,则命中db。
压测后有两个现象:
1) Dubbo的服务端爆出大量连接拿不到的异常,还伴随着无法获取数据库连接池的情况
2) Dubbo Consumer端有大量的Dubbo超时和重试的异常,且重试3次后,均失败。
3) Dubbo Consumer端的最大并发时91个
Dubbo Provider端的最大并发却是600个,而服务端配置的dubbo最大线程数即为600。
这个时候,出于性能测试的警觉性,发现这两个并发数极为不妥。
按照正常的请求模式,DubboConsumer和DubboProvider展示出来的并发应该是一致的。此处为何会出现服务端的并发数被放大6倍,甚至有可能不止6倍,因为服务端的dubbo连接数限制就是600。
此处开始发挥性能测试各种大胆猜想:
1)是否是因为服务端再dubboServerHandle处理请求时,开启了多线程,而这块儿的多线程会累计到Dubbo的连接上,dragoon采集的这个数据可以真实的反应目前应用活动的线程对系统的压力情况;
2)压测环境不纯洁?我的小伙伴们在偷偷和我一起压测?(这个被我生生排除了,性能测试基本环境还是要保持独立性)
3)是否是因为超时所致?这里超时会重试3次,那么顺其自然的想,并发有可能最多会被放大到3倍,3*91=273<<600....还是不止3倍?
有了猜想,就得小心求证!
首先通过和dubbo开发人员 【草谷】分析,Dubbo连接数爆满的原因,猜想1被否决,Dubbo服务端连接池是计数DubboServerHandle个数的业务是否采用多线程无关。
通过在压测时,Dump provider端的线程数,也证明了这个。
那么,可能还是和超时有很大关系。
再观察wsproductreadserver接口的处理时间分布情况:
从 RT 的分布来看 。基本上 78.5% 的响应时间是超过 1s 的。那么这个接口方法的 dubbo 超时时间是 500ms ,此时 dubbo 的重试机制会带来怎样的 雪崩效应 呢?
如果按照上图,虽然客户端只有1个并发在做操作,但是由于服务端执行十分耗时,每个请求的执行RT远远超过了超时时间500ms,此时服务端的最大并发会有多少呢?
和服务端处理的响应时间有特比特别大的关系。服务端处理时间变长,但是如果超时,客户端的阻塞时间却只有可怜的500ms,超过500ms,新一轮压力又将发起。
上图可直接看到的并发是8个,如果服务端RT再长些,那么并发可能还会再大些!
这也是为什么从marketingfront consumer的dragoon监控来看,只有90个并发。但是到服务端,却导致dubbo连接池爆掉的直接原因。
查看了wsproductreadserver的堆栈,600个dubboServerHandle大部分都在做数据库的读取和数据库连接获取以及tair的操作。
所以,为什么Dubbo服务端的连接池会爆掉?很有可能就是因为你的服务接口,在高并发下的大部分RT分布已经超过了你的Dubbo设置的超时时间!这将直接导致Dubbo的重试机制会不断放大你的服务端请求并发。
所 以如果,你在线上曾经遇到过类似场景,您可以采取去除Dubbo的重试机器,并且合理的设置Dubbo的超时时间。目前国际站的服务中心,已经开始去除 Dubbo的重试机制。当然Dubbo的重试机制其实是非常好的QOS保证,它的路由机制,是会帮你把超时的请求路由到其他机器上,而不是本机尝试,所以 dubbo的重试机器也能一定程度的保证服务的质量。但是请一定要综合线上的访问情况,给出综合的评估。
------------ 等等等,别着急,我们似乎又忽略了一些细节,元芳,你怎么看? ------------------------
我们重新回顾刚才的业务流程架构,wsproductReadserver层有DB和tair两级存储。那么对于同样接口为什么服务化的接口RT如此之差,按照前面提到的架构,包含tair缓存,怎么还会有数据库连接获取不到的情况?
接续深入追踪,将问题暴露和开发讨论,他们拿出tair
可以看到,客户端提交批量查询30个产品的产品信息。在服务端,有一个缓存模块,缓存的key是产品的ID。当产品命中tair时,则直接返回,若不命中,那么回去db中取数,再放入缓存中。
这里可以发现一个潜在的性能问题:
客 户端提交30个产品的查询请求,而服务端,则通过for循环和tair交互,所以这个接口在通常情况下的性能估计也得超过60-100ms。如果不是30 个产品,而是50或者100,那么这个接口的性能将会衰减的非常厉害!(这纯属性能测试的yy,当然这个暂时还不是我们本次关注的主要原因)
那么如此的架构,请求打在db上的可能性是比较小的, 由缓存命中率来保证。从线上真实的监控数据来看,tair的命中率在70%,应该说还不错,为什么在我们的压测场景,DB的压力确是如此凶残,甚至导致db的连接池无法获取呢?
所以性能验证场景就呼之欲出了:
场景: 准备30个产品ID,保持不变,这样最多只会第一次会去访问DB,并将数据存入缓存,后面将会直接命中缓存,db就在后面喝喝茶好了!
但是从测试结果来看,有两点可以观察到:
1)
2)
3)
于是开始检查这30个产品到底有哪几个没有存入缓存。
通 过开发Debug预发布环境代码,最终发现,这两个产品竟然已经被用户移到垃圾箱了。而通过和李浩和跃波沟通SellerCoponList的业务来 看,DA推送过来的产品是存在被用户移除的可能性。因而,每次这两个数据的查询,由于数据库查询不到记录,tair也没有存储相关记录,导致这些查询都将 经过数据库。数据库压力原因也找到了。
但是问题还没有结束,这似乎只像是冰山表面,我们希望能够鸟瞰整个冰山!
细细品味这个问题的最终性能表象 , 这是一种变向击穿缓存的做法啊!也就是具备一定的通用性。如果接口始终传入数据库和缓存都不可能存在的数据,那么每次的访问都就落到db上,导致缓存变相击穿,这个现象很有意思!
目前有一种解决方案,就是Null Object Pattern,将数据库不存在的记录也记录到缓存中,但是value为NULL,使得缓存可以有效的拦截。由于数据的超时时间是10min,所以如果数据有所改动,也可以接受。
我相信这只是一种方案,可能还会有其他方案,但是这种变向的缓存击穿却让我很兴奋。回过头来,如果让我自己去实现这样的缓存机制,数据库和缓存都不存在的 数据场景很容易被忽略,并且这个对于业务确实也不会有影响。在线上存在大量热点数据情况下,这样的机制,往往并不会暴露性能问题。巧合的是,特定的场景, 性能却会出现很大的偏差,这考验的既是性能测试工程师的功力,也考验的是架构的功力!
Bug 解决办法:
其实这过程中不仅仅有一些方法论,也有一些是性能测试经验的功底,更重要的是产出了一些通用性的性能问题解决方案,以及部分参数和技术方案的设计对系统架构的影响。
1)对于核心的服务中心,去除dubbo超时重试机制,并重新评估设置超时时间。
2)对于存在tair或者其他中间件缓存产品,对NULL数据进行缓存,防止出现缓存的变相击穿问题
GBA 传承:
个人感受:
1)性能调优和诊断是一个不断挖掘的过程,不放过一个细节点,大胆猜想,小心求证
2)敢于质疑开发的建议和解决方案,提出自己的思路,并求证
3)勇于专研。性能调优就像追求自己心仪的女孩,有时努力了很久却没有任何结果,但是心动的感觉却是一生仅有的。
相关推荐
如果没有适当的服务熔断机制,一旦某个服务出现问题,调用该服务的其他服务将会持续不断地尝试调用直至超时,这样不仅会造成大量系统资源的浪费,还可能导致调用者服务由于长时间等待响应而变得不可用,进一步影响...
6. 超时与重试:Dubbo提供了超时机制和重试策略,以应对网络延迟或服务不稳定的情况。 7. 异常处理:当服务调用失败时,Dubbo会进行异常处理,如抛出异常、重试或回退至备用服务。 8. 返回结果:调用成功后,服务...
3. 熔断机制:当服务调用频繁失败时,Dubbo可启用熔断机制,避免雪崩效应。 五、服务监控 1. 日志监控:Dubbo支持日志输出,帮助开发者追踪服务调用的详细信息,便于问题定位。 2. Metrics统计:通过监控服务调用...
6. **配置(Config)**:Dubbo 提供了 XML、API 和 Spring 注解等多种方式进行服务的配置,包括服务的元数据、服务版本、超时时间等。 在提供的 "dubbo_provide_demo" 文件中,我们可以看到服务提供者的实现。这...
在高并发或网络延迟的情况下,为了防止服务雪崩,Dubbo 支持服务降级机制。可以通过设置超时时间、重试次数等参数来实现自动降级。 #### 2.3 限流 为了保护服务不被大量的请求冲击,Dubbo 提供了限流功能。通过限制...
- 调整Dubbo的超时时间、重试次数、连接池大小等参数。 - 使用Dubbo Admin图形界面监控服务状态。 - 分析服务调用日志,排查性能瓶颈。 通过这个资源包,学习者不仅可以理解Dubbo的基本概念,还能通过实践案例...
5. **熔断与降级**:为应对服务故障,Dubbo提供了服务熔断和降级机制,保护系统免受雪崩效应的影响,提高系统的稳定性。 6. **服务治理**:包括服务的注册、发现、调用、超时、重试、隔离等策略,方便进行服务治理和...
4. **服务限流**:通过限制服务的并发调用,防止系统因流量激增而导致雪崩效应。 四、实战应用 在实际项目中,Dubbo被广泛应用于大型分布式系统,如电商平台、社交网络等。通过使用Dubbo,可以将复杂的业务逻辑...
Dubbo的核心功能包括服务注册与发现、负载均衡、容错机制、流量控制、服务治理等,广泛应用于微服务架构中。 **详细知识点:** 1. **Dubbo架构**:Dubbo采用服务提供者、消费者、注册中心和服务监控的四层架构模型...
4. 限流与熔断:通过Hystrix等工具,实现服务的限流保护和熔断机制,防止雪崩效应。 六、最佳实践 1. 合理规划服务接口:接口设计应遵循单一职责原则,避免大而全的接口。 2. 使用版本管理:在升级服务时,建议使用...
Dubbo会根据这些信息在运行时自动连接到对应的服务提供者。 5. **服务调用组件**:Dubbo提供了多种服务调用方式,如同步调用、异步调用、回调调用等,开发者可以根据业务需求选择合适的调用模式。 6. **扩展点**:...
- 熔断和降级机制可以防止服务雪崩,提高系统的整体稳定性。 8. **SPI扩展机制** - SPI(Service Provider Interface)允许开发者自定义扩展点,如协议、序列化方式等。 - 通过`META-INF/services`目录下的配置...
此外,还会涉及服务暴露的元数据配置,如服务版本、超时时间、重试策略等。 【详细知识点五】:服务消费者的安装与调用 服务消费者则是调用服务提供者接口的组件。手册将指导读者如何创建服务消费者项目,订阅并...
熔断机制则能防止服务雪崩,保护整个系统的稳定性。 9. **API 文档**:dubbo-admin 可以自动生成服务的 API 文档,方便开发人员理解和使用服务。 10. **扩展性**:dubbo-admin 的设计考虑了扩展性,允许开发者根据...
4. **重试机制**:在服务调用过程中,由于网络抖动或其他原因可能导致请求失败。Dubbo允许配置重试次数,如果第一次调用失败,会按照设定的策略自动进行重试,以增加请求成功的概率。 5. **监控与日志**:为了更好...
- 解决Dubbo服务雪崩的策略。 - Dubbo服务版本控制和接口兼容性设计。 6. **最佳实践:** - 高可用配置:如何设置多注册中心,实现主备切换。 - 性能优化:如缓存策略、连接池大小设置、序列化方式选择等。 - ...
可以设置服务调用的超时时间和重试次数,超时后会自动触发重试机制。 14. **Dubbo如何实现服务的版本管理?** 通过服务接口或实现类的版本注解,可以区分不同版本的服务。 15. **Dubbo的SPI机制是什么?** 服务...
4. **熔断与降级**:Dubbo提供了Hystrix组件进行服务熔断和降级处理,当服务出现异常或超时时,可以快速返回一个默认值或执行备用逻辑,防止服务雪崩。 5. **监控与日志**:集成Dubbo-admin进行服务治理,可以实时...
- 合理设置服务的超时时间和重试策略,避免雪崩效应。 通过这个简单的Dubbo官网入门Demo,初学者可以快速了解Dubbo的基本架构和工作流程,为进一步深入学习和使用Dubbo打下基础。在实际项目中,还需要结合具体的...