一、MQ常见问题
- ① 消息可靠性
确保发送的消息至少被消费一次;
- ② 延迟消息
实现消息的延迟投递;
- ③ 消息堆积
处理消息无法及时消费的问题;
- ④ 高可用
避免单点MQ故障导致整体不可用;
二、消息堆积-惰性队列
1、消息堆积问题
当生产者发送消息的速度超过了消费者处理消息的速度,就会导致队列中的消息堆积,直到队列存储消息达到上限。最早接收到的消息,可能就会成为死信,会被丢弃,这就是消息堆积问题。
2、解决消息堆积方法
- ① 增加更多消费者,提高消费速度;
- ② 在消费者内开启线程池加快消息处理速度;
- ③ 扩大队列容积,提高堆积上限。
3、惰性队列
从RabbitMQ的3.6.0版本开始,就增加了Lazy Queues的概念,也就是惰性队列。
- ① 惰性队列特征
Ⅰ 接收到消息后直接存入磁盘而非内存;
Ⅱ 消费者要消费消息时才会从磁盘中读取并加载到内存;
Ⅲ 支持数百万条的消息存储。
- ② 设置惰性队列
要设置一个队列为惰性队列,只需要在声明队列时,指定x-queue-mode属性为lazy即可。
Ⅰ 可以通过命令行将一个运行中的队列修改为惰性队列,如下:rabbitmqctl set_policy Lazy "^lazy-queue$" '{"queue-mode":"lazy"}' --apply-to queues
Ⅱ 用SpringAMQP声明惰性队列,如下:
@Bean注解的形式,如下:
@Bean
public Queue lazyQueue(){
return QueueBuilder
.durable("lazy.queue")
.lazy() // 开启x-queue-mode为lazy
.build();
}
@RabbitListener注解的形式,如下:
@RabbitListener(queuesToDeclare = @Queue(
name = "lazy.queue",
durable = "true",
arguments = @Argument(name = "x-queue-mode", value = "lazy")
))
public void listenLazyQueue(String msg){
log.info("接收到lazy.queue的延迟消息:{}", msg);
}
- ④ 惰性队列优缺点
Ⅰ 优点
基于磁盘存储,消息上限高;
没有间歇性的page-out,性能比较稳定;
Ⅱ 缺点
基于磁盘存储,消息时效性会降低;
性能受限于磁盘的IO。
三、高可用-MQ集群
官方文档:Clustering Guide — RabbitMQ。
1、集群分类
- ① 普通集群
是一种分布式集群,将队列分散到集群的各个节点,从而提高整个集群的并发能力。
- ② 镜像集群
是一种主从集群,普通集群的基础上,添加了主从备份功能,提高集群的数据可用性。
注意:镜像集群虽然支持主从,但主从同步并不是强一致的,某些情况下可能有数据丢失的风险。
- ③ 仲裁队列
在RabbitMQ的3.8版本以后推出的,底层采用Raft协议确保主从的数据一致性。
2、普通集群
- ① 普通集群特点
Ⅰ 会在集群的各个节点间共享部分数据,包括:交换机、队列元信息。不包含队列中的消息;
Ⅱ 当访问集群某节点时,如果队列不在该节点,会从数据所在节点传递到当前节点并返回;
Ⅲ 队列所在节点宕机,队列中的消息就会丢失。
- ② 模拟普通集群搭建
Ⅰ 获取Cookie
RabbitMQ底层依赖于Erlang,而Erlang虚拟机就是一个面向分布式的语言,默认就支持集群模式。集群模式中的每个RabbitMQ 节点使用 cookie 来确定它们是否被允许相互通信。
要使两个节点能够通信,它们必须具有相同的共享秘密,称为Erlang cookie。cookie 只是一串最多 255 个字符的字母数字字符。
每个集群节点必须具有相同的 cookie。实例之间也需要它来相互通信。
首先获取Cookie,指令如下:
docker exec -it mq cat /var/lib/rabbitmq/.erlang.cookie
其中YYNCLCJEKVNUFYQFPNZH
这一串就是生成的Cookie,如下:
[root@localhost ~]# docker exec -it mq cat /var/lib/rabbitmq/.erlang.cookie
YYNCLCJEKVNUFYQFPNZH[root@localhost ~]#