RabbitMQ使用时注意的一些问题

 1、前言数据库

      上篇RabbitMQ的博文竟然上了推荐,效果很不错,接下来咱们就来聊聊咱们RabbitMQ的方案,先谈方案,代码等等后面补上,感受不错给我点点关注,点点👍,原本能早点写完这篇博文的,因为工做最近很繁忙稍微推迟一些时间。缓存

 2、方案网络

      方案从两方面谈:生产者的投递以及消费端的消费。函数

      生产端设计

      生产端要保障的是消息发出去,RabbitMQ的Borker收到而且返会确认收到,因为网络的缘由消息发送Borker的时候可能失败,另外Borker返回给生产者确认的时候也可能发生闪断,因此为了保障100%投递咱们还须要合理的补偿机制。主要提供两种方案:消息打标和延时队列,仍是以最经典的下订单的场景为例:blog

      消息打标:队列

      消息打标的意思就是将消息落库之后,里面对消息状态进行记录,标记为发送中以及发送成功两种状态,而后采用定时轮询任务的方式去查找消息是否发送成功,具体看下图:回调函数

      

        接下来咱们详细介绍一下该流程:it

        1.订单生成同时落地到订单表和消息记录表,这里的消息记录表能够用MongoDB或者ES等方式进行替代;百度

        2.从消息记录表读取消息,发送消息到Borker同时更改消息状态为发送中;

        3.假设消息接收成功,Borker接收消息成功,并返回确认收到给生产者,这个时候更新消息记录表消息状态为成功;

        4.假设消息接收失败,可能失败的地方有两个处:Borker接收消息和返回消息均可能发生网络问题或者其余情况,致使生产者接收不到返回值;

        5.定时任务轮询,规定时间内没有发送成功消息再次按照步骤2进行投递,这个规定时间最多容忍2或者次查询轮询同一个条消息,若是依然接收不成功,那么则设置消息接收失败,这里多是交换机或者队列绑定失败形成的,须要咱们人工排查;

        延迟队列:

        使用延迟队列对消息的延迟投递,经过回调函数作二次检查确认消息投递成功;延迟队列是针对消息来讲,是指当消息发送出去之后不想当即被消费,而是等待特定的时间后,消费者才进行消费,好比咱们常见的支付付款,30分钟内必须付款成功,不然就异常,这里是延迟队列的经典场景;RabbitMQ来讲自己是不支持延迟队列的,可是能够经过死信队列和过时时间来实现延迟队列,简单解释下就是生产队发布消息到正常队列,设置过时时间,绑定死信交换机,消费端直接消费死信队列,这样就完成延迟队列的实现;经过延时队列去实现消息100%可靠投递的化,会涉及到消费者消费的问题,相对比较复杂;

       

       接下来咱们详细介绍经过延迟队列实现消息100%可靠投递的流程:

       1.当订单落库之后,生产者发送消息给Borker,而且发送延时消息,该消息是用来作二次检查确认的;

       2.消费者(2)消费成功之后,将消费成功的消息体回发到Borker中(3);

       3.回调服务(4)消费Boker中消费者消费成功的消息体而且入库;

       4.当延时队列(5)中存在消息时候作检查数据库是否存在消息,若是存在着消息消费成功,若是不存在则消息消费失败,同时再次调用生产者发送消息;

       以上就是我前面提到过的两种方案,咱们公司如今仍是再用第一种 ,对于第二种主要是为了提高系统的吞吐量,减小一次入库;其实合适思想就是经过补偿,来完成消息100%投递,这里面就存在一个问题,同一条消息可能会被投递屡次,可能照成消费端屡次消费同一条消息,因此这个时候咱们就要考虑客户端幂等性的设计;另外消费端消费的时候,消息的顺序是得不到保障的,若是有业务之间相互依赖就须要考虑消息顺序不一致时候处理。

       消费端

       消费端消费须要注意得地方就是上面提到得两种状况:幂等性以及消息的顺序问,接下来咱们也来聊一聊消费端的设计问题。

       幂等性

       幂等性这个也是咱们Web端设计时候要考虑的问题之一,幂等性就是屡次提交与一次提交看到的结果是相同的,这里解释的有点简单,感兴趣的本身百度下深刻了解下;这里咱们来聊聊咱们消费端怎么来设计实现幂等;

       1.惟一id+业务规则,利用数据库主键去重,咱们如今就是经过惟一id去重,业务规则具体能够根据大家的使用场景去决定你是否须要加上这个条件;

       2.经过Redis去实现幂等,经过Redis缓存去判断该消息是否消费过,可是这个时候咱们要考虑Redis与数据库怎么要保障原子性的问题;

       业务依赖(顺序性)

       这个问题其实我不太介意设计这么复杂,可是要是真是存在这样的场景,那也聊一聊个人一些想法:

       1.保障顺序消费的消息都须要在同一个队列中,保障顺序消费的消息的Id是一致的,而且消费者只能有一个;

       2.增长消息体属性:顺序消费的标记用来区分谁先消费;

       3.当消费端消费之后,若是是消费顺序正确,那么落库,若是消息顺序不正确,则先落库消息,而且发送延时消息;

       4.当收到延时队消息的时候,而后根据消息id查询数据库,进行数据处理,若是仍是顺序不对则再次发送延时消息;

       为何这么设计?其实不这么设计也是能够,好比咱们消息顺序不对的时候,直接投入延时队列,这种不能区分到底谁先被消费,只能靠随机去尝试,极端状况下可能不少次都没法保证顺序是一致,因此我增长顺序标记的想法,为何要保证到同一个队列和只有一个消费者,这是为了保证顺序性,当多个队列,多个消费者的时候顺序性更难保证。

       以上都是我本身的一些想法,若是发现不对,请指正谢谢!

 3、结束

       最近一段时间比较忙,代码部分我想作一些封装,暂时没时间写,等等稳定之后补充上,你们在稍微等等,接下来还会介绍一些消息存储和镜像队列方面的知识,欢迎你们加群438836709!欢迎你们关注我!

       

相关文章
相关标签/搜索