之前的方案
《基于OpenResty与Consul实现服务网格ServiceMesh》 一文是2019年对服务网络架构的一个实践,里边有一些不完美的地方,比如每个服务节点上要装OpenResty + Consul client两个组件来做代理,OpenResty上要装微博开源的upsync插件来更新上游服务的upstream配置,且只能更新现有upstream的节点横向扩缩容,如果新增或者删除stream的话,需要使用远程的shell脚本执行来改OpenResty里的nginx.conf文件再执行reload操作。
2021年初笔者基于Ribbon + Spring Cloud Config,修改了Ribbon源码做自定义开发,做了一个客户端负载均衡组件:Ribbon向Config来获取服务列表,通过Pinger机制来对各个服务节点做健康检查,Config管理端修改了服务配置之后通过Spring Bus(kafka)来通知节点上的Config客户端库来重新获取配置。
做了这个项目之后,熟悉了负载均衡的玩法。后面笔者又做了OpenResty + Redis + RocketMQ的一个秒杀架构。又看了一些关于蚂蚁金服ServiceMesh架构的一些文章。又想起了自己曾经做了的这个ServiceMesh小Demo,决定重新优化一下架构。
新方案
下面说下新的优化思路:
- Consul分Server和Client端,Server端3节点高可用集群、客户端装在每个业务服务器节点上,共同组成了一个服务配置共享的网络。
- 去掉OpenResty,把代理程序缩到每个业务服务进程里边,以SpringBoot Starter作为一个Lib让每个业务应用引用,这个库作为Proxy。
- Consul client作为边车,Proxy负责为所在业务应用连接边车,从边车获取可用服务列表,然后直连调用服务端。
1、跟之前的边车不同,这次边车只负责给客户端提供服务列表,并没有负责转发客户端的请求。客户端与服务端是直连调用的。
2、客户端进程内的Proxy库,可以基于spring-cloud-starter-consul-discovery
来做封装和定制化二次开发。
优缺点:
- 与原来的OpenResty + Consul的方案相比,业务应用里边要引入1个封装的依赖,然后服务调用使用封装过的带负载均衡功能的HttpClient工具。但是好处是服务调用是直连调用了,不需要像原来一样用OpenResty做中间代理了。也就绕开了前文提到的这块不完美的几个地方。
- 与Ribbon + Config的方案相比,业务应用引入封装Jar包、服务调用工具用新客户端类这点是一样的。搭建Config变为搭建Consul,前者之前使用的是JDBC模式存储服务节点信息,用Consul后更为方便。另外不需要搭建Kafka来做Spring Bus通知服务节点变化,Consul网络会通过Gossip协议扩散到各个服务节点里的边车中、客户端去边车定时查就可以了,相比原来架构简单了不少。(节点配置变化通知及时应该确实是原来的更及时,变化后立即通过kafka通知客户端,客户端收到通知立刻调用rest接口到Config查询。通过Consul的Gossip扩散到客户端旁边的Consul Client边车本身就会有一定的延迟,然后客户端又是定时轮询边车的。但考虑到延迟个最多10几秒应该可以接受)