系统架构的演进:同步通讯到异步通讯的过渡
- 一 . 同步通讯 VS 异步通讯
- 1.1 同步调用方案
- ① 耦合度高
- ② 性能下降
- ③ 资源浪费
- ④ 级联失败
- 1.2 异步调用方案
- ① 同步解耦
- ② 性能提升 , 吞吐量增加
- ③ 服务没有强依赖 , 不必考虑级联失败问题
- ④ 流量削峰
- 1.3 小结
- 二 . 三大 MQ 的对比
在现代软件开发中,通讯方式的选择对于系统的性能和可扩展性至关重要。我们将对比同步通讯与异步通讯的不同之处,以及它们在实际应用中的优缺点。通过一个电商系统的例子,我们将揭示同步调用可能导致的耦合度高、性能下降、资源浪费和级联失败等问题。同时,我们将探索异步调用如何通过事件驱动和消息队列(Broker)来解决这些问题,实现服务解耦、性能提升和流量削峰。
此外,我们还对市面上流行的四种消息队列技术—— RabbitMQ、ActiveMQ、RocketMQ 和 Kafka 进行全面的比较。我们将从它们的开发语言、支持的协议、可用性、吞吐量、消息延迟和可靠性等多个维度进行分析,了解每种技术的特长和适用场景。
一 . 同步通讯 VS 异步通讯
同步通讯就类似于打视频电话 , 一旦建立连接 , 二者就建立了同步联系 . 虽然同步通讯的时效性较高 , 但是同一时间点只能有一个人跟我进行对话 .
而异步通讯就类似于发微信消息 , 同一时间点我可以跟许多人聊天 , 但是它的时效性并不是太好 , 接收方不一定就能立刻看到消息 , 可能需要等待一段时间才能看到消息 .
1.1 同步调用方案
我们可以通过一个电商系统来反射出同步通讯和异步通讯的问题
① 耦合度高
那产品经理想要增加一个短信功能
那由于订单服务、仓储系统、短信系统都需要支付服务来进行调用 , 这就需要修改支付服务的代码 , 就导致整个系统出现了耦合 .
② 性能下降
那这样的模型 , 还会导致性能下降 , 假设我们每个服务所耗费的时间我们都标注在下面了
那由于整个系统是同步调用的 , 只有等待订单服务执行完毕 , 支付服务才能继续调用通知仓储系统 .
因此 , 整个流程执行下来 , 需要 50ms + 150ms + 150ms + 150ms = 500 ms , 这也就意味着 1s 只能处理 2 个订单 , 非常耗时 .
③ 资源浪费
那调用链中的每个服务 , 都需要等待前一个服务结束才能执行下一个服务 , 在等待的过程中也会浪费许多资源 .
④ 级联失败
假设仓储系统承受了巨大的压力 , 最后扛不住了 . 那支付服务调用仓储系统 , 就会调用失败 , 就会阻塞到这里 .
那之后越来越多的请求调用支付服务 , 然后再去调用仓储服务 , 那这些请求都会被阻塞掉 , 最后都会执行失败 .
慢慢的就会导致支付服务也承受不住压力崩溃掉 , 导致整个系统出现了故障 , 最终就会导致用户的体验感大大降低 .
1.2 异步调用方案
异步调用最常见的就是事件驱动模式 .
当用户进行支付的时候 , 就会调用支付服务 . 支付成功之后 , 就需要订单服务、仓储系统、短信系统各自执行自己的业务 .
那事件驱动模式肯定不可能跟之前一样 , 由支付服务调用这三个服务 .
那他的做法是在中间添加一个 Broker (事件代理者)
那什么叫事件代理呢 ?
那对于我们这个业务来说 , 一旦有用户支付成功 , 就是一个事件 , 那这个事件就会交给 Broker 来去管理 .
那订单服务、仓储系统、短信系统就会跟 Broker 询问用户是否支付成功 , 这就叫做事件订阅 .
那在这个模型中 , 支付服务发布了支付成功事件之后 , 就结束了他的任务 , 就可以返回结果给用户了 .
那支付服务把通知订单服务、仓储系统、短信系统的工作交给了 Broker 来去实现 , 它就不再自己去通知这三个服务了 .
那这种方式相比于同步调用 , 存在哪些优势呢 ?
① 同步解耦
假如我们的产品经理又想要添加优惠券功能 , 那就不需要修改支付服务的代码了 , 因为支付服务只负责发布支付成功的事件 , 我们只需要让新功能来去从 Broker 中订阅事件即可 .
这样就解决了服务和服务之间的耦合了 .
那后续如果产品经理觉得短信通知太费钱了 , 我们也不需要删除代码 , 只需要让短信系统取消订阅事件即可
② 性能提升 , 吞吐量增加
在之前 , 我们是需要支付服务依次调用其他所有服务 . 而现在不一样了 , 支付服务只负责发布支付成功事件 , 那这样的话支付服务就可以立即返回给用户支付成功信息 , 而其他的订单服务、通知仓储系统等等本身就是与用户无关的业务 , 所以不需要将这些业务算进我们的运行时间中 .
那这样的话 , 总共才需要 50ms+10ms = 60ms , 性能大大提升 , 吞吐量也提高了
③ 服务没有强依赖 , 不必考虑级联失败问题
如果通知仓储系统挂了 , 也跟支付服务没有多大关系 , 支付服务只负责发布支付成功事件 , 这样的话就不必关心级联失败的问题了 .
④ 流量削峰
假设同一个时间点 , 只能处理一个请求 , 那此时过来了许多请求 , 就可以将请求放入到 Broker 中 , 然后订单服务、仓储系统 … 慢慢执行就可以了
1.3 小结
同步调用的优点 : 时效性较强 , 可以立即得到结果
同步调用存在的问题 :
- 耦合度高
- 性能下降
- 有额外的资源消耗
- 存在级联失败问题
异步通信的优点 :
- 耦合度低
- 吞吐量提升
- 故障隔离
- 流量削峰
异步通信的缺点 :
- 非常依赖 Broker 的可靠性、安全性、吞吐能力
- 架构变的更加复杂 , 不方便追踪管理
二 . 三大 MQ 的对比
MQ (MessageQueue) , 也叫做消息队列 , 字面意思指的就是存放消息的队列 , 也就是事件驱动架构中的 Broker
这里的消息指的就是我们上面说的事件
我们来看一下市面上比较常见的四种 MQ 的技术对比 :
RabbitMQ | ActiveMQ | RocketMQ | Kafka | |
---|---|---|---|---|
公司/社区 | Rabbit | Apache | 阿里 | Apache |
开发语言 | Erlang (并发能力强 , 性能极其好) | Java | Java | Scala & Java |
协议支持 | AMQP、XMPP、SMTP、STOMP | OpenWire、STOMP、REST、XMPP、AMQP | 自定义协议 | 自定义协议 |
可用性 | 高 | 一般 | 高 | 高 |
单机吞吐量 (性能承载能力) | 一般 | 差 | 高 | 非常高 |
消息延迟 | 微秒级 | 毫秒级 | 毫秒级 | 毫秒以内 |
消息可靠性 (消息会不会丢) | 高 | 一般 | 高 | 一般 |
追求可用性 (当需要处理数据时 , 资源处于可用状态的程度) : Kafka、RocketMQ、RabbitMQ
追求可靠性 : RabbitMQ、RocketMQ
追求吞吐能力 (十万级别的) : RocketMQ、Kafka
追求消息低延迟 : RabbitMQ、Kafka
那综上所述 , 每个方案都有优缺点 , 并没有十分完美的技术 . 我们按照自己业务的要求选择合适的消息队列即可 .
到此为止 , MQ 的简单介绍就介绍到这里了 , 如果对你有帮助的话 , 还请一键三连~
希望得到你的鼓励