JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

SpringBoot + RabbitMQ 实现高可用可伸缩的简易版分布式系统

wys521 2024-10-27 15:37:10 精选教程 29 ℃ 0 评论

这个话题源自于我司一个项目的技术架构升级,由原来的模块编程调整为微服务编程,鹏哥所在的研发部负责提供升级的解技术支持。之前系统由4个模块组成,约定4个模块是通过Activity MQ解耦,但是模块之间难免会有一些需要等待对方返回才能下一步的调用,之前的解决方案是使用Activity MQ 的同步调用,现在系统升级改为使用RabbitMQ代替原来的ActivityMQ,异步的替换没有啥问题,但是同步的时候负责的开发就有点懵了,因为我的同事并没有提供rabbit mq 同步调用的方案,项目升级因此中断而造成了延误。

中午正好跟项目的负责人一起吃饭,他一直在跟我吐槽我们研发部对他们项目升级支持不够,没有提供MQ同步方法的支持,鹏哥听了火冒三丈,脑子一热直接怼了过去:MQ 产生的意义是什么,MQ的出现就是为了解耦,你们把他用在同步调用上,还怎么实现解耦,同步调用直接rest api 调用不就行了,使用MQ多此一举。对面项目经理瞬间无话,至此切换下一个话题。

吃完饭回来,冷静下来之后,想想MQ支持同步其实也不是没有好处,比如:

  • 多实例间负载均衡
  • 服务发现治理
  • 快速服务横向扩容

幸亏当时对方经理对rabbitMQ不是很熟,不然丢人估计就丢大了,哈哈。

好了废话不多说,我们言归正卷。rabbit 实现同步调用其实依赖与其私有队列和发送确认,既利用声明一个不指定名称的队列,靠rabbit 来生成一个唯一的队列名,同时将这个队列名赋值给消息头里面的reply_to字段,以告诉生产者,这是一个返回信息。

原理很简单,我们来看一个具体的案例。我们先假设服务A需要调用服务B来完成A的业务逻辑,加入服务B有两个节点。

多实例间负载均衡

我们先来想一下,模块编程时代,我们是如何实现负载均衡的:我们会在服务B外层架一个负载均衡服务器,如nginx 等,然后再A调用B的时候,其实是通过nginx 代理的方式,路由到其中一个B服务的节点上,如下图:


?

这种行业的标准解决方案已经被业界无数次的验证可行性,这里就不多赘述了。现在我们来看一下MQ是怎么实现负载均衡的。这其实MQ天然的特性,并不是因为使用了同步调用才有的。在多个消费者监听同一个队列的时候,rabbit mq 使用简单的轮训以实现消费者的均衡,这种方式巧妙的将负载粗暴的平均到每一个消费实例上。rabbit mq在同步调用案例中,负载均衡的示意图如下:


?

服务发现治理

在微服务模式下,我们来想一下eureka的作用。服务A需要调用服务B的一个接口,但是它并不知道这个服务B在那台服务上,也不知道服务B有多少台可以工作的实例,这个时候eureka就出场了。首先服务A和服务B都注册到eureka服务器上,并把eureka的服务列表copy一份到服务器的本地,这样当A需要调用服务B的接口的时候,就可以根据服务路由表快速的找到可以提供服务的实例。
那模块编程时代,这个功能靠什么实现呢?rabbit mq 有一次拯救了我们。服务A在调用B的接口的时候,并不需要知道提供服务的是谁,只需要往对应的queue上发送消息即可,rabbit mq 负责将消息推送给监听这个queue的消费者。

快速服务横向扩容

扩容这个问题,如果是使用Nginx 作为代理服务器的话,每次扩容都需要修改Nginx的配置,将新的服务器信息添加到Nginx配置信息中去。这种方式给每一次的扩容带来工作量和风险。rabbit mq 在对待这个问题上也是天然的支持,当我们发现服务B 当前实例不能满足现在的请求压力的时候,我们只需要将B新部署实例连上对应的队列即可,无需修改任何配置。当我们不需要的这么多实例的时候,也可以直接停掉即可,也不用修改任何配置。

一个基于Spring boot的例子

说了这么理论,现在我们来实现我们吹过的牛。使用Spring boot + rabbit 来实现一个分布式系统的雏形。

新建一个client的项目,配置DirectExchange 和一个Queue,并绑定在一起。

?最基本的定义方法。

?

为了方便测试,我们提供一个rest api 负责发送和接受同步返回的消息。发送MQ的时候我用使用convertSendAndReceive 代替convertAndSend 来实现同步的调用,并接收返回值。

?

好了。client 端就完成了,现在我们来编写服务端。


?

编写一个receiver,负责监听client端定义的queue。并将Process 方法添加返回值。


?

你也许会好奇,为什么我没有配置rabbit的任何信息,这是因为,你要你在POM中引入了 rabbit的jar,并且没有修改默认的rabbit的用户名和密码,Spring boot 会默认帮你链接到rabbit上的。


?

?

使用docker 启动一个 MQ的实例,如果不会Docker 启动MQ 鹏哥会提供另外一篇博客来简单介绍一下。


?

分别启动 client 和Server


?

使用Postman 请求一下client 的API来模拟一个请求,同时client 会去向 Server 发送一个同步请求。

?

client端日志:

?

server 端日志:


?

至此我们使用 rabbit mq 模拟了一个同步的调用,下边我们来模拟我们的高可用和可伸缩。

修改服务端的启动配置,以便我们可以启动多个实例。


在启动完一个实例之后,修改端口号,再次启动,你会发现已经起了两个实例。?

我们来启动三个服务端实例,来模拟负载均衡。


?

使用postman 请求6次刚才的接口,我们在client 端 的日志里面看到了6个请求的返回值。


?

同时均匀的在服务端的3个实例上,分别承载了两次调用。




?

?

?

至此我们演示完了这个简易分布式系统的所有的功能。

项目代码地址:https://github.com/linghuxiong/spring-boot-demo/tree/master/spring-boot-rabbit-rpc

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表