简介:Dubbo 作为分布式微服务框架,众多公司在实践中基于 Dubbo 进行分布式系统架构。重启开源后,我们不仅看到 Dubbo 3.0 最新的 Roadmap 发布,而且还看到阿里在自身电商开始推进 Dubbo 和内部 HSF 的融合,并在 双11 上开始使用 Dubbo 3.0。本文是工商银行基于 Dubbo 构建金融微服务架构的分享,主要讲述了服务发现的应对策略和成果,后续将发布工行大规模服务监控治理的实践,以及从企业角度怎么去对 Dubbo 二次开发等内容。欢迎关注。
作者 | 张远征
来源|阿里巴巴云原生公众号
导读:Dubbo 作为分布式微服务框架,众多公司在实践中基于 Dubbo 进行分布式系统架构。重启开源后,我们不仅看到 Dubbo 3.0 最新的 Roadmap 发布,而且还看到阿里在自身电商开始推进 Dubbo 和内部 HSF 的融合,并在 双11 上开始使用 Dubbo 3.0。本文是工商银行基于 Dubbo 构建金融微服务架构的分享,主要讲述了服务发现的应对策略和成果,后续将发布工行大规模服务监控治理的实践,以及从企业角度怎么去对 Dubbo 二次开发等内容。欢迎关注。
工行传统的业务系统一般都是基于 JEE 的单体架构,面对金融业务线上化及多样化的发展趋势,传统架构已经无法满足业务的需求。因此从 2014 年开始,工行选择了一个业务系统做服务化的尝试,并验证、评估、对比了当时的几个分布式服务框架,最终选择了相对完善、并且国内已经有较多公司落地使用的 Dubbo。与此同时,工行还对 Dubbo 做了企业定制,帮助这个业务系统完成了服务化的落地,上线之后也收到了非常好的效果。
2015 年,工行开始扩大服务架构的落地范围,一方面帮助传统业务系统进行架构转型,另一方面也逐渐沉淀了类似中台的超大规模服务群组,支撑业务系统快速服务的组合和复用。随着经验积累,工行也不断对 Dubbo 进行迭代优化和企业定制,同时围绕服务也逐步打造了完善的服务生态体系。
2019 年,工行的微服务体系也正式升级为工行开放平台核心银行系统的关键能力之一,助力工行 IT 架构实现真正的分布式转型。
工行的微服务体系组成如下图所示:
经过工行多年的落地实践,本文共总结了以下两方面的最大挑战:
本文将先从服务发现方面,来分享一下工行的应对策略及成效。
在 Dubbo 中,服务的注册订阅及调用是一个标准范式,服务的提供者初始化时注册服务,服务消费者初始化时订阅服务并获取全量提供者列表。而运行期间,服务提供者发生变化时,服务消费者可获取最新的提供者列表。消费者与提供者之间点对点 RPC 调用,调用过程不经注册中心。
在注册中心的选择上,工行在 2014 年就选择了 Zookeeper。Zookeeper 在业界的各类场景下有大规模的应用,并且支持集群化部署,节点间数据一致性通过 CP 模式保证。
在 Zookeeper 内部,Dubbo 会按服务建立不同的节点,每个服务节点下又有 providers、consumers、configurations 及 routers 四个字节点:
在线上生产环境,Zookeeper 分数据中心部署了多个集群,每个集群配置了 5 个选举节点,若干个 Observer 节点。Observer 节点是 Zookeeper3.3.3 版本引入的一个新的节点类型,它不参与选举,只听取表决结果,其他能力则和 Follower 节点相同。Observer 节点有以下几方面的好处:
工行根据这几年线上 Zookeeper 的使用心酸血泪史,总结了 Zookeeper 在作为服务注册中心时面临的问题:
综上,可以得出的结论是:总体上 Zookeeper 作为注册中心还是比较称职的,但在更大规模服务量场景下,需要进一步优化。
工行最主要的优化措施包括下面这几方面:订阅延迟更新、注册中心采取 multiple 模式、升级到按节点注册等。
工行对 Zookeeper 客户端组件 zkclient 做了优化,把消费者收到事件通知后获取提供者列表做了一个小的延时。
当 zkclient 收到 childchange 一次性的事件后,installWatch() 通过 EventThread 去恢复对节点的监听,同时又使用 getChildren() 去读取节点下的全部子节点获取提供者列表,并刷新本地服务提供者缓存。这就是前面说的“5050 条数据”问题的根源。
工行在 zkclient 收到 childchange() 的事件后,做了个等待延迟,再让 installWatch() 去做它原来该做的事情。这个等待过程中如果服务提供者发生变化,则不产生 childchange 事件。
有人会问,这是不是违背了 zookeeper 的 CP 模型呢,其实并不是,zookeeper 服务端的数据是强一致的,消费者也收到了事件通知,只是延后去读取提供者清单,后面执行 getChildren() 时,读取到的已经是 zookeeper 上的最新数据,所以是没有问题的。
内部压测结果显示,服务提供者大规模上线时,优化前,每个消费者收到了总计 422 万个提供者节点的数据量,而延迟 1 秒处理后,这个数据量则变成了 26 万,childchange 事件次数和网络流量都变成了原来的 5% 左右,做完这个优化,就能从容应对投产高峰期大量服务的上下线。
工行采纳并优化改造了 Dubbo 新版本中 registry-multiple 的 SPI 实现,用于优化多注册中心场景下的服务订阅。
Dubbo 中服务消费者原有处理逻辑是这样:当存在多个注册中心的时候,消费者按注册中心对应的 invoker 缓存去筛选提供方,第一个注册中心对应的缓存中如果没找到,则去找第二个注册中心对应的缓存。如果此时第一个注册中心出现可用性问题,推送给消费者的数据有缺失,甚至为空,就会影响消费者的这个筛选过程,如出现无提供方的异常、调用负载不均衡等。
而 multiple 注册中心是把多个注册中心推送的数据合并后再更新缓存,所以即使单个注册中心故障,推送了数据不完整或者为空,只要有其他任意一个注册中心的数据使完整的,就不会影响最后合并的数据。
并且,multiple 注册中心机制也用于异构的注册中心场景,出现问题可以随时把注册中心下线,这个过程对服务节点的服务调用则完全透明,比较适合灰度试点或者应急切换。
更进一步,还有额外的收益,消费者端 Reference 对象是比较占用 JVM 内存,通过 multiple 注册中心模式,可以帮消费者端节省一半的 invoker 对象开销,因此,非常推荐多个注册中心场景采用 multiple 模式。
工行反向移植 Dubbo2.7 及 Dubbo3.0 的服务发现逻辑,使用“按节点注册”的服务注册-发现模型。这里即配置中心、元数据中心、注册中心这个铁三角组合:
这个模型的变化,对于消费者的服务调用则没有任何影响。消费者端根据元数据中心上“服务节点名称”与“服务”的关系,以及注册中心“服务节点名称”与实际 ip 端口的关系,生成兼容存量模式的服务提供方 invoker 缓存。
压测结果显示,按节点注册可以让注册中心上的数据量变成原来的 1.68%,这对量就对线上的 Zookeeper 来说毫无压力,10 万级别的服务量和 10 万级别的节点量都能够轻松支撑。
未来,工行也希望能有机会走出去,深度参与到社区中,把自身在 Dubbo、Zookeeper 服务端、zkclient 上的好的 feature 贡献出来,比如除了上面的优化点外,工行还在 Dubbo 上做了 RPC 结果的精细化识别,PAAS 的适配,同端口多协议、自隔离等能力,还在 Zookeeper 上增加了注册熔断机制,同时正在研究 Observer 的同步机制避免数据全量同步带来的一系列问题。
另外,从微服务的发展看,Mesh 已经是目前的热点之一。工行的痛点主要在服务 SDK 版本升级上,Istio 不争气,MCP 生死未卜,如何能让存量 Dubbo 服务平滑过渡到 MESH 架构,目前已经有初步的方案,但还有非常多的技术难关需要克服。
欢迎 Dubbo 有实践的同学们一起来探讨大规模场景下的问题和心得,共同把 Dubbo 的企业落地做的更好!
更多企业落地实践内容,可下载云原生架构白皮书了解详情!
原文链接:https://developer.aliyun.com/article/779740?
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。