1.消息落库,进行变更消息状态:
A.写入数据库,可能涉及多个库,业务库,消息库
B.发送消息
C.消息确认
D.更新数据库消息状态
E.定时任务获取数据库消息状态
F.重试发送
G.重试数量大于 3 次,修改状态
2.消息的延迟投递,做二次确认,回调检查,
如果再高并发的情况下,消息就不要入库了,延迟投递,可以不保证首次100%的成功,但是一定要保证性能。
1.首次发送,一定等到业务数据入库之后再发送消息,Upstream serivce上游服务
2.延迟发送刚发送消息的检查消息
3.当消费者消费消息
4.消息消费成功之后,发送一个确认消费消息
5.CallBack服务收到消费者的确认消息,消费成功之后,做消息的持久化存储
6.CallBack服务检查,处理第二步发送的检查消息,检查数据库是否有处理成功,如果处理成功了,那么就不用处理任何事情,如果处理失败了,Callback服务再通知Upstream服务再次发送消息。
前提 : A, B两个节点组成一个镜像队列, B是Master节点
场景一
A先停, B后停
解决方案 : 该场景下B是Master, 只要先启动B, 在启动A即可。或者先启动A, 30秒之内启动B即可恢复镜像队列
场景二
A, B同时停机
解决方案 : 只需要在30秒内连续启动A和B即可恢复镜像
场景三
A先停, B后停, 且A无法恢复
解决场景 : 因为B是Master, 所以等B启起来以后, 在B节点上调用控制台命令 : rabbitmqctl forget_cluster_node A解除与A的Cluster关系, 再将新的Slave节点加入B即可重新恢复镜像队列
场景四
A先停, B后停, 且B无法恢复
解决方案 : 因为Master节点无法恢复, 所以较难处理, 在3.4.2之前没有什么好的解决方案, 但是现在已经有解决方案了, 在3.4.2以后的版本。因为B是主节点, 所以直接启动A是不行的, 当A无法启动时, 也就没有办法在A节点上调用rabbitmqctl forget_cluster_node B 命令了。但是在新版本中forget_cluster_node支持–offline参数, 支持线下移除节点。这就意味着运行rabbitmqctl在理想节点上执行命令, 迫使RabbitMQ在未启动Slave节点中选择一个节点作为Master。当在A节点执行**rabbitmqctl forget_cluster_node --offline B **时, RabbitMQ会mock一个节点代表A, 执行 forget_cluster_node命令将B移除cluster, 然后A就可以正常启动了, 最后将新的Slave节点加入A即可重新恢复镜像队列。
场景五
A先停, B后停, 且A, B均无法恢复, 但是能得到A或B的磁盘文件
解决方案 : 这种场景更加难以处理, 只能通过恢复数据的方式去尝试恢复, 将A或B的数据库文件默认在$RABBIT_HOME/var/lib目录中, 把它拷贝到新节点对应的目录下, 再将新节点的hostname改成A或B的hostname, 如果是A节点(Slave)的磁盘文件, 按照场景四处理即可, 如果是B节点(Master)的磁盘文件, 则按照场景三处理, 最后将新的Slave加入到新节点后完成恢复
这种场景很极端, 只能尝试恢复
场景六
A,B均停机, A,B均无法恢复, 且A或B的磁盘文件都无法恢复, 极端情况
解决方案 : 一首凉凉送给大家, 这种情况完全没办法解决
AMQP协议是一个二进制协议,拥有一些现代特点:多信道、协商式、异步、安全、跨平台、中立、高效。
Exchange:交换机,接收消息,并根据路由键转发消息到绑定的队列,
交换机属性:
· Name: 交换机名称
· Type: 交换机类型,direct、topic、 fanout、 headers
· Durability: 是否需要持久化
· Auto Delete: 当最后一个绑定到Exchange上的队列删除后,自动删除该Exchange
· Internal: 当前Exchange是否用于RabbitMQ内部使用,默认为False
· Arguments: 扩展参数,用于扩展AMQP协议定制化使用
消息的确认,是指生产者投递消息后,如果Broker收到消息,则会给我们生产这一个应答。
生产者进行接收应答,用来确定这条消息是否正常的发送到Broker,这种方式也是消息的可靠性投递的核心保障。
如何实现Confirm确认消息?
第一步:在channel上开启确认模式:channel.confirmSelect();
第二步:在channel上添加监听:addConfirmListener,监听成功和失败的返回结果,
Return消息机制:
Return Listener用于处理一些不可路由的消息。
我们的消息生产者,通过指定一个Exchange和Routingkey,把消息送到某一个队列中,然后我们的消费者监听队列,进行消息处理操作。然后我们的消费者监听队列,进行消息处理操作。但是在某些情况下,如果我们在发送消息的时候,当前的exchange不存在或者指定的路由key路由不到,这个时候我们需要监听这种不可达的消息,就要使用return listener。
Mandatory:如果为true,则监听会接收到路由不可达的消息,然后进行后续处 理,
如果为false,那么broker端自动删除该消息。(默认false)
rabbitMQ 提供了一种 qos (服务质量保证)功能,即在非自动确认消息的前提下,如果一定数目的消息(通过基于 consume 或者 channel 设置 QOS 的值)未被确认前,不进行消费新的消息。关键代码就是在声明消费者代码里面的:
1.prefetchSize:0
2.prefetchCount:会告诉 RabbitMQ 不要同时给一个消费者推送多于 N 个消息,即一旦有 N 个消息还没有 ack,则该 consumer 将 block 掉,直到有消息 ack
3.global:true、false 是否将上面设置应用于 channel,简单点说,就是上面限制是 channel 级别的还是 consumer 级别
备注:prefetchSize 和 global 这两项,rabbitmq 没有实现,暂且不研究。特别注意一点,prefetchCount 在 no_ask=false 的情况下才生效,即在自动应答的情况下这两个值是不生效的。
消费端的手工ack和nack,ack表示告知RabbitMQ已经成功消费消息,nack表示告知RabbitMQ消费端处理消息失败。
手工ack和nack使用场景:
1.消费端进行消费的时候,由于业务异常,我们可以进行日志记录,后续做补偿操作。
2.消费端由于服务器宕机等严重问题,比如消息消费一半时宕机,RabbitMQ既收不到 ack也收不到nack,此时消费端采用手工ack,等消费端服务重启好后,RabbitMQ回重 发此未能消费成功的消息,保障消息消费成功。
消费端的重回队列:
消费端重回队列是为了对没有处理成功的消息,把消息重新递给Broker。一般我们在实际应用中,都会关闭重回队列。