介绍:Dubbo是一个轻量级的开源Java服务框架,是很多企业搭建分布式服务架构的首选。中国工商银行自2014年开始探索分布式架构转型,自主研发了基于开源Dubbo的分布式服务平台。作者|严高飞来源|阿里云原生公众号Dubbo是一个轻量级的开源Java服务框架,是很多企业搭建分布式服务架构的首选。中国工商银行自2014年开始探索分布式架构转型,自主研发了基于开源Dubbo的分布式服务平台。Dubbo框架在提供者和消费者数量少的服务规模下运行稳定,性能良好。随着对网上银行、多元化、智能化的需求越来越强烈,在可预见的未来,将出现一个提供商为数千甚至数万消费者提供服务的场景。在如此高的负载下,如果服务器程序设计不够好,网络服务在处理数万个客户端连接时可能会出现低效甚至完全瘫痪的情况,这就是C10K问题。那么,基于Dubbo的分布式服务平台能否应对复杂的C10K场景呢?为此,我们搭建了大规模的连接环境,模拟服务调用,进行了一系列的探索和验证。C10K场景下,Dubbo服务调用1出现大量事务失败,准备环境使用Dubbo2.5.9(默认netty版本为3.2.5.Final)编写服务提供者和对应的服务消费者。provider的service方法中没有实际的业务逻辑,只是sleep100ms;consumer端配置servicetimeout为5s,每个consumer启动后每分钟调用一次service。一台8C16G服务器准备容器化部署一个服务提供者,数百台8C16G服务器准备容器化部署7000个服务消费者。启动Dubbo监控中心,监控服务调用。2.自定义验证场景,观察验证结果不理想。C10K场景下,Dubbo服务调用超时失败。如果分布式服务调用耗时较长,从服务消费者到服务提供者的整个链路节点将长期占用线程池资源,增加额外的性能损耗。但是,当并发服务调用突然增加时,很容易造成全链路节点拥塞,进而影响其他服务调用,进而导致整个服务集群性能下降甚至整体不可用,导致雪崩。服务调用超时的问题不容忽视。因此,我们对这个C10K场景下的Dubbo服务调用超时失败进行了详细的分析。C10K场景问题分析根据服务调用交易环节,我们首先怀疑交易超时是由于提供者或消费者自身进程卡顿或网络延迟造成的。因此,我们在事务失败的provider和consumer服务器上打开进程gclog,多次打印进程jstack,在宿主机抓包。1.观察gc日志,jstackprovider,consumer进程gc时长,gc间隔,内存占用,线程堆栈等,没有明显异常,暂时排除猜想,比如gc触发stoptheworld导致超时,或者不当线程设计导致阻塞和超时。2.观察两种场景下失败的交易。对于以上两种场景下失败的交易,分别观察网络抓包,对应以下两种不同的现象:对于场景一:提供者网络抓包稳定运行期间的交易超时跟踪以及提供者和消费者交易日志。消费者发起服务调用请求后,提供者快速捕获消费者的请求消息,但提供者从收到请求消息到开始处理事务需要2s+。同时观察交易请求响应的数据流向。从提供者的业务方法处理到返回包发送给消费者也需要2s+,之后消费者很快收到交易返回消息。但是此时总事务时间已经超过5s,超过服务调用超时时间,导致抛出超时异常。因此判断事务超时的原因不在消费者端,而在提供者端。针对场景二:提供者重启后发起大量事务超时服务调用请求,提供者很快收到消费者的请求消息,但提供者通常不会向应用层提交事务消息,而是回复一条RST消息,事务超时并失败。provider重启后1-2分钟内观察到大量RST包。通过部署脚本,provider重启后每10ms打印一次established状态的连接数,发现provider重启后连接数并没有很快恢复到7000,而是需要1-2分钟连接数恢复正常值。在此过程中,在消费者端逐一查询与提供者的连接状态,均已建立,怀疑是提供者单方面连接。我们继续分别分析这两种异常情况。场景一:提供者在实际交易前后耗时较长,导致交易超时。精细采集provider的运行状态和性能指标:在provider的服务器上每3s采集一次服务provider的jstack,观察nettyworkerthread每60s左右频繁处理心跳。同时打印top-H,观察到占用CPU时间片较多的前10个线程中有9个netty工作线程。由于providerserver是8C,Dubbo默认有9个nettyworker线程,也就是9个nettyworker线程都比较忙。部署服务器系统性能收集工具nmon,观察CPU每隔60秒左右产生一次毛刺;网络数据包的数量也同时出现了故障。部署ss-ntp,持续打印网络接收队列和发送队列中的数据积压。据观察,队列在耗时的事务时间附近累积得更多。在Dubbo服务框架中,提供者和消费者发送心跳消息(消息长度为17)的周期为60s,与上述间隔接近。结合网络抓包,在耗时交易时间点附近心跳包较多。根据Dubbo框架的心跳机制,当消费者数量较多时,提供者发送心跳消息,需要应答的消费者心跳消息会比较密集。因此怀疑心跳密集导致netty线程繁忙,影响了事务请求的处理,进而导致事务时间增加。进一步分析nettyworker线程的运行机制,记录每个nettyworker线程在处理连接请求、处理写队列、处理selectKeys三个关键环节的处理时间。观察到每间隔60s左右(与心跳间隔一致)处理和读取的数据包较多,耗时较长,期间交易时间有所增加。同时观察网络抓包,provider收到的心跳包比较多。因此,上述猜测得到证实。密集的心跳导致netty工作线程繁忙,导致事务时间增加。场景二:单边连接导致事务超时单边连接的原因分析TCP建立连接的三次握手过程中,如果全连接队列已满,会导致单边连接.全连接队列的大小由系统参数net.core.somaxconn的最小值和listen(somaxconn,backlog)的backlog决定。somaxconn是Linux内核的一个参数,默认值为128;backlog是在创建Socket的时候设置的,在Dubbo2.5.9中默认的backlog值为50,所以生产环境的全连接队列为50,通过ss命令(Socket)也发现全连接队列大小为50统计数据)。观察TCP连接队列,确认有满连接队列溢出现象。即:全连接队列容量不足导致出现大量单边连接。在这种验证场景中,订阅提供者的消费者数量过多。当provider重启时,注册中心向consumer推送provider上线通知,所有consumer几乎同时重新连接provider,导致fullconnectionqueue溢出。.单边连接影响范围分析单边连接的影响范围多为消费者的第一笔交易,偶尔也有连续2-3笔交易失败的第一笔交易。在单边建立的连接下,交易不一定会失败。三路握手全连接队列满后,如果半连接队列空闲,provider创建定时器重传syn+ack给consumer。重传默认5次,重传间隔按倍数递增,1s..2s..4s..共31s。在重传次数内,如果满连接队列返回空闲,则消费者响应ack,连接建立成功。至此交易成功。在重传次数内,如果全连接队列仍然繁忙,则新事务将在达到超时时间后失败。达到重传次数后,连接断开。此后,消费者发送请求,提供者回复RST。事务到达超时时间后失败。根据Dubbo的服务调用模型,提供者发送RST后,消费者抛出Connectionresetbypeer异常,然后与提供者断开连接。但是消费者收不到当前交易的响应消息,导致超时异常。同时,消费者的计时器每2秒检测一次与提供者的连接。如果连接异常,则发起重连,恢复连接。此后交易一直正常。三、C10K场景问题分析总结上面事务超时的原因有两个:心跳机制导致netty工作线程繁忙。在每个心跳任务中,提供者向所有在1个心跳周期内没有发送或接收消息的消费者发送心跳;消费者向所有在1个心跳周期内没有发送或接收消息的提供者发送心跳。连接到提供者的消费者很多,导致心跳包堆积;同时,处理心跳的过程会消耗较多的CPU,影响业务包的处理时间。全连接队列容量不足。provider重启后,队列溢出,导致大量单边连接。单边连接下的第一个事务超时失败的概率很高。4、接下来思考上面的场景1:如何减少单个netty工作线程处理心跳的时间,加快IO线程的运行效率?初步设想如下方案:减少单次心跳的处理时间,增加netty工作线程数,减少单IO线程的负载,打散心跳,避免密集处理。对于上面的场景2:如何避免第一次大量半连接导致的事务失败?设想了以下方案:增加TCP全连接队列长度,涉及操作系统、容器、Netty,提高服务端accept连接的速度,提高事务消息的处理效率。1.层层优化进行了大量优化,提升C10K场景下的事务处理效率,提升服务调用的执行能力。优化内容包括以下几个方面:具体涉及优化的框架层如下:逐项验证各项优化内容后,各项措施均有不同程度的改进,效果如下:二、综合优化验证效果以上优化结果综合应用效果最佳。在这个1个provider连接7000个consumer的验证场景下,重启provider后,没有出现长时间运行的事务超时场景。优化前后对比,provider的CPU峰值降低了30%,consumer和provider的处理时间差控制在1ms以内,P99交易时间从191ms降低到125ms。在提高交易成功率的同时,有效减少消费者的等待时间,减少服务运行的资源占用,提高系统稳定性。3、实际上线运行效果基于以上验证结果,工行在分布式服务平台中集成了以上优化内容。截至发布之日,已经有数万消费者连接到一个供应商的在线场景。落地优化后的版本,经过提供商的版本升级和长期运行,未出现异常事务超时,实际运行效果符合预期。未来展望中国工商银行深度参与了Dubbo社区的建设,在金融层面大规模应用Dubbo的过程中遇到了很多技术挑战。服务系统的扩展和定制,不断提升服务系统的稳定性,以“源于开源,回馈开源”的理念,不断为开源社区贡献通用增强能力。未来,我们将继续致力于Dubbo的金融级规模化应用,与社区合作,持续提升Dubbo的性能能力和高可用水平,加速金融行业数字化创新转型和数字化转型。全面自主和控制的核心关键。作者简介严高飞是微服务领域的架构师。主要从事服务发现和高性能网络通信的研究与开发。擅长ZooKeeper、Dubbo、RPC协议等技术方向。PC端登录start.aliyun.com了解动手实验室,沉浸式体验在线互动教程。版权声明:本文内容由阿里云实名注册用户投稿,版权归原作者所有。阿里云开发者社区不拥有自己的版权,也不承担相应的法律责任。具体规则请参考《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如发现本社区涉嫌抄袭内容,请填写侵权投诉表进行举报,一经查实,本社区将立即删除涉嫌侵权内容。
