有幸和美团大佬共同探讨单节点连接数超 1.5W 的问题
在和美团一个大佬从 Netty 连接复用开始了,最后聊到了微服务架构中单个节点连接数过高的问题,我觉得这个很值得大家探讨,一起来交流探讨一番。
1、抛出问题
例如一个电商的微服务架构如下图所示:
简单罗列一下这个系统的构成:
网关域整个微服务的入口网关,集群部署。
优惠券域主要是用于提供电商系统中有幸与美团大佬共同探讨单节点连接数超 1.5W 的问题的优惠券服务。
积分服务商场的会员积分服务。
支付服务提供订单支付相关服务
订单域订单域,主要提供下单服务,在订单域中需要调用优惠券、积分、支付等服务,包括图中未画出的库存等服务。
上面的架构图非常简单清晰,但如果每一个域中的部署的实例超过 5000 台,又意味着什么呢?
每一个实例部署 5000 个可能让大家觉得匪夷所思,认为在现实中基本不会存在,但如果上升到当下一线互联网公司,恐怕都还不止,并且在一线互联网企业通常是多机房双活部署,这里的问题强调在一个机房中就有这么大的规模。
如果上述微服务架构采用阿里开源的 Dubbo 框架,下单服务进行负载均衡,订单域中的一台机器持有的连接数轻松破 1.5 万,实际的电商业务非常复杂,需要调用的服务远不止上图中勾勒的这么少,对机器的内存、网络调度带来极大压力,严重时将影响系统的稳定性,很容易出现超时等异常。
2、问题分析与解决方案
本文将限定与微服务框架使用 Dubbo,但本文思想的阐述并不局限于 Dubbo。
上述造成单个节点轻松破 2w 连接的原因是负载均衡机制造成的。
优惠券服务部署 5000 个节点,下单服务作为其消费者,会从注册中心获取到整个服务列表,然后需要调用优惠券服务时会在客户端进行负载均衡,从服务列表中包含的 5000 个服务提供者中按照负载算法选择一个服务者提供者加以调用,即下单服务需要创建 5000 个连接。
值得注意的是下单服务并不只是调用优惠券服务,还需要调用其他服务,从而导致一个下单服务会随着其调用的服务数的增多,创建的连接数将非常多。
如何破局呢?
首先我们要理解负载均衡的底层目的:
避免单点故障由于服务提供者集群部署,客户端在发起调用时可以按照某种算法从集群中选择一个,一个宕机并不会影响客户端的使用,从而提供高可用性保证。
实现高并发单个节点受限内存、连接数等限制,其服务能力并不足以扛住海量请求,故需要依靠多个节点共同提供服务,从而构成一个服务集群,大厂中单个服务部署 5000+节点是非常常见的。
总的来说,负载均衡相对客户端来说,其基本要求:充分将流量平均分配给服务节点,充分利用集群的处理能力。
但必须持有服务提供者的所有连接才能实现负载均衡?我看未必,请看如下示意图:
其核心思想是对客户端、服务端进行分组。
从单个客户端维度来看,并不需要持有所有服务提供者的列表,从而也就无需创建到所有服务提供者的 tcp 连接,只需持有部分连接,另外一部分分配给其他客户端。
但从所有客户端维度来看,可以调用所有的服务提供者,实现对所有服务提供者进行负载均衡。
经过上面的分组,单个服务节点(无论是客户端、服务端)端连接数量都能成倍的下降,效果将十分显著。
那在 Dubbo 中是否可以利用现成的机制来实现呢?
答案是:当然可以,尽管该功能设计的目的并不是本文的目的,但还是有异曲同工之妙。
其具体做法如下所示:
可以对客户端、服务端打标签,这样的话,订单服务-1 被打上标签 c1,尽管订单服务-1 能从注册中心获取全部打支付服务列表(4 台),但由于在负载均衡之前首先会执行路由选择,根据标签路由机制:订单服务-1 由于其标签为 c1,故只能访问 tag 为 c1 的服务提供者,这样就只会创建到 tag 为 c1 的支付服务的连接,从而实现降低连接数之目的。
完美解决。在文章的末尾,我们稍微再关注一下 Dubbo 路由机制可以参考官方提供的原理图:
关于 Dubbo 路由机制,可以参考笔者的另一篇博文:Dubbo服务治理之灰度发布方案
文章首发于https://www.codingw.net/posts/4c69eedc.html
作者简介:丁威,《RocketMQ 技术内幕》一书作者、RocketMQ 开源社区优秀布道师,公众号「中间件兴趣圈」维护者,主打成体系剖析 Java 主流中间件,已发布 Kafka、RocketMQ、Dubbo、Sentinel、Canal、ElasticJob 等中间件 15 个专栏。
版权声明: 本文为 InfoQ 作者【中间件兴趣圈】的原创文章。
原文链接:【http://xie.infoq.cn/article/149eeef3c69aedc63cda86190】。文章转载请联系作者。
评论