rainyzz's blog

消息队列简介

为什么要使用消息队列

  • 消息队列主要功能是解耦和,如用户下单时,只要完成核心流程就可以返回给用户,而不是等待所有相关操作(如发站内消息,发短信通知)都完成。对于实时性要求不强的流程,可以放到后台慢慢执行。
  • 消息队列也可以将巨大的数据写入压力舒缓到下游慢慢执行
  • 需要将数据向下游广播

消息队列模型

  • Push/Queue方式:每有一条新数据都会推送给消费者进行消费,如果消费者消费速度比较低时可能会造成数据堆积
  • Pull/Subscribe/Topic方式:消费者定时拉取消息数据,消费者能够指定位置,控制自己的消费速度,但是如果拉取间隔控制不好的话可能会造成数据延迟

总结来说,消费包括单播与广播。所谓单播,就是点到点;而广播,是一点对多点。当然,最常见的情况是组间广播、组内单播。组间广播将一个消息给多个业务方,组内单播是一条消息在一个组内只消费一次。

消息数据存储

  • 一般消息数据可能会存储在Broker中,Producer写入Broker,Consumer从Broker读取数据,Consumer回复消费确认,Broker删除/备份消息
  • 在Broker处可以完成错峰/流控/最终可达等一系列需求

消息队列设计中的问题

消息乱序

可以指定版本号,需要消费者和生产者来维护版本号,也可以记录消息的id,确保消息不重复
或者定义多个状态,某些消息在特定状态下是无效的

消息不丢失

  • 首先将消息落地,然后发送。当失败或者超时时,消息状态是待发送,定时任务不停轮询所有待发送消息,最终一定可以送达
  • 可能造成消息重复

消息重复

  • 幂等地处理消息,同一条消息处理多次应该达到的状态是一致的, 丢弃已经失效的消息
  • 消息唯一ID:业务方自定义的,还是根据IP/PID/时间戳生成的MessageId,如果有地方记录这个MessageId,消息到来是能够进行比对就能够发现重复

消息队列应该做的重复处理工作包括

  • Broker记录messageId,直到投递成功后清除,重复的ID到来不做处理,返回成功,就基本不会在server端产生重复消息。
  • 对于server投递到consumer的消息,由于不确定消息是在处理过程中还是已经丢失,重发之前询问对应消费者消息处理是否成功,如果询问无果,再重发。