1.基本消息:
同步发送:一个生产者一个消费者,生产者发送的时候会同步等待broker的状态
异步发送:一个生产者一个消费者,生产者发送的时候不会等待broker的状态,直接继续下面的业务
单向发送:只管发不管broker是否接收到,适用于消息日志
2.顺序消息:一个生产者发送多个消息,每个消息又有多个步骤。比如一个订单号有多个步骤,每个订单下的多条消息顺序都是固定从0~5的
核心代码:
SendResult sendResult = producer.send(msg, new MessageQueueSelector() { @Override public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) { Integer id = (Integer) arg; int index = id % mqs.size(); return mqs.get(index); } }, orderId);
3.广播消息:广播消息并没有特定的消息消费者样例,这是因为这涉及到消费者的集群消费模式。在集群状态(MessageModel.CLUSTERING)下,每一条消息只会被同一个消费者组中的一个实例消费到。
只需要设置这个参数:
consumer.setMessageModel(MessageModel.BROADCASTING);
4.延迟消息::比如12306买票,下单成功后需要在30分钟内付款。延迟消息实现的效果就是在调用producer.send方法后,消息并不会立即发送出去,而是会等一段时间再发送出去
message.setDelayTimeLevel(3)
1到18分别对应
messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
5.批量消息:rocketmq发送消息是有大小限定的,这里默认4M,如果数据量实在太大我们就分批发送。由业务层进行消息拆分
6.过滤消息:并不是broker发送的所有消息消费者都需要接收,如果不需要的我们则过滤掉。
过滤包括2中方式:1.基本的Tag过滤 2.Sql过滤,进行sql过滤的时候,需要配置2m-2s的配置文件,新增enablePropertyFilter=true这个配置参数,然后重启broker服务,不需要重启nameserver.
7.事物消息:用来保证redis和mysql数据一致性非常有用
1、事务消息不支持延迟消息和批量消息
1.如果是commit那么直接推送给消费者
2.如果是ROLLBACK_MESSAGE则直接丢弃
3.如果是UNKNOW每个一段时间进行检查一次,如果在这个时间间隔中状态变为commit那么推送给消费者,如果是ROLLBACK_MESSAGE也是丢弃处理,如果还是unknow那么继续检查,直到检查15次还是unknow那么该消息也直接丢弃。
问题分析:
使用RocketMQ如何保证消息不丢失?
1,2,4三个场景都是跨网络的,而跨网络就肯定会有丢消息的可能
对于3这个环节,通常MQ存盘时都会先写入操作系统的缓存page cache中,然
后再由操作系统异步的将消息写入硬盘。这个中间有个时间差,就可能会造成消息
丢失。如果服务挂了,缓存中还没有来得及写入硬盘的消息就会丢失
RocketMQ消息零丢失方案
1.生产者使用事务消息机制保证消息零丢失
2.同步刷盘
3.消费者端不要使用异步消费机制,消费成功直接commit,失败则rollback.
正常情况下,消费者端都是需要先处理本地事务,然后再给MQ一个ACK响应,这时
MQ就会修改Offset,将消息标记为已消费,从而不再往其他消费者推送消息。所以
在Broker的这种重新推送机制下,消息是不会在传输过程中丢失的
这种异步消费的方式,就有可能造成消息状态返回后消费者本地业务逻辑处理失败
造成消息丢失的可能
RocketMQ特有的问题,NameServer挂了如何保证消息不丢失?
NameServer之间没有数据交互所以不存在脑裂问题,只要有一台服务是好的就可以对外提供服务。
如果集群中所有的NameServer节点都挂了呢?
那肯定不能对外提供服务了
RocketMQ消息零丢失方案总结:
生产者使用事务消息机制。
Broker配置同步刷盘+Dledger主从架构
消费者不要使用异步消费。
整个MQ挂了之后准备降级方案,用keepalived做高可用。