谈谈消息队列的设计与实现

1,295 阅读4分钟

定义

消息队列技术是分布式应用间交换信息的一种技术。

  • 消息队列可以驻留在内存或磁盘上,队列存储消息直到它们被应用程序取走。
  • 通过消息队列,应用程序可独立地执行,不需要直到彼此地位置或在继续执行前不需要等待接收程序接收此消息。

应用场景

  • 异步通信

  • 解耦业务

      基于消息解耦,关注“通知”,而非关注“处理” 
    
  • 错缝与流量控制

  • 广播

  • 时序保证

如图:

上图中,搜索时,需要去跟商品还有后台交互,交易时,也需要跟后台交互商品交互。四个模块之间地关联错综复杂,这时候可以借助消息队列去处理。

消息队列模型

  • 广播模式

  • P2P点对点

模块构成

  • Broker: 消息服务器
  • Producer: 消息生产者,业务地发起方,负责生产消息传递给Broker
  • Consumer: 消息消费者,业务地处理方,负责从broker获取消息并进行业务逻辑处理
  • Topic: 主题,发布订阅模式下的消息统一汇集地,不同生产者向Topic发送消息,由MQ服务器分发到不同的订阅者,实现消息的广播。
  • queue: 队列,P2P模式下,特定生产者向特定Queue发送消息,消费者订阅特定的queue完成指定消息的接收。
  • Message: 消息体,根据不同业务通信协议定义的固定格式进行编码的数据包,来封装业务数据,实现消息的传输。

传统通信协议

  • AMQP协议: 应用协议的一个开放标准,为面向消息的中间件设计
  • MQTT协议: 格式简洁、占用带宽小,移动端通信,PUSH、嵌入式通信系统,基于TCP的二进制协议。
  • STOMP: 简单文本消息协议。
  • XMPP协议: 基于XML的协议。
  • 自定义协议: ZeroMQ/Redis/KafKa/RocketMQ协议自定义二进制协议。
  • 基于TCP/IP Socket接口进行传输。

设计考虑点

从关注处理到关注通知

高级特性如下:

可靠投递

消费确认

重复消息和顺序消息

性能考虑

PUSH 或 PULL

业界产品

  1. RebbitMQ

  1. ZeroMQ

  1. Apache ActiveMQ

  1. Kafka

  1. Apache RocketMQ

6.NSQ (了解)

  1. beanstalkd(了解)

应用环境推荐

生产环境推荐

  • 高吞吐量、高可靠性可容忍场景的

    • 日志处理
      • kafka
  • 高可靠场景

    • 电商订单服务
      • RocketMQ

存储模型的区别

RocketMQ存储模型

顺序写,随机读。

  • 所有数据单独存储在一个commitLog里面,跟mysql中的binlog一样,安全顺序写,随机读。
  • 对最终用户展现的队列实际只存储消息在commitLog的位置信息,并且串行方式刷盘。
    • 好处
      • 队列轻量化,单个队列数据流非常少。
      • 对磁盘的访问串行化,避免磁盘竞争。
    • 缺点
      • 写顺序写,但是读变成完全随机读。
      • 读一条消息,先读Consume Queue,在读Commit Log,增加了读开销。
      • 要保证Commit Log与Consume Queue 完全一致,增加了架构设计的复杂性。

RocketMQ刷盘策略

支持异步刷盘

    写完PageCache直接返回。
    RocketMQ可配置。

写完内存就返回,异步的去刷新Disk。

支持同步刷盘

  • 写入PageCache,线程等待,通知刷盘程序刷盘。
  • 刷盘线程刷盘后,唤醒前端等待线程,
  • 可能是一批线程。
  • 前端等待线程向用户返回成功。

RocketMQ实现高可用

  • 对于非实时性消息
    • 对各Master-Slave对。
    • Pub多个Master
    • Sub多个slave
  • 对于严格时序消息
    • 单机单线程。
    • Master-slave 如果master挂了,会发送失败,同时也不能消费。
    • 这时候高可用如何保证???

设计方案

  • 目前nameServer是无状态的,Broker的心跳信息上报给nameServer。
  • 引入zookeeper,NameServer通过Zookeeper(nameServer A)竞争称为Controller
  • Broker依赖Zookeeper,通过Zookeeper获取Controller所在的nameServer。
  • Broker的心跳信息只上报给Controller,再由nameServer复制给其他nameServer nameServer地位变成不对等,有Master的概念。 切换过程中,通过Controller来切换slave变成Master,同时更新其他两个nameServer的路由信息。
  • NameServer Controller的HA由ZK来负责
  • Client任然是任意连接一台nameServer。

RocketMQ 消息可靠性。

  • ACK
    • RocketMQ Producer 重试三次
    • Consumer失败,可以异步再消费,可以回溯。
    • 消费Offset可以保存本地,或者保存到Broker
  • 网络
    • netty

推拉

  • 消费端采用推方式还是拉方式消费消息
    • PULL OR PUSH
      • Long Pulling