五一期间去韩国游玩,顺便去了朋友公司扯淡去了。 所谓的扯淡,就是过去听技术分享,有python, golang, devops,docker一些话题。总的来说,技术方面跟国内还是有一些差距的。
正题开始,因为业务的各方面的强需求,我们使用了rabbitmq作为消息队列,利用rabbitmq的ack机制来确认消息的可靠性。 但是rabbitmq本身是没有绝对的消息顺序机制的,单个queue在多消费者下不能保证其先后顺序。 另外ack的机制会触发消息重复消费的,需要我们在设计上避免该问题。
该文章写的有些乱,欢迎来喷 !
关于消息的重复执行
首先我们可以确认的是,触发消息重复执行的条件会是很苛刻的! 也就说 在大多数场景下不会触发该条件!!! 一般出在任务超时,或者没有及时返回状态,引起任务重新入队列,重新消费! 在rabbtimq里连接的断开也会触发消息重新入队列。
消费任务类型最好要支持幂等性,这样的好处是 任务执行多少次都没关系,顶多消耗一些性能! 如果不支持幂等,比如发送信息? 那么需要构建一个map来记录任务的执行情况! 不仅仅是成功和失败,还要有心跳!!! 这个map在消费端实现就可以了!!! 这里会出现一个问题,有两个消费者 c1, c2 ,一个任务有可能被c1消费,如果再来一次,被c2执行? 那么如何得知任务的情况? 任务派发! 任务做成hash,固定消费者!
坚决不要想方设法在mq扩展这个future。
一句话,要不保证消息幂等性,要不就用map记录任务状态.
关于消息的绝对顺序执行
我们遇到的大多数场景都不需要消息的有序的,如果对于消息顺序敏感,那么我们这里给出的方法是 消息体通过hash分派到队列里,每个队列对应一个消费者,多分拆队列。
为什么要这么设计? 同一组的任务会被分配到同一个队列里,每个队列只能有一个worker来消费,这样避免了同一个队列多个消费者消费时,乱序的可能! t1, t2 两个任务, t1 虽然被c1先pop了,但是有可能c2先把 t2 任务给完成了。
一句话,主动去分配队列,单个消费者。
基于Rabbitmq的多任务处理框架
这里提一下,我们用rabbitmq实现了一个颇为复杂的架构,节省了太多的mq连接及消耗。通过python pika gevent实现的,因py有gil,所以使用多进程来跑多核,进程之间不使用共享变量,而是用队列来传递ack信号。
这里实现的场景是用pika消费rabbitmq,然后把获取到的任务提丢到队列,另一个进程去消费该任务,然后触发ack。
END.