前面也介绍过消息队列如何进行选型,今天讲一下消息队列的主要应用场景。首先大家思考一个问题,我们为什么要使用消息队列,消息队列给我们带来了哪些好处呢?
我们最常想到就是使用消息队列解决应用耦合,异步消息,流量削峰等问题。下面我们根据这些应用场景简单分析一下。
解耦
相对于解耦来说,我们先谈谈耦合的情况。在传统的应用当中,我们一般来说一整个业务系统都会是一个应用,所有的业务都会在一个服务里面。
我们举例说明一下,我们现在有一个支付系统的业务需要调用短信发送的需求,那么我们需要再支付系统里面接入发送短信的功能,那现在我们另外一个电商系统里面的下单业务,也需要发送短信,那这个时候我们就又需要再电商业务系统里面再实现一次,这样是不是就是非常的麻烦,同样的事情做两次,非常的耦合。
那我们如果将这个发送消息的功能,单独做成一个服务,然后支付系统和电商业务系统只需要发送一个发送短信的消息,就可以解决重复实现代码的功能的,而且这个发送短信的功能可以接入任何发送短信的业务需求。这个就是消息应用在系统解耦上。
其实解耦还有一个方式就是使用RPC服务调用,也可以实现解耦,只是一个异步一个是同步,我们可以思考一下使用消息队列比使用RPC服务调用有什么好处呢?
异步消息&&流量削峰
异步化是一个非常重要的机制,在处理高并发、高可用等系统设计时,如果不需要或者限制于系统承载能力,不能立即处理消息,此时就可以应用消息队列,将请求异步化。还是举例说明一下,用户注册后,需要发注册邮件和注册短信。传统的做法有两种:串行的方式和并行方式。
异步处理的一个典型场景是流量削峰,我们用电商的秒杀场景来举例。秒杀抢购的流量峰值是很高的,很多时候服务并不能承载这么高的瞬间流量,于是可以引入消息队列,结合限流工具,对超过系统阈值的请求,在消息队列中暂存,等待流量高峰过去以后再进行处理。
延时任务
延时任务执行其实是RocketMq的一个非常好用的特性。还是举例说明一下,比如你现在在抖音看中一个东西后下单成功了,但是没有立即支付,进入订单详情会显示倒计时,如果超过支付时间,订单就会被自动取消。我们想想如果不使用消息的解决方案。
不使用队列方案:
订单生成以后,将这个生成订单的信息缓存到Redis,并设置过期时间与订单过期时间一致,当接口查不到这个订单以后,则过期
使用消息队列的延时消息:
订单服务生成订单后,发送一条延时消息到消息队列。消息队列在消息到达支付过期时间时,将消息投递给消费者,消费者收到消息之后,判断订单状态是否为已支付,假如未支付,则执行取消订单的逻辑。
很明显,使用延时消息这种方案很优雅,第一种方案,如果下单量非常大的时候,会造成Redis压力巨大,而延时队列对处理这种消息积压问题明显性能强很多。
缓存同步
高并发场景下,很多应用使用本地缓存,提升系统性能 。本地缓存可以是 HashMap 、ConcurrentHashMap。为了提升接口性能,每个应用节点都会将字典表加载到本地缓存里。当字典表数据变更时,可以通过业务系统发送一条消息到 RocketMQ 进行广播,每个应用节点都会消费消息,刷新本地缓存。
日志处理
将日志消息发送到消息队列中,然后由日志处理器异步处理。这样可以将日志记录与应用程序的执行解耦,避免因为日志记录导致的性能影响。最常用的就是使用kafka来收集日志,我们拿最常用的日志系统架构ELK来举例说明,使用FileBeat做日志数据采集,采集完了以后将日志发往kafka,kafka可以帮助日志收集削峰,然后发往Logstash 进行日志过滤,最后再将日志存储到ES里面,最后使用kibana进行日志展示。
分布式事务
在分布式系统中,消息队列可以用于实现分布式事务。通过将事务消息发送到消息队列中,各个参与者可以异步处理事务,从而提高系统的并发性和吞吐量。
分布式事务是指涉及多个独立的系统或服务的事务操作。在传统的单一数据库系统中,事务通常是原子性、一致性、隔离性和持久性(ACID)的。但是,在分布式系统中,由于数据分布在多个节点上,实现这些 ACID 特性变得更加困难。
分布式事务通常涉及多个参与者和协调者,其中参与者可能位于不同的物理位置,而协调者负责协调所有参与者的操作,以确保事务的一致性和可靠性。一些常见的分布式事务模型包括:两阶段提交(2PC)、三阶段提交(3PC)、AT模式、TCC 模式、saga模式、XA模式。这个比较复杂,后面对单独这块结合阿里的Seta进行详细解读。