今日学习,
消息队列简述
什么是消息队列?
消息队列是典型的生产者和消费者模型,生产者不断向消息队列中生产消息,消费者不断从队列中获取消息。因为消息的生产和消费是异步的,而且只关心消息的发送和接收,没有业务逻辑的侵入,轻松的实现系统间的解耦。消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。
消息队列有什么作用?
应用解耦,异步处理,流量削峰
- 应用解耦: 分布式系统中服务与服务之间可能处于上下游关系,如果下游服务出现异常,此时依赖于此下游服务的所有上游服务都将出现不可用状态,此时两个上下游服务就存在很高的耦合,而我们设计软件系统的标准就是高内聚,低耦合。所以此时,避免两个系统耦合度过高就成了需要解决的问题,此时我们引入消息中间件来解决这个问题。 设定一个场景:双十一购物节的时候,用户下单后,订单系统需要通知库存系统。传统的做法就是,订单系统去调库存系统的服务接口,那么如果这时,库存系统出现异常,订单就会失败。引入mq之后,订单系统在用户下单后,订单系统完成持久化处理,将消息写入消息队列,直接向客户端返回用户订单下单成功的响应,库存系统订阅下单的消息,获取下单消息,进行库操作。那么就算库存系统出现故障,消息队列也能保证消息的可靠性传递,不会导致消息的丢失。
- 异步处理:设定一个用户注册的场景,用户注册后,需要发注册邮件和注册短信,传统的做法有两种.一个串行化处理,一个是并行处理。首先来看一下串行化处理:将注册信息写入数据库后,发送注册邮件再发送注册短信,以上三个任务必须全部完成后才能返回给客户端。这有一个问题是,邮件,短信并不是必须的,它只是一个通知,而这种做法让客户端等待没有必要等待的东西。并行方式:将注册信息写入数据库后,发送邮件的同时,发送短信,以上三个任务完成后,返回成功信息给客户端,并行的方式提高了处理的时间。 而引入消息队列之后,将短信和邮件等不是必须的业务处理逻辑异步处理。引入消息队列之后,用户端的响应时间就等于写入数据库的时间加上写入消息队列的时间,时间更快。
- 流量削峰: 秒杀活动中以及其他高并发系统中,一般会因为流量过大,导致应用直接挂掉,为了解决这个问题,一般需要在应用前端使用消息队列。 首先在这种场景下引入消息队列可以起到控制活动人数的作用,在消息队列中设置一个阈值,一旦人数超过这个这个阈值,就会将订单直接丢弃或者别的处理。第二可以缓解短时间内的高流量压垮应用,也就是应用程序按自己的最大处理能力获取订单。 用户的请求,服务器收到之后,首先写入消息队列,加入消息队列长度超过最大值,则直接抛弃用户请求或跳转到提示界面。随后秒杀业务根据消息队列的请求消息,再做后续的处理。
使用mq如何保证分布式事务的最终一致性
- 分布式事务:业务相关的多个操作,要么同时成功或者同时失败
- 最终一致性:与之对应的是强一致性,最终一致性指的是,多个业务操作可以不用保证处处同时一致,只要保证最后结果一致即可,而强一致性指的是业务操作需要处处且同一时刻都要保持事务一致。
- mq如果要保证最终一致性则需要保证两点:首先是生产者要保证100%的消息投递,利用事务消息机制来保证,第二是消费者这一端需要保证幂等消费,利用唯一性id+业务自己来实现。
如何保证消息消费的幂等性
其实就是保证消息不会被重复消费,但是所有的mq中间件都没有实现消息的幂等消费,需要使用者自己去实现,最常见的就是rocketmq的消息id,但是不推荐,推荐根据业务自己去生成一个全局唯一id。
如何保证mq中消息的不丢失
首先要保证mq中消息的不丢失,要先来分析哪里会存在消息的丢失,首选是生产者往mq中推送消息的时候,然后是mq主从同步的时候,再是mq消息落盘的时候,最后是消费者消费消息的时候。
- 首先先来分析生产者往mq中推送消息的情况,这个情况最为复杂。每种mq中间件都用了不同的方式进行实现,首先是rocketmq。
- rocketmq会先向生产者发一个half消息,这个消息被生产者接收之后,会向mq发送一个确认收到半消息的通知。此时生产者会向mq发送具体的消息及本地事务状态,如果本地事务状态为成功,这条消息就可以被消费者消费,如果是失败就直接返回失败,如果是未确认状态就会不断向生产者发起回查,这个回查的次数是15次,如果超过15次就会被定性成失败消息。这就是rocketmq事务消息机制,用来处理分布式事务场景。
- rabbitmq:第一种是利用回调机制来保证,第二是利用手动事务的方式,有三个api。分别是channel.txSelect()开启事务,channel.txCommit()提交事务,channel.txRollback()回滚事务,但是这种方式对channel是阻塞的,效率较低。第三是发布者确认的方式:这个方式借鉴了rocketmq的事务消息机制。
- kafka允许有消息丢失的情况。
- 然后是分析mq主从消息不丢失:rocketmq中消息同步的方式最好使用同步而不是异步。rabbitmq中如果是普通集群,消息是分散存储的,节点之间不会主动的进行消息的同步,有可能会丢失消息。而在镜像集群中,会主动进行消息的同步,这样数据的安全性会得到提高。
- 最后是消息存盘不丢失:rocketmq采用同步刷盘。rabbitmq采用将队列持久化。新增Quorum类型的队列,会采用raft协议进行消息同步。