RocketMQ是一款分布式、队列模型的消息中间件(3.2.6版本 )
1.能够保证严格的消息顺序
2.提供丰富的消息拉取模式
3.高效的订阅者水平扩展能力
4.实时的消息订阅机制
5.亿级别消息堆积的能力
专业术语:
producer:消息生产者,负责生产消息
consumer:消息消费者,负责消费消息
Push Consumer:Consumer的一种,应用通常向Consumer对象注册一个Listener接口,一旦接收到消息,
consumer对象立刻回调Listener接口的方法,基于心跳检测,不断询问消息队列是否有消息需要被消费。
即好像是broker不断的给consumer推送消息
Pull Consumer:Consumer的一种,通常主动调用Consumer的拉消息方法从broker拉取消息,主动权由应用控制
Producer Group:一类producer的集合名称,这类producer通常发送一类消息,并且逻辑一致。
Consumer Group:一类consumer的集合名称,这类consumer通常发送的是一类消息
broker:消息中转的角色,负责存储消息,转发消息,一般也称为server
广播消费:一条消息被多个consumer消费,即使这些Consumer属于同一个Consumer Group,消息也会被
Consumer Group中的每个consumer都消费一次。在JMS中相当于JMS publish/subscribe model
集群消费:同一个consumer group中的消息会被消费(天然的负载均衡)
顺序消费、不同顺序消费。。。。
配置broker-a.properties和broker-b.properties,消息为同一group的消息可以实现负载均衡。
集群的方式:
双master模式(推荐使用,性能最好)。
多Master多Slave方式,异步复制(可以保证实时消费)
多Master多Slave方式,同比双写(可以保证实时性消费,并且保证数据不丢失,但是性能会较异步复制差)
apache下的activeMQ可以设置持久化与非持久化,而RocketMQ可以保证消息的持久化
先订阅。后发布。可以保障消息是被每一条每一条消费的。
如果数据量很大(海量),先生产数据,然后consumer从MQ中批量的去拿出这些数据
负载均衡与重试机制:(RocketMQ不设置的时候默认为集群形式的消费)
MQ向Consumer发送消息失败时,会采取重试的策略,默认为16次,retries参数,重试时间越来越长。
当试了一定的次数依然是消息发送失败的话,要记录日志(写入数据库),否则数据丢失
方式消息的重复性消费,在消费者方代码层面进行幂等性判断。
RocketMQ天然的实现了负载均衡。消息被负载到不同的消费端(订阅了同样的组,并且topic被过滤)
如果消费消息时,某台机器消费消息出现故障(没有返回给MQ一个SUCCESS或者LATER信息),
则将消息分配给别的消费者服务器进行消费。
一定要先启动消费者端进行监听,再启动producer进行发送消息,否则会产生消息被重复多次消费的问题。
重复消费的问题无法进行规避,是必然存在的问题,如果业务对消费数据非常敏感,务必进行全局的去重
1.将消息的唯一键,可以使msgId,也可以是消息内容中的唯一标识性的字段,例如订单的id,
建议使用消息内容中的唯一性标识字段进行去重。例如:去重表
只能设置为广播形式(类似于ActiveMQ的Topic形式)和集群形式(负载均衡)
广播形式:消息需要被多个消费者都要消费
多主多从实现:2m-2s文件夹下,同步双写,异步刷盘实现主从集群配置
消息重试、顺序消费、事务消费、消息的堆积能力是RocketMQ的亮点
现在的版本没有支持分布式事务
消息都是持久化的,commit.log和consumerQueue.log中记录了消息
commitlog记录了所有发送的消息。而consumerQueue记录了消息的偏移量(位置)相对于commitlog
需要和index文件进行配合去检索
先启动nameServer,再启动broker,nameserver的作用相当于服务器之间通信的配置。
再去启动tomcat,配置classes下的config.properties
而Apache下的activeMQ没有消息的重发机制,消息持久化也不方便。
nameServer类似于ZK,做注册。消息内容真正落在了broker上
FilterServ是用来过滤消息的,过滤掉消息中的TAGS标签的信息。
RocketMQ的API详解:
集群模式:设置消费端对象的属性,MessageModel.CLUSTERING,这种方式就可以达到类似于ActiveMQ
水平扩展负责均衡消费消息的实现,这种行为可以支持先发送数据(就是生产端先传送数据到MQ),消费者
订阅主题发生在生产端之后都可以,比较灵活。
广播模式:设置消费端属性MessageModel.BOARDCASTING,
这种模式相当于生产端发送数据到MQ,多个消费
端都可以消费消息。
Producer:
普通消费:消费的顺序得不到保障,是随机的。
顺序消费:把相同业务逻辑的数据放到同一个topic的一个队列中去实现,一个topic理论上可以保存10000
个队列,消费端对应消费的是每一个完整的队列,从而保证了队列中消息的顺序消费
consumer实用的监听接口是:MessageListenerOrderly,返回值是ConsumeConcurrentlyStatus
此时一个线程只允许接收一个队列中的数据,线程和线程之间对于队列不冲突。
producer发消息时:相同的业务逻辑指定在一个queue中。
consumer接收消息时:实现MessageListenerOrderly,指定只有一个线程从一个队列中消费数据
可以有多个queue并行进行消费,每个queue属于指定的线程,并且互相不会影响
commitLog中的数据每天都会自动清理一次,所以commitLog不会产生内存不足现象。
事务消费(分布式事务):TransactionMQProducer两个阶段:
第一个阶段:把消息传递给MQ,消费端此时是不可见的,但是数据其实已经发送到broker上了
第二个阶段:为本地消息的回调处理,如果成功的话返回COMMIT_MESSAGE,则在broker上的
数据对消费端是可见的,失败则只为ROLLBACK_MESSAGE,消费端不可见。
1.支付宝在扣款事务之前,向实时消息服务请求发送消息,实时消息服务只会记录消息数据,
而不会去真正的发送,只有消息发送成功后才会提交事务。
2.当支付宝扣款业务被提交成功之后,向实时消息服务确认发送,只有在得到确认发送指令之后,
实时消息服务才回去发送真正的消息。
3.当支付宝扣款事务提交失败回滚后,向实时消息服务取消发送,在得到取消发送指令前,消息不会
被发送。
4.对于那些未确认的消息或者取消的消息,需要有一个消息状态确认系统定时的去支付宝系统查询这个
消息的状态并且进行更新。假设在支付宝扣款事务被成功提交之后,系统挂了,此时消息状态并未
被更新为“确认发送”,从而导致消息不能被发送。
优点:消息数据独立的进行存储,降低业务系统和消息系统之间的耦合。
缺点:一次消息发送过程需要两次请求,业务处理服务需要实现消息状态回查接口。
无需关注消费端,只需要关注生产端是否处理完本地的业务和消息是否发送了出去。
实现本地的事务时需要实现接口LocalTransactionExecutorxecutor,
实现executeLocalTransactionBranch进行操作,一边向MQ发消息,一边执行本地的代码。
会返回一个TransactionSendResult的状态作为本地事务执行成功之后的结果。
如果处理本地事务失败,仍然会发送第一条MQ,而第二条MQ不会发送。
sendStatus仅仅只是代表的Producer的消息成功的发出去了。
如果消费端消费失败,则会采用重试机制,当重试次数达到后还是错误的就由人工处理。
遇到问题:已经成功的向MQ发送了第一条prepared消息,并且本地数据业务操作完成,
但是在向MQ发送第二次确认消息发送的命令时,确认的消息发送失败?
阿里的做法:每隔一分钟去MQ中查询,将数据库中prepared的消息表信息提取出来
在producer中的check方法进行判断这个消息是否要去处理,如果rollback则删除prepared表
中的记录,如果commit则也将prepared表中的消息进行删除,在MQ中产生了新的消息。
消费端的去重:在消费端DB中创建一张去重表,保障了消息的消费的一致性。
consumer端:
pull:数据量大的情况下可以使用,指定每次拉取的数量,减缓服务器的压力。
取消息的过程需要用户自己来定义,首先通过打算消费的topic拿到MessageQueue的集合
遍历MessageQueue的集合,然后针对每一个messageQueue批量的取出消息,在一次取完后
记录队列下一次要取数据开始的offset,知道取完了,再换下一个messageQueue,比较繁琐。
push:consumer把轮询的过程给封装了,并且注册了MessageListener监听器,取到消息后,唤醒
MessageListener的ConsumerMessage()来消费,对用户而言,感觉消息是被推送过来的。