其中生产者发送普通消息值得注意的几个点:
其中消费者订阅普通消息值得注意的几个点:
顺序消息
消费消息的顺序要同发送消息的顺序一致,在 RocketMQ 中,主要指的是局部顺序,即一类消息为满足顺 序性,必须 Producer 单线程顺序发送,且发送到同一个队列,这样 Consumer 就可以按照 Producer 发送 的顺序去消费消息。
普通顺序消息
顺序消息的一种,正常情况下可以保证完全的顺序消息,但是一旦发生通信异常,Broker 重启,由于队列 总数发生变化,哈希取模后定位的队列会变化,产生短暂的消息顺序不一致。 如果业务能容忍在集群异常情况(如某个 Broker 宕机或者重启)下,消息短暂的乱序,使用普通顺序方 式比较合适。
严格顺序消息
顺序消息的一种,无论正常异常情况都能保证顺序,但是牺牲了分布式 Failover 特性,即 Broker 集群中只 要有一台机器不可用,则整个集群都不可用,服务可用性大大降低。 如果服务器部署为同步双写模式,此缺陷可通过备机自动切换为主避免,不过仍然会存在几分钟的服务不 可用。(依赖同步双写,主备自动切换,自动切换功能目前还未实现) 目前已知的应用只有数据库 binlog 同步强依赖严格顺序消息,其他应用绝大部分都可以容忍短暂乱序,推 荐使用普通的顺序消息
原因:生产者分布式超时的问题,消费者意外宕机,进度未及时储存。
解决:应用方收到消息后,可通过Tair、DB等去重。
消息一旦进入死信队列,则不再向应用投递,MetaQ监控系统会向应用报警 (报警功能开发中)
由于消息一旦进入死信队列,则不能再被订阅,建议应用在最后一次重试消费时,将失败消息保存到DB
MetaQ每台服务器提供大约亿级的消息堆积能力(多个业务方共用),超过堆积阀值,订阅消息吞吐量会下降。
MetaQ采用了长轮询方式从Broker拉消息,实时性同Push方式一致,消息的延迟时间大约几毫秒左右。
com.taobao.metaq v3.0 = RocketMQ + 淘宝个性化需求
对于优先级问题,可以归纳为 2 类
1) 只要达到优先级目的即可,不是严格意义上的优先级,通常将优先级划分为高、中、低,或者再多几个级 别。每个优先级可以用不同的 topic 表示,发消息时,指定不同的 topic 来表示优先级,这种方式可以解决 绝大部分的优先级问题,但是对业务的优先级精确性做了妥协。
2) 严格的优先级,优先级用整数表示,例如 0 ~ 65535,这种优先级问题一般使用不同 topic 解决就非常不合 适。如果要让 MQ 解决此问题,会对 MQ 的性能造成非常大的影响。这里要确保一点,业务上是否确实需 要这种严格的优先级,如果将优先级压缩成几个,对业务的影响有多大?(可以放入之前进行排序,优先级高的先放入队列,但这个时候又要保证顺序性)
Broker 端消息过滤
在 Broker 中,按照 Consumer 的要求做过滤,优点是减少了对于 Consumer 无用消息的网络传输。 缺点是增加了 Broker 的负担,实现相对复杂。
Consumer 端消息过滤
这种过滤方式可由应用完全自定义实现,但是缺点是很多无用的消息要传输到 Consumer 端。
回溯消费是指 Consumer 已经消费成功的消息,由于业务上需求需要重新消费,要支持此功能,Broker 在向 Consumer 投递成功消息后,消息仍然需要保留。并且重新消费一般是按照时间维度,例如由于 Consumer 系统故障, 恢复后需要重新消费 1 小时前的数据,那么 Broker 要提供一种机制,可以按照时间维度来回退消费进度。
RocketMQ 支持定时消息,但是不支持任意时间精度,支持特定的 level,例如定时 5s,10s,1m 等。
Producer Group
用来表示一个发送消息应用,一个 Producer Group 下包含多个 Producer 实例,可以是多台机器,也可以 是一台机器的多个进程,或者一个进程的多个 Producer 对象。一个 Producer Group 可以发送多个 Topic 消息,Producer Group 作用如下:
1. 标识一类 Producer
2. 可以通过运维工具查询这个发送消息应用下有多个 Producer 实例
3. 发送分布式事务消息时,如果 Producer 中途意外宕机,Broker 会主动回调 Producer Group 内的任意 一台机器来确认事务状态。
Consumer Group
用来表示一个消费消息应用,一个 Consumer Group 下包含多个 Consumer 实例,可以是多台机器,也可 以是多个进程,或者是一个进程的多个 Consumer 对象。一个 Consumer Group 下的多个 Consumer 以均摊 方式消费消息,如果设置为广播方式,那么这个 Consumer Group 下的每个实例都消费全量数据。
发送消息可以将内容封装在一个util工具类中,调用这个工具类就可以实现消息的发送。(其实很多中间件的实现都是分为部署和使用两步,可以在util中把它部署好了,然后封装在工具类中,那么就可以直接使用了,十分的方便,比如说缓存或者开关什么的,都可以)
接受消息的话,一般就是一个监听器,可以理解为有消息的时候就会调用这个方法。所以实现的时候,通常就是实现或者继承一个类或接口,然后实现对应的方法就可以了。