想想为什么要应用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就能够了。
发表回复