RabbitMQ
1.死信队列
解决消息不能重新消费问题
1.消息被拒绝(basic.reject/ basic.nack)并且不再重新投递 requeue=false
2.消息超期 messageProperties.setExpiration()->可以做消息延时发送(还有一种方式类似于rocketmq的延时发送不过需要插件支持)
3.队列达到最大长度(队列满了,无法再添加数据到mq中)
2.幂等性(概念 任意多次执行所产生的影响均与一次执行的影响相同)
解决的问题消息重复消费
1.使用全局唯一ID数据库进行保存
2.利用redis(因为数据量较大最终需要考虑要保存到数据库中,可以先查缓存没有再查数据库)setnx
3.消息确认模式
解决的问题消息丢失问题
1.自动确认模式,消费者挂掉,待ack的消息回归到队列中。消费者抛出异常,消息会不断的被重发,直到处理成功。
不会丢失消息,即便服务挂掉,没有处理完成的消息会重回队列,但是异常会让消息不断重试
2.手动确认模式,如果消费者来不及处理就死掉时,没有响应ack时会重复发送一条信息给其他消费者;
如果监听程序处理异常了,且未对异常进行捕获,会一直重复接收消息,然后一直抛异常;如果对异常进行了捕获,
但是没有在finally里ack,也会一直重复发送消息(重试机制)
3.不确认模式,acknowledge="none" 不使用确认机制,只要消息发送完成会立即在队列移除,
无论客户端异常还是断开,只要发送完就移除,不会重发
4.消息顺序
mqserver本身没有支持,业务逻辑解决
1.消息实体中增加:版本号 & 状态机 & msgid & parent_msgid,通过 parent_msgid 判断消息的顺序
2.当一个消息执行完之后,再发布下一个消息
3.一个queue一个消费者以此消费
4.多个queue每个queue一个消费者 producer按顺序生成消息
5.消息丢失/消息重复消费
1.消息丢失(参考3.消息确认模式) 消息进入消费端即给server发送ack,由于某些问题导致消息没有被真正消费掉
2.消息重复消费
1.消费者挂掉或者失去连接(和mqserver失去连接但是和数据库连接正常)消息正在处理但是server检测到消费者失去连接会
发送给其他消费者
2.任务超时,或者没有及时返回状态
6.消费端限流
解决的问题巨量的消息瞬间全部推送过来导致消费端服务器崩溃
void BasicQos(uint prefetchSize,ushort prefetchCount,bool global)
消费端体现,一次最多能处理多少条消息(基本上为1),限流策略在什么上应用(channel--true,consumer---false)
prefetchSize:0
prefetchCount:会告诉RabbitMQ不要同时给一个消费者推送多余n个消息,
一旦有n个消息还没有ack,则该consumer将block调,知道有消息ack
global:true\false是否将上面设置应用于channel,简单的说就是上面限制是channel
级别的还是consumer级别,基本使用false。
7.Confirm和Return
解决消息生产失败问题
Confirm为消息发送exchange是否成功
Return为消息发送queue是否成功
8.消息如何100%投递成功
解决消息
消息存放到数据库赋值上响应状态(发送成功 消费成功等)
组成
- ExChange
- Direct routing key 一对一
- Fanout 忽略routing key 广播到所有的Queue中
- Topic 通配符匹配routing key
- Headers 忽略routing key 根据消息的header内容匹配
RabbitMQ消费消息的两种模式:推和拉
- 推模式(push)
- 效率高
channel.basicConsume(queneName,consumer)方法将信道(channel)设置成投递模式,直到取消队列的订阅为止;
在投递模式期间,当消息到达RabbitMQ时,RabbitMQ会自动地、不断地投递消息给匹配的消费者,而不需要消费端手动来拉取,
当然投递消息的个数还是会受到channel.basicQos的限制 - 耗内存
推模式将消息提前推送给消费者,消费者必须设置一个缓冲区缓存这些消息。优点是消费者总是有一堆在内存中待处理的消息,
所以当真正去消费消息时效率很高。缺点就是缓冲区可能会溢出 - 实时性好
- 拉模式(pull)
- 获取单条消息
使用channel.basicGet方法来进行消费消息 - 效率低
拉模式在消费者需要时才去消息中间件拉取消息,这段网络开销会明显增加消息延迟,降低系统吞吐量 - 实时性差
几个MQ的区别