消息队列的高可用

91 阅读2分钟

消息发送

发送方发送消息, 因网络问题或其他问题未到MQ,则发送失败无影响。

若消息到达MQ, MQ通用做法是消息先写入预写日志,写入成功则通知发送方成功。再此场景:

  • MQ预写失败,发送方未收到成功通知,再发一次
  • MQ预写成功,发送方未收到成功通知,同样messageId再发一次,MQ通过messageId判重,返回已发送过

MQ 稳定性

RocketMQ:

Topic和Broker是多对多关系(N:M)

RocketMQ架构.jpg 1个Topic的消息被分散到多个broker组, broker组内通过主从(Master-Slave)模式保证可用性;

  • 当一个broker组 broker-a不可用,消息仍可发往其他broker组;例如broker-b

  • 当主节点不可用,发送方不能将新消息发往改broker组,但消费方仍能从从节点读取到历史消息; 例如Consumer2从broker-a组id为1的从节点消费消息

Kafka

采用了类似ElasticSearch的分片副本集群内分散部署方式,如下:

Kafka副本保存形式.jpg

消息流程发送流程如下:

  • Producer从ZK上找到Topic的分片(partition)Leader
  • Producer发送消息到到该Leader服务器
  • 分片副本从Leader处拉取新写入消息

当某台机器不可用时,该机器上的分片会通过ZK重新选出主分片,所以分片最少3份

消息消费

理想中大家希望MQ与Consumer间通信有且仅有一次,但由于网络异常或Consumer消费异常等原因。实际难以实现:

  1. MQ只发送一次消息,这样如果有异常,Consumer就永远无法消费该消息

  2. MQ发送消息,Consumer消费成功返回Ack, MQ再没收到消息前,衰减式重试发送消息; 这样消息会被发送至少1次以上,确保Consumer能消费到消息