RocketMQ 学习相关
RocketMQ vs. ActiveMQ vs. Kafka
Messaging Product | Client SDK | Protocol and Specification | Ordered Message | Scheduled Message | Batched Message | BroadCast Message | Message Filter | Server Triggered Redelivery | Message Storage | Message Retroactive | Message Priority | High Availability and Failover | Message Track | Configuration | Management and Operation Tools |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ActiveMQ | Java, .NET, C++ etc. | Push model, support OpenWire, STOMP, AMQP, MQTT, JMS | Exclusive Consumer or Exclusive Queues can ensure ordering | Supported | Not Supported | Supported | Supported | Not Supported | Supports very fast persistence using JDBC along with a high performance journal,such as levelDB, kahaDB | Supported | Supported | Supported, depending on storage,if using levelDB it requires a ZooKeeper server | Not Supported | The default configuration is low level, user need to optimize the configuration parameters | Supported |
Kafka | Java, Scala etc. | Pull model, support TCP | Ensure ordering of messages within a partition | Not Supported | Supported, with async producer | Not Supported | Supported, you can use Kafka Streams to filter messages | Not Supported | High performance file storage | Supported offset indicate | Not Supported | Supported, requires a ZooKeeper server | Not Supported | Kafka uses key-value pairs format for configuration. These values can be supplied either from a file or programmatically. | Supported, use terminal command to expose core metrics |
RocketMQ | Java, C++, Go | Pull model, support TCP, JMS, OpenMessaging | Ensure strict ordering of messages,and can scale out gracefully | Supported | Supported, with sync mode to avoid message loss | Supported | Supported, property filter expressions based on SQL92 | Supported | High performance and low latency file storage | Supported timestamp and offset two indicates | Not Supported | Supported, Master-Slave model, without another kit | Supported | Work out of box,user only need to pay attention to a few configurations | Supported, rich web and terminal command to expose core metrics |
启动过程
Start Name Server
nohup sh bin/mqnamesrv &
tail -f ~/logs/rocketmqlogs/namesrv.log
Start Broker
nohup sh bin/mqbroker -n localhost:9876 &
tail -f ~/logs/rocketmqlogs/broker.log
Send & Receive Messages
export NAMESRV_ADDR=localhost:9876
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer
Shutdown Servers
sh bin/mqshutdown broker
sh bin/mqshutdown namesrv
基本概念
消息模型(Message Model)
RocketMQ主要由 Producer、Broker、Consumer 三部分组成,其中Producer 负责生产消息,Consumer 负责消费消息,Broker 负责存储消息。Broker 在实际部署过程中对应一台服务器,每个 Broker 可以存储多个Topic的消息,每个Topic的消息也可以分片存储于不同的 Broker。Message Queue 用于存储消息的物理地址,每个Topic中的消息地址存储于多个 Message Queue 中。ConsumerGroup 由多个Consumer 实例构成。
消息生产者(Producer)
RocketMQ提供多种发送方式,同步发送、异步发送、顺序发送、单向发送。
消息消费者(Consumer)
主题(Topic)
代理服务器(Broker Server)
消息中转角色,负责存储消息、转发消息。代理服务器在RocketMQ系统中负责接收从生产者发送来的消息并存储、同时为消费者的拉取请求作准备。代理服务器也存储消息相关的元数据,包括消费者组、消费进度偏移和主题和队列消息等。
名字服务(Name Server)
名称服务充当路由消息的提供者。生产者或消费者能够通过名字服务查找各主题相应的Broker IP列表。多个Namesrv实例组成集群,但相互独立,没有信息交换。
就是根据topic 查询对应的那些 broker存储消息,类似于 kafka 的 ZK;
拉取式消费(Pull Consumer)
推动式消费(Push Consumer)
生产者组(Producer Group)
消费者组(Consumer Group)
RocketMQ 支持两种消息模式:集群消费(Clustering)和广播消费(Broadcasting)。
集群消费(Clustering)
集群消费模式下,相同Consumer Group的每个Consumer实例平均分摊消息
广播消费(Broadcasting)
广播消费模式下,相同Consumer Group的每个Consumer实例都接收全量的消息。
普通顺序消息(Normal Ordered Message)
普通顺序消费模式下,消费者通过同一个消息队列( Topic 分区,称作 Message Queue) 收到的消息是有顺序的,不同消息队列收到的消息则可能是无顺序的。
严格顺序消息(Strictly Ordered Message)
严格顺序消息模式下,消费者收到的所有消息均是有顺序的。
消息(Message)
RocketMQ中每个消息拥有唯一的Message ID,且可以携带具有业务标识的Key。系统提供了通过Message ID和Key查询消息的功能。
标签(Tag)
总结下主要和kafka不一样的点:
- 消费推拉都支持
- 消费模式多样,同时支持集群消费和广播消费
- 消费顺序多样,比如普通顺序消息就是kafka的方式, 同时还支持严格顺序消息 类似于kafka只有一个分区
- 消息体默认具有唯一的Message ID,也可以自己指定具有业务标识的Key和kafka类似, 但是不同的是 RQ 提供了通过Message ID和Key查询消息的功能。
- tag 可以在一个topic内,对不同的消息打标签
特性(features)
https://github.com/apache/rocketmq/blob/master/docs/cn/features.md
消息顺序:比如 订单创建、订单付款、订单完成 三个消息对于同一个订单,必须保证严格按照顺序消费才有意义。
顺序消息分为全局顺序消息与分区顺序消息;
- 全局顺序 对于指定的一个 Topic,所有消息按照严格的先入先出(FIFO)的顺序进行发布和消费。 适用场景:性能要求不高,所有的消息严格按照 FIFO 原则进行消息发布和消费的场景。类比kafka 一个partition
- 分区顺序 对于指定的一个 Topic,所有消息根据 sharding key 进行区块分区。 同一个分区内的消息按照严格的 FIFO 顺序进行发布和消费。 Sharding key 是顺序消息中用来区分不同分区的关键字段,和普通消息的 Key 是完全不同的概念。 适用场景:性能要求高,以 sharding key 作为分区字段,在同一个区块中严格的按照 FIFO 原则进行消息发布和消费的场景。类比kafka按照shardkey 进行分区
消息过滤:
目前支持2种, 1 是根据消息的tag进行过滤, 或者自定义过滤规则,目前RQ 这些是在broker实现的, 好处是减少 consumer端的开销。缺点是实现比较复杂。
消息可靠性:
- 机器挂了但是是马上可以恢复的,RQ 可以保证消息不丢失,或者丢失少量, 依赖刷盘是同步还是异步
- 若机器磁盘坏了, 单点故障无法恢复,这就依赖于分片的写策略了,若是异步写可以保证99%数据不丢失 , 若是同步双写可以保证100% 不丢失,但是开启同步双写会影响性能。
回溯消费:
就是业务逻辑出问题了, 需要重新消费, RQ 支持按照时间回溯,可以精确到毫秒级别。
事务消息:
该特性是其与其他消息存储的最大不同,包括 kafka 、rabbitmq ...
RocketMQ事务消息(Transactional Message)是指应用本地事务和发送消息操作可以被定义到全局事务中,要么同时成功,要么同时失败。RocketMQ的事务消息提供类似 X/Open XA 的分布事务功能,通过事务消息能达到分布式事务的最终一致。
定时消息:
就是延迟消息,消息投递到 broker之后不会被真正消费,只有到达指定时间之后才去消费, 具体实现大概如下 这些消息全部投递到 SCHEDULE_TOPIC_XXXX 的topic中 , 并按照延迟时间录入到不同的 queue中,broker会调度消费这些queue 再投递到真正的topic中。以上相同延迟的消息会放入一个queue,保证相同延迟消息的消费顺序性。
消息重试:
kafka消息消费的时候,默认是自动提交offset机制,可能导致消费失败了, 但是 offset已经提交了, 故这属于最多一次语义。但是要实现至少一次语义则必须消息队列实现消息重试机制。
重试场景如下:
- 业务错误比如手机号码注销了, 充值肯定充不进去,此时即使重试也不管用, 最好办法是 比如3S 之后再重试
- 比如DB 不可用了, 此时即使跳过, 消费其他的也还是不可用,所以最好的办法是sleep 30S
RocketMQ会为每个消费组都设置一个Topic名称为“%RETRY%+consumerGroup”的重试队列, 这个重试队列是针对消费组的,用于暂时保存因为各种异常而导致Consumer端无法消费的消息。考虑到异常恢复起来需要一些时间,会为重试队列设置多个重试级别,每个重试级别都有与之对应的重新投递延时,重试次数越多投递延时就越大。RocketMQ对于重试消息的处理是先保存至Topic名称为“SCHEDULE_TOPIC_XXXX”的延迟队列中,后台定时任务按照对应的时间进行Delay后重新保存至“%RETRY%+consumerGroup”的重试队列中。
消息重投:
当生产者投递消息失败时会发起,保证消息不丢失, 尽可能成功,但是会造成消息重复。当出现数据量大网络抖动的时候,重复投递是大概率事件,比如由于网络抖动,ACK失败,但是消息实际已经落盘了。另外生产者主动重发、消费者挂了, 触发新的负载均衡也会导致消息重复。
死信队列:
消费者消费失败,broker自动进行重试还是失败, broker就会把它投递到死信队列, 消息不会丢失。这条消息就叫做死信队列。
架构设计
https://github.com/apache/rocketmq/blob/master/docs/cn/architecture.md
NameServer 是全分布式的、平等部署的, produce注册的时候是向所有的NameServer广播注册, 其中任何一台挂了, 都没啥问题, 算是彻底解决了单点问题。
Broker 属于 一个master对应多个 Slave 架构。多个slave 是只读的可以分摊读的压力。
设计(design) 关键核心技术实现细节,比较复杂
https://github.com/apache/rocketmq/blob/master/docs/cn/design.md
样例
https://github.com/apache/rocketmq/blob/master/docs/cn/RocketMQ_Example.md
- 生产者
- 同步发送,这种可靠性同步地发送方式使用的比较广泛,比如:重要的消息通知,短信通知。
- 异步发送 callback,异步消息通常用在对响应时间敏感的业务场景,即发送端不能容忍长时间地等待Broker的响应。
- 单向发送消息, 不用管发送的结果,比如 日志发送
- 生产的时候自定义属性,message putUserProperty
- 消费消息
- 普通消费
- 顺序消息样例: 2种方式全局有序, queue内有序(发送时指定按照那个KEY进行hash)
- 延时消息 发送消息时指定 delayTimeLevel
- 批量消息,能显著提高传递小消息的性能,限制是这些批量消息应该有相同的topic,相同的waitStoreMsgOK,而且不能是延时消息。此外,这一批消息的总大小不应超过4MB。
- 当消息过大时需要执行消息列表分割
- 过滤消息样例
- 按照 TAG 进行过滤
- 订阅消息时,使用 用MessageSelector.bySql来使用sql筛选消息
- 事务消息
- 事务消息共有三种状态,提交状态、回滚状态、中间状态:
- 生产消息的时候需要指定 transactionListener
- executeLocalTransaction 当半消息发送成功之后回调
- checkLocalTransaction broker 周期性回调 check消息最终状态,使用 produce 定义的线程池去执行
- OMSProducer 本质上属于 openAPI的方式进行调用