消息发送
发送方发送消息, 因网络问题或其他问题未到MQ,则发送失败无影响。
若消息到达MQ, MQ通用做法是消息先写入预写日志,写入成功则通知发送方成功。再此场景:
- MQ预写失败,发送方未收到成功通知,再发一次
- MQ预写成功,发送方未收到成功通知,同样messageId再发一次,MQ通过messageId判重,返回已发送过
MQ 稳定性
RocketMQ:
Topic和Broker是多对多关系(N:M)
1个Topic的消息被分散到多个broker组, broker组内通过主从(Master-Slave)模式保证可用性;
-
当一个broker组 broker-a不可用,消息仍可发往其他broker组;例如broker-b
-
当主节点不可用,发送方不能将新消息发往改broker组,但消费方仍能从从节点读取到历史消息; 例如Consumer2从broker-a组id为1的从节点消费消息
Kafka
采用了类似ElasticSearch的分片副本集群内分散部署方式,如下:
消息流程发送流程如下:
- Producer从ZK上找到Topic的分片(partition)Leader
- Producer发送消息到到该Leader服务器
- 分片副本从Leader处拉取新写入消息
当某台机器不可用时,该机器上的分片会通过ZK重新选出主分片,所以分片最少3份
消息消费
理想中大家希望MQ与Consumer间通信有且仅有一次,但由于网络异常或Consumer消费异常等原因。实际难以实现:
-
MQ只发送一次消息,这样如果有异常,Consumer就永远无法消费该消息
-
MQ发送消息,Consumer消费成功返回Ack, MQ再没收到消息前,衰减式重试发送消息; 这样消息会被发送至少1次以上,确保Consumer能消费到消息