RabbitMQ作为一款轻量级高可用高性能的消息中间件,已经得到很多公司青睐,特别是一些有金融背景的公司。若对消息要求很高,但消息的量级不足千万时,RabbitMQ就是非常不错的选择。下面主要是记录一下RabbitMQ部分参数的用法及一些高级功能的总结。
Mandatory和Immediate是channel发布消息时的两个参数,主要用在当发布消息时,在不可达目的地时的消息如何处理,mandatory默认是false,当exchange无法根据类型和routing找到符合要求的队列时,消息将直接被丢弃;mandatory为true时,当出现找不到符合要求的队列时,消息将直接返回给发送者,配合ReturnListener使用,如果是spring集成amqp,则是ReturnCallback,主要代码如下:
template.setMandatory(true);
template.setReturnCallback(new ReturnCallback() {
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
logger.error("Messageid:{} send fail,replyCode:{},replyText:{}",
message.getMessageProperties().getCorrelationId(),replyCode,replyText);
RepublishMessageRecoverer recover = new RepublishMessageRecoverer(rabbitTemplate(), "ErrorExchange", "errorRoutingKey");
recover.recover(message, new Throwable("Republish fail message"));
}
});
在returnedMessage中,我把收到的错误消息再路由到错误的队列中,并记录一下日志,供后期排查问题用。
immediate参数设置为true时,表示消息发送到队列后,需要立即消费,若当前队列没有消费者,则消息将会被路由到生产者,在RabbitMQ3.0版本以后,这个参数因为影响镜像队列的性能,被去掉了,不再对immediate参数支持。
2,镜像队列
通俗的讲:镜像模式是RabbitMQ集群模式最常用的一种,当某个队列为镜像队列时,那集群中的其他机器会至少有一个此队列的备份队列,而且当master队列down掉时,备份队列中某一个(一般是此备份队列的第一个)会自动切换为master队列提供服务,保证服务的可用性。结构如下:
镜像队列一般以vhost为基础,当vhost为镜像模式时,该vhost下的队列都是镜像队列。当设置某个vhost的policies时,有几个关键性参数需要关注:
ha-mode:镜像模式,分为三种all,exactly,nodes。如下:
ha-mode |
ha-params |
result |
all |
none |
镜像队列会在整个集群中创建mirror队列,当集群新增一个节点时,镜像队列会mirror到此节点上。 |
exactly |
count |
在集群中mirror count个队列, |
nodes |
node names |
mirror队列将会被创建在指定的node名字上,节点名字也就是二郎节点在集群状态上显示的那个; |
ha-sync-mode:mirror队列的同步方式,有automatic和manual。默认为manual,当为manual时,master队列消息不会主动同步到slave,除非显式的调用同步命令。当为automatic时,master队列消息会主动同步到slave中,推荐设置为automatic。通过RabbitMQ管理界面设置镜像队列示例如下:
3.惰性队列
RabbitMQ从3.6.0版本开始引入惰性队列的概念,它会尽快的尽可能的持久消息到磁盘上,只有当消费者消费这些消息时才会加载到内存中。它被设计的一个最主要的目的是能够支持更长的队列(几百万量级),当消费者由于各种各样的原因比如延迟队列,消费者下线,消费者消费慢,down机等,致使长时间不能消费消费而造成消息堆积时,惰性队列就非常有用。
默认情况下,当生产消息时,队列消息会尽可能的保存在内存中,这样就可以尽快的把消息推送给消费者,即使是持久性的消息,在被写到磁盘时,也会保留一份在内存中。当broker需要释放内存时,会将内存中的消息paged out 到磁盘上。paged 一批消息到磁盘将会耗会时间和堵塞队列接收新消息。虽然最新的RabbitMQ版本提高了page算法,但是在大消息量级时,堵塞队列操作的情形依然存在。
惰性队列特性就是尽可能快速的把消息移动到磁盘保存,这就表示在普遍的操作中内存中会保留着非常少的消息,不过这会增加磁盘I/O的消费。
惰性队列有2中模式:default和lazy。默认模式是default,若想设置为惰性队列,
可以通过queue.daclare
也可以通过policy,如:
比如惰性队列与普通队列的对比,发送1千万条消息,每条消息的大小只为1KB,普通队列耗时801秒,而惰性队列在420秒,若此时没有消费者,惰性队列消耗内存1.5MB,而普通队列为1.2GB。
4.内存和磁盘设置
当内存使用超过配置的阈值或者磁盘剩余空间低于配置的阈值时,RabbitMQ都会暂时堵塞客户端的connection并停止接收从客户端发送过来的消息,以此来避免服务崩溃。
所以需要设置内存阈值,通过rabbitmqctl environment可以查看vm_memory_high_watermark参数,如下:
默认情况下RabbitMQ所使用的内存阈值设置为0.4,这并不意味着此时的RabbitMQ不能使用超过40%的内存,这仅仅只是限制了RabbitMQ的消息生产者。在最坏的情况下,二郎的垃圾回收机制会导致2倍的内存消耗,也就是80%的使用占比。
vm_memory_high_watermark正常取值范围在0.4到0.66,不建议取值超过0.7.也可以设置绝对值内存,如:
{vm_memory_high_watermark,{absolute,”1024MiB”}},命令如下:
rabbitmqctl set vm_memory_high_watermark {absolute,”1024MiB”}
5.state状态
管理界面上会有connection,channel,queue的state,这些状态有以下几种,idle,running,flow,blocked,blocking,所表达意思如下:
idle 空闲,一般在队列上没有生产者和消费者时会显式显示
running 表示进行生产或者消费
flow 表示消息的发送速率受限,connection,channel或者queue出现了性能瓶颈,因为消息的发送是从connection->channnel->queue->store流式处理的,queue环节容易造成性能瓶颈
blocked与blocking主要针对connection,blocking对应于不是试图发送消息的connection,比如消费者的connection,此时connection可以继续运行;blocked对应于一直有消息发送的connection,这种状态下的connection会停止发送消息。
6.HTTP API接口
RabbitMQ management 插件不仅提供了一个优秀的web管理界面,还提供了HTTP API接口以供调用。通过/api/nodes接口来获取集群节点的信息,返回结果是一个json字符串,通过解析json字符串,拿到我们需要的参数,包括磁盘,内存占用等的实时信息;如下:
获取exchange信息 ip:15672/api/exchanges/
获取queue信息 ip:15672/api/queues/vhost/name
获取各个节点信息 /api/nodes/name
获取所有的连接信息 /api/connections
获取指定的信道信息 /api/channels/channel
获取所有的绑定信息 /api/bindings
等等,具体详情请查看官网。
7.消息追踪
RabbitMQ management 提供了一个rabbitmq_tracing插件,执行开启命令后,会在控制台有tracing功能,它会记录所配置的vhost下所有的队列消息发送接收情况,有两种模式一个text,一个是json。缺点是:没有做到与业务队列逻辑隔离,当消息量很大时,消息轨迹记录也会消耗该台机器的性能,进而影响消息发送接收情况,所以是否开启此插件功能,需要根据业务逻辑及消息量级来考虑。
RabbitMQ高阶功能还有很多比如流控,跨集群的federation plugin 和shovel plugin,网络分区等等,后续会补充。