工商银行分布式服务 C10K 场景解决方案

标签: 工商银行 分布 服务 | 发表时间:2021-05-11 21:46 | 作者:阿里巴巴云原生
出处:http://weekly.dockone.io

头图.png

作者 | 颜高飞
来源 | 阿里巴巴云原生公众号

Dubbo 是一款轻量级的开源 Java 服务框架,是众多企业在建设分布式服务架构时的首选。中国工商银行自 2014 年开始探索分布式架构转型工作,基于开源 Dubbo 自主研发了分布式服务平台。

Dubbo 框架在提供方消费方数量较小的服务规模下,运行稳定、性能良好。随着银行业务线上化、多样化、智能化的需求越来越旺盛,在可预见的未来,会出现一个提供方为数千个、甚至上万个消费方提供服务的场景。

在如此高负载量下,若服务端程序设计不够良好,网络服务在处理数以万计的客户端连接时、可能会出现效率低下甚至完全瘫痪的情况,即为 C10K 问题。那么,基于 Dubbo 的分布式服务平台能否应对复杂的 C10K 场景?为此,我们搭建了大规模连接环境、模拟服务调用进行了一系列探索和验证。

C10K 场景下 Dubbo 服务调用出现大量交易失败

1. 准备环境

使用 Dubbo2.5.9(默认 netty 版本为 3.2.5.Final)版本编写服务提供方和对应的服务消费方。提供方服务方法中无实际业务逻辑、仅 sleep 100ms;消费方侧配置服务超时时间为 5s,每个消费方启动后每分钟调用1次服务。

准备 1 台 8C16G 服务器以容器化方式部署一个服务提供方,准备数百台 8C16G 服务器以容器化方式部署 7000 个服务消费方。

启动 Dubbo 监控中心,以监控服务调用情况。

2. 定制验证场景,观察验证结果



验证情况不尽如人意。C10K 场景下 Dubbo 服务调用存在超时失败的情况。

如果分布式服务调用耗时长,从服务消费方到服务提供方全链路节点都会长时间占用线程池资源,增加了额外的性能损耗。而当服务调用并发突增时,很容易造成全链路节点堵塞,从而影响其他服务的调用,并进一步造成整个服务集群性能下降甚至整体不可用,导致发生雪崩。服务调用超时问题不可忽视。因此,针对该 C10K 场景下 Dubbo 服务调用超时失败情况我们进行了详细分析。

C10K 场景问题分析

根据服务调用交易链路,我们首先怀疑交易超时是因为提供方或消费方自身进程卡顿或网络存在延迟导致的。



因此,我们在存在交易失败的提供方、消费方服务器上开启进程 gc 日志,多次打印进程 jstack,并在宿主机进行网络抓包。

1. 观察 gc 日志、jstack

提供方、消费方进程 gc 时长、gc 间隔、内存使用情况、线程堆栈等无明显异常,暂时排除 gc 触发 stop the world 导致超时、或线程设计不当导致阻塞而超时等猜想。

2. 针对两种场景下的失败交易进行观察

针对以上两种场景下的失败交易,分别观察网络抓包,对应有以下两种不同的现象:

针对场景 1:提供方稳定运行过程中交易超时

跟踪网络抓包及提供方、消费方交易日志。消费方发起服务调用请求发起后,在提供方端迅速抓到消费方请求报文,但提供方从收到请求报文到开始处理交易耗时 2s+。



同时,观察交易请求响应的数据流。提供方业务方法处理完毕后到向消费方发送回包之间也耗时 2s+,此后消费方端迅速收到交易返回报文。但此时交易总耗时已超过 5s、超过服务调用超时时间,导致抛出超时异常。



由此,判断导致交易超时的原因不在消费方侧,而在提供方侧

针对场景 2:提供方重启后大量交易超时

服务调用请求发起后,提供方迅速收到消费方的请求报文,但提供方未正常将交易报文递交给应用层,而是回复了 RST 报文,该笔交易超时失败。



观察在提供方重启后 1-2 分钟内出现大量的 RST 报文。通过部署脚本,在提供方重启后每隔 10ms 打印 established 状态的连接数,发现提供方重启后连接数未能迅速恢复到 7000,而是经过 1-2 分钟后连接数才恢复至正常数值。而在此过程中,逐台消费方上查询与提供方的连接状态,均为 established,怀疑提供方存在单边连接情况。

我们继续分别分析这两种异常场景。

场景 1:提供方实际交易前后均耗时长、导致交易超时

细化收集提供方的运行状态及性能指标:
  1. 在提供方服务器上每隔 3s 收集服务提供方 jstack,观察到 netty worker 线程每 60s 左右频繁处理心跳。
  2. 同时打印 top -H,观察到占用 CPU 时间片较多的线程排名前 10 中包含 9 个 netty worker 线程。因提供方服务器为 8C,Dubbo 默认 netty worker 线程数为 9 个,即所有 9 个 netty worker 线程均较忙碌。



  1. 部署服务器系统性能采集工具 nmon,观察到 CPU 每隔 60 秒左右产生毛刺;相同时间网络报文数也有毛刺。



  1. 部署 ss -ntp 连续打印网络接收队列、发送队列中的数据积压情况。观察到在耗时长的交易时间点附近队列堆积较多。



  1. Dubbo 服务框架中提供方和消费方发送心跳报文(报文长度为 17)的周期为 60s,与以上间隔接近。结合网络抓包,耗时长的交易时间点附近心跳包较多。




根据 Dubbo 框架的心跳机制,当消费方数量较大时,提供方发送心跳报文、需应答的消费方心跳报文将会很密集。因此,怀疑是心跳密集导致 netty 线程忙碌,从而影响交易请求的处理,继而导致交易耗时增加。



进一步分析 netty worker 线程的运行机制,记录每个 netty worker 线程在处理连接请求、处理写队列、处理 selectKeys 这三个关键环节的处理耗时。观察到每间隔 60s 左右(与心跳间隔一致)处理读取数据包较多、耗时较大,期间存在交易耗时增加的情况。同一时间观察网络抓包,提供方收到较多的心跳报文。



因此,确认以上怀疑。心跳密集导致 netty worker 线程忙碌,从而导致交易耗时增长。

场景 2:单边连接导致交易超时

  • 分析单边连接产生的原因


TCP 建立连接三次握手的过程中,若全连接队列满,将导致单边连接。



全连接队列大小由系统参数 net.core.somaxconn 及 listen(somaxconn,backlog) 的 backlog 取最小值决定。somaxconn 是 Linux 内核的参数,默认值是 128;backlog 在创建 Socket 时设置,Dubbo2.5.9 中默认 backlog 值是 50。因此,生产环境全连接队列是 50。通过 ss 命令(Socket Statistics)也查得全连接队列大小为 50。



观察 TCP 连接队列情况,证实存在全连接队列溢出的现象。



即:全连接队列容量不足导致大量单边连接产生。因在本验证场景下,订阅提供方的消费方数量过多,当提供方重启后,注册中心向消费方推送提供方上线通知,所有消费方几乎同时与提供方重建连接,导致全连接队列溢出。
  • 分析单边连接影响范围


单边连接影响范围多为消费方首笔交易,偶发为首笔开始连续失败 2-3 笔。

建立为单边的连接下,交易非必然失败。三次握手全连接队列满后,若半连接队列空闲,提供方创建定时器向消费方重传 syn+ack,重传默认 5 次,重传间隔以倍数增长,1s..2s..4s.. 共 31s。在重传次数内,若全连接队列恢复空闲,消费方应答 ack、连接建立成功。此时交易成功。



在重传次数内,若全连接队列仍然忙碌,新交易到达超时时间后失败。

到达重传次数后,连接被丢弃。此后消费方发送请求,提供方应答 RST。后交易到达超时时间失败。



根据 Dubbo 的服务调用模型,提供方发送RST后,消费方抛出异常 Connection reset by peer,后断开与提供方的连接。而消费方无法收到当前交易的响应报文、导致超时异常。同时,消费方定时器每2s检测与提供方连接,若连接异常,发起重连,连接恢复。此后交易正常。



3. C10K 场景问题分析总结

总结以上造成交易超时的原因有两个:
  • 心跳机制导致 netty worker 线程忙碌。在每个心跳任务中,提供方向所有 1 个心跳周期内未收发过报文的消费方发送心跳;消费方向所有 1 个心跳周期内未收发过报文的提供方发送心跳。提供方上所连接的消费方较多,导致心跳报文堆积;同时,处理心跳过程消耗较多 CPU,影响了业务报文的处理时效。
  • 全连接队列容量不足。在提供方重启后该队列溢出,导致大量单边连接产生。单边连接下首笔交易大概率超时失败。


4. 下一步思考


  1. 针对以上场景 1:如何能降低单个 netty worker 线程处理心跳的时间,加速 IO 线程的运行效率?初步设想了如下几种方案:
    • 降低单个心跳的处理耗时
    • 增加 netty worker 线程数,降低单个 IO 线程的负载
    • 打散心跳,避免密集处理

  2. 针对以上场景 2:如何规避首笔大量半连接导致的交易失败?设想了如下方案:
    • 增加 TCP 全连接队列的长度,涉及操作系统、容器、Netty
    • 提高服务端 accept 连接的速度


交易报文处理效率提升

1. 逐层优化

基于以上设想,我们从系统层面、Dubbo 框架层面进行了大量的优化,以提升 C10K 场景下交易处理效率,提升服务调用的性能容量。

优化内容包括以下方面:



具体涉及优化的框架层如下:



经对各优化内容逐项验证,各措施均有不同程度的提升,效果分别如下:



2. 综合优化验证效果

综合运用以上优化效果最佳。在此 1 个提供方连接 7000 个消费方的验证场景下,重启提供方后、长时间运行无交易超时场景。对比优化前后,提供方 CPU 峰值下降 30%,消费方与提供方之间处理时差控制在 1ms 以内,P99 交易耗时从 191ms 下降至 125ms。在提升交易成功率的同时,有效减少了消费方等待时间、降低了服务运行资源占用、提升了系统稳定性。

3. 线上实际运行效果

基于以上验证结果,中国工商银行在分布式服务平台中集成了以上优化内容。截至发文日期,线上已存在应用一个提供方上连接上万个消费方的场景。落地该优化版本后,在提供方版本升级、及长时间运行下均无异常交易超时情况,实际运行效果符合预期。

未来展望

中国工商银行深度参与 Dubbo 社区建设,在 Dubbo 金融级规模化运用的过程中遇到了诸多技术挑战,为满足金融级高敏交易的苛刻运行要求,开展了大规模自主研发,并通过对 Dubbo 框架的扩展和定制持续提升服务体系的稳定性,以“源于开源、回馈开源”的理念将通用增强能力不断贡献至开源社区。

未来,我们将持续致力于 Dubbo 的金融级规模化应用,协同社区继续提升 Dubbo 的性能容量和高可用水平,加速金融行业数字化创新和转型及基础核心关键的全面自主可控。

作者简介

颜高飞,微服务领域架构师,主要从事服务发现、高性能网络通信等研发工作,擅长 ZooKeeper、Dubbo、RPC 协议等技术方向。

相关 [工商银行 分布 服务] 推荐:

工商银行分布式服务 C10K 场景解决方案

- - DockOne.io
来源 | 阿里巴巴云原生公众号. Dubbo 是一款轻量级的开源 Java 服务框架,是众多企业在建设分布式服务架构时的首选. 中国工商银行自 2014 年开始探索分布式架构转型工作,基于开源 Dubbo 自主研发了分布式服务平台. Dubbo 框架在提供方消费方数量较小的服务规模下,运行稳定、性能良好.

工商银行神秘技术故障引发恐慌

- - Solidot
中国最大国有银行工商银行的柜面取款、ATM、网银等服务周日中断近一个小时,引发了客户恐慌和诸多猜测,其中包括黑客攻击,以及银行为紧缩银根而有意为之. 国家电视台CCTV声称工行技术故障导致服务中断45分钟. 工商银行则通过官方微博表示,计算机系统从上午10:38开始升级,造成部分业务受到影响,到11:23所有服务已经全部恢复.

工商银行MySQL数据库架构解密

- -
点击▲关注 “IT168企业级”给公众号置顶. 作者:林承军   编辑:爱可生. 摘要:本文根据DTCC数据库大会分享内容整理而成,将介绍工行 IT 架构转型中传统 OLTP 数据库架构面临的挑战和诉求,构建基于 MySQL 分布式企业级解决方案实践历程,包括技术选择、高可用设计、两地三中心容灾、运维管理、资源使用效率等方面的思考和实践经验,同时也介绍了工行转型的成效以及对后续工作的一些思考.

中国工商银行DevOps工具链建设之路

- - DockOne.io
【编者的话】新技术发展迅猛,金融产品和服务模式创新加快,快速增长的产品需求与有限研发资源之间的矛盾长期存在. 如何提高研发效能,快速上线业务需求,支撑业务创新发展,是金融机构产品研发部门面临的挑战. 传统银行的产品、架构体系庞大复杂,对研发效能提升带来更大挑战,无论流程改进还是工具支撑,都需兼顾现有系统的安全稳定运行.

Service Mesh 在中国工商银行的探索与实践

- - DockOne.io
微服务架构是当今互联网和金融机构渐趋主流的系统架构模式,其核心是集成服务通信、服务治理功能的服务框架,微服务框架在持续演进同时,服务网格(Service Mesh)作为一种新型的微服务架构,因架构灵活、普适性强,被认为具有较好发展前景. 中国工商银行(后简称工行)主动探索服务网格领域,从 2019 年开始服务网格技术预研工作,通过对服务网格技术深入研究和实践后,于 2021 年建设了服务网格平台.

解读Google分布式锁服务

- XiaoHui - NoSQLfan
在2010年4月,Google的网页索引更新实现了实时更新,在今年的OSDI大会上,Google首次公布了有关这一技术的论文. 在此之前,Google的索引更新,采用的的批处理的方式(map/reduce),也就是当增量数据达到一定规模之后,把增量数据和全量索引库Join,得到最新的索引数据. 采用新的索引更新系统之后,数据的生命周期缩短了50%,所谓的数据生命周期是指,数据从网页上爬下来,到展现在搜索结果中这段时间间隔,但是正如Google所强调的,这一系统仅仅是为增量更新所建立的,并没有取代map/reduce的批量作业处理模式.

分布式服务框架:Zookeeper

- - 标点符
Zookeeper是一个高性能,分布式的,开源分布式应用协调服务. 它提供了简单原始的功能,分布式应用可以基于它实现更高级的服务,比如同步,配置管理,集群管理,名空间. 它被设计为易于编程,使用文件系统目录树作为数据模型. 服务端跑在java上,提供java和C的客户端API. Zookeeper是Google的Chubby一个开源的实现,是高有效和可靠的协同工作系统,Zookeeper能够用来leader选举,配置信息维护等,在一个分布式的环境中,需要一个Master实例或存储一些配置信息,确保文件写入的一致性等.

分布式配置服务etcd VS 分布式协调服务zookeeper

- - 操作系统 - ITeye博客
etcd是一个高可用的键值存储系统,主要用于共享配置和服务发现. etcd是由CoreOS开发并维护的,灵感来自于 ZooKeeper 和 Doozer,它使用Go语言编写,并通过Raft一致性算法处理日志复制以保证强一致性. Raft是一个来自Stanford的新的一致性算法,适用于分布式系统的日志复制,Raft通过选举的方式来实现一致性,在Raft中,任何一个节点都可能成为Leader.

中国工商银行银行卡被盗用后,处理过程实录

- Nickcheng - 博客园-Duiker's Blog
最近发现自己工商银行的银行卡消磁了,所以去工商银行的换张卡,结果发生了一连串杯具. 换完卡,查询了一下余额,发现少了几千块,打印详单吧,确认是被盗用了,联系工行,打110报警,结果步步都是个坎,看来老百姓别没事麻烦这些大爷. 续1:在工行详单中通常会打印出所在的地区号和网点号,但是对于普通老百姓来说,给出的这些数字,你想了解到底是在那个地方被盗刷了,您就得打95588这个电话了,发生问题的两笔业务的地区号分别是4600和4000,查询后确认分别是北京和深圳.

工商银行打造在线诊断平台的探索与实践

- - DockOne.io
作者 | 刘慕雨 中国工商银行软件开发中心云计算实验室. 在信息系统建设方面,工商银行一直积极探索,以开放的姿态借鉴行业先进经验,旨在为客户提供更优质的金融服务和用户体验. 随着分布式架构和云计算平台在工行的广泛应用,如何高效排查程序错误或性能瓶颈,是个棘手的问题. 为此,我们基于 Arthas 建设了在线诊断平台,在保护客户信息安全的原则基础上,对相关能力做了剪裁和整合,通过 Web 方式支持更复杂的交互场景,在实际线上问题分析中发挥关键作用.