设计可靠通信之使用消息队列进行异步交互
依赖链中的服务越多,这条链路所能保证的整体可用性就越低。使用类似消息队列这样的通信代理来设计异步的服务交互是提高可靠性的另一大技术。
当开发者不需要立刻得到响应,也不需要响应始终保持一致时,可以使用异步通信技术来降低直接的服务调用的数量,相应地,这也能够提高系统整体的可用性——尽管这是以业务逻辑变得更加复杂为代价的。
使用消息队列来解除服务直接调用的耦合。
但是通信代理会变成故障单点,为了确保扩容、监控和运维的有效性,开发者需要特别小心这部分内容。
消息队列
1. 消息队列使用场景
消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,削峰填谷等问题。实现高性能、高可用、可伸缩和最终一致性架构。
解耦:多个服务监听、处理同一条消息,避免多次 rpc 调用。
异步消息:消息发布者不用等待消息处理的的结果。
削峰填谷:较大流量、写入场景,为下游 I/O 服务抗流量。当然大流量下就需要使用其他方案了。
消息驱动框架:在事件总线中,服务通过监听事件消息驱动服务完成相应动作。
2. 消息队列模式
点对点模式,不可重复消费
多个生产者可以向同一个消息队列发送消息,一个消息在被一个消息者消费成功后,这条消息会被移除,其他消费者无法处理该消息。如果消费者处理一个消息失败了,那么这条消息会重新被消费。
发布/订阅模式
发布订阅模式需要进行注册、订阅,根据注册消费对应的消息。多个生产者可以将消息写到同一个 Topic 中,多种消息可以被同一个消费者消费。一个生产者生产的消息,同样也可以被多个消费者消费,只要他们进行过消息订阅。
3. 选型参考
消息顺序:发送到队列的消息,消费时是否可以保证消费的顺序;
伸缩:当消息队列性能有问题,比如消费太慢,是否可以快速支持扩容;当消费队列过多,浪费系统资源,是否可以支持缩容。
消息留存:消息消费成功后,是否还会继续保留在消息队列;
容错性:当一条消息消费失败后,是否有一些机制,保证这条消息一定能成功,比如异步第三方退款消息,需要保证这条消息消费掉,才能确定给用户退款成功,所以必须保证这条消息消费成功的准确性;
消息可靠性:是否会存在丢消息的情况,比如有 A/B 两个消息,最后只有 B 消息能消费,A 消息丢失;
消息时序:主要包括“消息存活时间”和“延迟消息”;
吞吐量:支持的最高并发数;
消息路由:根据路由规则,只订阅匹配路由规则的消息,比如有 A/B 两者规则的消息,消费者可以只订阅 A 消息,B 消息不会消费。
kafka、RabbitMQ、Pulsar、RocketMQ 各自优缺点见原文消息队列基本原理和选型对比。
部分摘取自 摩根·布鲁斯和保罗·A.佩雷拉的《微服务实战》