乐趣区

关于大数据:解决rabbitmq消息队列的顺序及重复消费问题

想想为什么要应用 MQ?

1. 解耦,零碎 A 在代码中间接调用零碎 B 和零碎 C 的代码,如果未来 D 零碎接入,零碎 A 还须要批改代码,过于麻烦!

2. 异步,将音讯写入音讯队列,非必要的业务逻辑以异步的形式运行,放慢响应速度

3. 削峰,并发量大的时候,所有的申请间接怼到数据库,造成数据库连贯异样

应用了音讯队列会有什么毛病?

1. 零碎可用性升高: 你想啊,原本其余零碎只有运行好好的,那你的零碎就是失常的。当初你非要加个音讯队列进去,那音讯队列挂了,你的零碎不是呵呵了。因而,零碎可用性升高

2. 零碎复杂性减少: 要多思考很多方面的问题,比方一致性问题、如何保障音讯不被反复生产,如何保障保障音讯牢靠传输。因而,须要思考的货色更多,零碎复杂性增大。

如何保障音讯队列是高可用的?

应用集群的形式维持 MQ 的可高用性。

如何保障音讯不被反复生产?

保障音讯不被反复生产的要害是保障音讯队列的幂等性,这个问题针对业务场景来答分以下几点:

1. 比方,你拿到这个音讯做数据库的 insert 操作。那就容易了,给这个音讯做一个惟一主键,那么就算呈现反复生产的状况,就会导致主键抵触,防止数据库呈现脏数据。

2. 再比方,你拿到这个音讯做 redis 的 set 的操作,那就容易了,不必解决,因为你无论 set 几次后果都是一样的,set 操作原本就算幂等操作。

3. 如果下面两种状况还不行,上大招。筹备一个第三方介质, 来做生产记录。以 redis 为例,给音讯调配一个全局 id,只有生产过该音讯,将 <id,message> 以 K - V 模式写入 redis。那消费者开始生产前,先去 redis 中查问有没生产记录即可。

如何解决丢数据的问题?

1. 生产者丢数据

生产者的音讯没有投递到 MQ 中怎么办?从生产者弄丢数据这个角度来看,RabbitMQ 提供 transaction 和 confirm 模式来确保生产者不丢音讯。

transaction 机制就是说,发送音讯前,开启事物 (channel.txSelect()),而后发送音讯,如果发送过程中呈现什么异样,事物就会回滚 (channel.txRollback()),如果发送胜利则提交事物 (channel.txCommit())。

然而毛病就是吞吐量降落了。因而,依照博主的教训,生产上用 confirm 模式的居多。一旦 channel 进入 confirm 模式,所有在该信道下面公布的音讯都将会被指派一个惟一的 ID(从 1 开始),一旦音讯被投递到所有匹配的队列之后,rabbitMQ 就会发送一个 Ack 给生产者 (蕴含音讯的惟一 ID),这就使得生产者晓得音讯曾经正确达到目标队列了. 如果 rabiitMQ 没能解决该音讯,则会发送一个 Nack 音讯给你,你能够进行重试操作。

2. 音讯队列丢数据

解决音讯队列丢数据的状况,个别是开启长久化磁盘的配置。这个长久化配置能够和 confirm 机制配合应用,你能够在音讯长久化磁盘后,再给生产者发送一个 Ack 信号。大数据培训这样,如果音讯长久化磁盘之前,rabbitMQ 阵亡了,那么生产者收不到 Ack 信号,生产者会主动重发。

那么如何长久化呢,这里顺便说一下吧,其实也很容易,就上面两步

①、将 queue 的长久化标识 durable 设置为 true, 则代表是一个长久的队列

②、发送音讯的时候将 deliveryMode=2

这样设置当前,rabbitMQ 就算挂了,重启后也能复原数据。在音讯还没有长久化到硬盘时,可能服务曾经死掉,这种状况能够通过引入 mirrored-queue 即镜像队列,但也不能保障音讯百分百不失落(整个集群都挂掉)

3. 消费者丢数据

启用手动确认模式能够解决这个问题

①主动确认模式,消费者挂掉,待 ack 的音讯回归到队列中。消费者抛出异样,音讯会一直的被重发,直到解决胜利。不会失落音讯,即使服务挂掉,没有解决实现的音讯会重回队列,然而异样会让音讯一直重试。

②手动确认模式,如果消费者来不及解决就死掉时,没有响应 ack 时会反复发送一条信息给其余消费者;如果监听程序处理异样了,且未对异样进行捕捉,会始终反复接管音讯,而后始终抛异样;如果对异样进行了捕捉,然而没有在 finally 里 ack,也会始终反复发送音讯 (重试机制)。

③不确认模式,acknowledge=”none” 不应用确认机制,只有音讯发送实现会立刻在队列移除,无论客户端异样还是断开,只有发送完就移除,不会重发。

如何保障音讯的程序性?

针对这个问题,通过某种算法,将须要放弃先后顺序的音讯放到同一个音讯队列中。而后只用一个消费者去生产该队列。同一个 queue 里的音讯肯定是程序音讯的。我的观点是保障入队有序就行,出队当前的程序交给消费者本人去保障,没有固定套路。例如 B 音讯的业务应该保障在 A 音讯后业务后执行,那么咱们保障 A 音讯先进 queueA,B 音讯后进 queueB 就能够了。

退出移动版