UOS 4.0 - RabbitMQ 高级特性(测试篇)
Posted 同方有云
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UOS 4.0 - RabbitMQ 高级特性(测试篇)相关的知识,希望对你有一定的参考价值。
host: generic-1, generic-2, generic-3
user: nyao
vhost: nyao
queue: simple_queue
示例程序中,给出了最基本的使用方式,可根据需要自行修改测试
只创建 exchange 不创建 queue 是不是可以,exchange 的行为是怎样的?
答案:可以只创建 exchange,不创建 queue,此时认为 exchange 没有与任何 queue binding,故到达这个 exchange 的所有消息都会被丢弃。千万必要被网上的教程误导,官方文档说的很明白,exchange 和 queue 在 rabbitmq server 端是两种角色,分别通过 channel.exchange_declare 和 channel.queue_declare 在客户端进行声明。
exchange 相当于信箱的角色,用户通过 channel.basic_publish 像特定的 exchange 即信箱中投递信件,当然信上要写上 xxxx 收(即 routing_key)
exchange 收到客户端投递的信件后,要开始送信,那么送给谁呢?所以我们要通过 channel.queue_binding 函数,将对应的 queue 赋予名字 xxxx(即 binding_key),这时候 exchange 就会在与他绑定的 queue 中寻找是否有对应的 queue,然后就把这封信投递给它,如若没有,那么就直接丢弃了。
当然如果创建 exchange 的时候设置了 durable = True,是不是就不会丢弃了呢?自然不是,durable 只在 rabbitmq 进程挂掉,重启,并且从异常中恢复的时候,保证其中的消息不丢失,如果 exchange 拿到的信没地方投递,该丢弃的一样丢弃,这也很正常,如果没地方投信,还一直存着,越积越多肯定就出问题了。
所以使用 rabbitmq 时,理解好 exchange 和 queue 角色至关重要,为后续研究 rabbitmq 的使用和优化铺平道路。
如果设置 queue 或者 exchange 为 auto_delete = True,在 queue 中仍然有数据时候会不会自动删除 queue 和 exchange,何时可以删除?
答案:即使设置了 auto_delete 为 True,在队列中有数据时,是不会自动被删除的
可以看到,此时 exchange hello_ning 和 queue hello_queue 都还是存在的,现在我们将 queue 中的数据消费掉后,再次查看 queue 已经被自动删除了。
为了确认,我们进行第二次试验,在 hello_queue 中放入 10 条消息,但我们只消费 1 条,这时候会怎样呢?
在消费掉第一条数据后,直接 close channel,根据实验结果发现,queue 和 exchange 双双被删除了,所以 queue 和 exchange 是否被删除不取决于 queue 中是否有数据,那取决于什么呢?
我们继续实验,将两个 consumer 消费 hello_queue:
好了,我们再来看 exchange ,设置实验将一个 exchange binding 到 多个 queue 上面,观察 exchange 何时被删除
从上面测试可以得到两个结论:
无论是 queue 还是 exchange,第一次创建出来以后,即使 queue 没有 consumer,或者 exchange 没有 关联的 queue,都是不会被自动删除的
当 queue 没有任何 consumer 与它连接时,该 queue 就会被删除,无论该 queue 队列中是否仍然有消息未被消费
当 exchange 没有任何 与 之关联的 queue 时,exchange 才会被自动删除
所以对于 rabbitmq 的正确使用姿势是:
queue 不应该在 publisher 进行申明和创建,为什么?原因在于,如果后续没有任何 consumer 联入这个 queue,那么这个 queue 就会成为永远的僵尸 queue,可参见:rabbitmq queue僵尸队列,理论上只要用法得当,是不应该产生僵尸队列的。
ttl 设置是否能够确认生效
从上面的验证可以看出,ttl 功能是生效的。那么这个 ttl 功能能用来干嘛?解决现在 rabbitmq 队列堵了不会自动清理的问题,对于某些监控数据,或者是 rpc 消息,如果不是很严格的话是允许数据丢失的,那么我们就可以通过 ttl 来控制,比如 10 分钟内没有被消费掉,那么就丢弃消息。这样的好处在于,当 consumer 跪了以后,不会导致 queue 中大量的数据积压从而造成 rabbitmq 彻底挂掉,比如:现在的监控 queue 大量积压数据后,导致 rabbitmq server 不响应了,或者响应速度巨慢。
使用队列长度限制
那么到底是丢弃了后发来的10条,还是先发来的10条呢?
使用默认 policy (即非 HA 队列),测试从 generic-1 publisher 消息,是否能够从 generic-3 收到消息
从上面结果可知,正如 rabbitmq 官方文档中描述的那样,对于非 ha queue,publish 到一个节点上,可以从其他节点上成功 consume 消息,由于在消费消息的节点上没有相应的 queue,所以需要从其他节点上将数据同步过来,rabbitmq 在中间会起到一个 proxy 的作用,去到集群其他节点上,将消息取过来。
在来验证一下,如果我们将数据写入到 generic-1 中以后,把 generic-1 节点 down 掉后,再从 generic-3 上面 consume 消息
如我们预期,提示 simple_queue 在 generic-1 节点上,所以无法获取消息,报错为 generic-1 节点 down 掉了,不可达。
再次开启 generic-1 节点,发现消息能被收到了,说明消息被持久化了,我们来确认下
如我们预期,这确实是一个持久化的队列,所以能够在重启后,继续收到消息
通过配置 policy,将队列设置自动复制到两个节点上
为什么 generic-1 都启动起来了还是读不到呢? 原因是 generic-2 是最后挂掉的,那时候 generic-2 成为这个 queue 的 master 角色,而 generic-1 是不知道这时候 generic-2 上是否有数据更新的,所以消费的时候仍然要去找 generic-2。那如果 generic-2 起不来了是不是就瞎了呢?rabbitmqctl forget_cluster_node generic-2 命令,将 generic-2 移除出集群,这样就可以从 generic-1 上面读到数据了。
根据复制的理论分析发现,rabbitmq 应该还是有水平扩展能力的,比如:我们使用 3副本,但可以使用 3个节点的 rabbitmq 集群,但也可以使用 6 个节点的 rabbitmq 集群啊,所以吞吐不够的时候不要怕,扩展它,获得更高的吞吐量。
autoheal,pause_minority,ignore 有什么区别?
首先我们来看一下 autoheal,测试方法为阻断 generic-2 与 generic-1, generic-3 之间的通信
查看 rabbitmq 的状态:
从 cluster status 可以看出,rabbitmq 集群出现网络分区
分区1:{running_nodes,['rabbit@generic-3','rabbit@generic-1']}
分区2:{running_nodes,['rabbit@generic-2']}
那么这个时候 generic-2 是不是还可以工作呢? 答案是肯定的,我们可以向 generic-2 ,publish 和 consume 消息
但是由于 generic-2 是孤立节点,被一但被判别为这种状态,从 generic-2 上 publish 的消息,就不能像原些一样从 generic-3 上收到了。
出现分区后的,自动修复过程
可以看到,多数自动把少数给干掉了,原来在 generic-2 中存的 125 条消息没了,丢了。所以使用 autoheal 在很多情况下是不能保证消息不丢失的,那如果想要消息不丢失怎么办呢? 我们继续来看 pause_minority
与 autoheal 不同的是,我们看到 generic-2 节点出现分区后,已经不是 running 状态了
这个时候我们来向 generic-2 发个消息后,报错
此时,在让 generic-3 也出现分区,会是什么情况呢?
我们可以看到,所有节点全部都不是 running 状态,此时,集群就彻底不可用了。
恢复它
所以 pause_minority 的目标很明确,如果集群中节点自己判断为只能与少数联通时,那么这个分区中的所有节点都会被自动 down 掉。即分区中节点数量如果不超过半数,节点就不提供服务,这就保证了如果 queue 使用的复制策略是 ha-all,那么在集群能够工作的时候,queue 中肯定是有最新数据的。
看一下它的 queue 数据恢复
对于 ignore,故名思议就是出现分区以后,忽略,即不自动关闭节点,也不在节点联通和自动修复。
以上是关于UOS 4.0 - RabbitMQ 高级特性(测试篇)的主要内容,如果未能解决你的问题,请参考以下文章