RabbitMQ原理分析

RabbitMQ 简介

基于AMQP协议实现,主要作用是解耦,冗余,扩展性(增大消息入队和处理的频率变得很容易),平滑峰值,可恢复性,送达保证(ACK机制 消费者消费消息后必须返回相应的ACK),顺序保证等.

文章当中使用的RabbitMQ的版本是RabbitMQ 3.6.6.

关键概念

Exchange交换机

启动RabbitMQ相关的服务,会默认创建一个不可以删除的Exchange.
绑定规则:RoutingKey与队列名称相等(Direct).

生产者将他们生产的消息推入到交换机中,交换机决定将消息发送至下一个交换机或者是队列.
一般的情况都是一个交换机绑定的多个队列.交换机绑定交换机的会使数据流变的复杂,这种情况在一些业务场景可能会需要用到.

分为四种交换机类型:
BindingKey 是指与队列或交换机与交换机绑定的Key,根据相应的规则与RoutingKey进行匹配.
RoutingKey是指生产者告知Rabbit的路由Key.

1.Direct exchange (直接交换)
如果 Binding key 匹配, 那么Message就会被传递到相应的queue中.

2.Fanout exchange(广播类型)
多个队列会接收到这个消息
会向响应的queue广播。

3.Topic exchange (对key进行模式匹配)
routing key为一个句点号”.”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词)

*:注意这个只是匹配一个单词,要注意与正则匹配的中的概念进行区分.
#:匹配一个或多个单词.

如BindingKey:”TEST.TOPICB”、”TEST.TOPICA”, “TEST.TOPIC.A”, 那么我们设置Routing Key 设置为 “TEST.*” 那么会匹配 “TEST.TOPICB”、”TEST.TOPICA”.
如果设置Routing Key为”TEST.#” 那么会匹配”TEST.TOPIC.A”.

4.headers(通过headers里的键值对进行路由)
这里需要了解一下RabbitMQ的协议,可以通过rabbitmq官网下载AMQP协议.
headers类型的Exchange不依赖于routing key匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。
在绑定Queue与Exchange时指定一组键值对;当消息发送到Exchange时,RabbitMQ会取到该消息的headers(也是一个键值对的形式),对比其中的键值对是否完全匹配Queue与Exchange绑定时指定的键值对.如果完全匹配则消息会路由到该Queue,否则不会路由到该Queue。

如果没有队列绑定在交换机上,则发送到该交换机上的消息会丢失。
一个交换机可以绑定多个队列,一个队列可以被多个交换机绑定。
交换也可以互相进行绑定.但是一般情况下不推荐这样做,复杂情况下会使数据流变得难以理解.

Queue:队列

队列里存储消息,并且被消费者处理消息.
可以对对应的队列设置相应的存储消息策略,可以设置为持久存储,也可以设置过期时间.
一个队列可以有多个消费者,这点需要注意.Kafka当中的消费者不能存在多个,但是可以有多个消费者组.
之前说到交换机的概念,我们也可以将信息直接发送到指定的队列当中,这种方式只不过是通过了默认的交换机.

Consumer:消费者

根据AMQP 0-9-1,消费者支持两种方式消费:
1.推送方式
2.拉取方式

当应用需要丢弃这个消息(basic.reject)或者是重新入队(basic.nack),我们可以返回相应的响应.
需要注意的是绝不能在多条消息消费时(multiple)返回basic.reject.

Binding:绑定

Bindings就是之前提过的交换机中的BindingKey.
绑定是决定消息该从交换机放入到哪个队列,或者放到哪个exchange里面的规则.

Vhsot:虚拟主机

虚拟主机,这个概念与nginx 虚拟域名类似,主要是一些权限的管理,vhsot的相关配置不可以跨越,完全隔离环境.

每个vhost都有自己的connections, exchanges, queues, bindings等.
因此这个概念与nginx当中的server block中的虚拟域名概念的类似.

Broker/Cluster

一个RabbitMQ broker运行着一组包含着多个或者一个Erlang node,每一个node运行着RabbitMQ 共享用户 bindings,虚拟主机,队列交换机等.
这些节点集合称为集群.
RabbitMQ集群当中的节点都是相等的,没有follower和leader.

RabbitMQ可靠性

接下来写一些重点需要介绍的内容,可靠性也与可用性息息相关.

ACK与Confirm

ACK机制保证了生产者与消费者标记消息被处理.
ACK保证了消息最少发送一次,当没有ACK的时候消息并不算被消费,因此消费者没有发送对应的ACK或者断开了连接那么消息会被重新放入到队列当中.

生产者的Confirm,与消费者的ACK类似,但是需要注意的生产者发送消息是多条消息,所以需要Confirm这个机制来保证消息被正确接收,还有Transaction机制保证消息的事务处理.

HeartBeat:心跳包

HeartBeat 作用防止TCP网络连接中断,帮助RabbitMQServer找出断开的连接.也可以用来断开空闲的连接.

消费者与生产者

当消费者失去连接,生产者失去连接或者崩溃,或者RabbitMQ进行了fail over,生产者需要发送未被ACK的消息,消费者需要注意重复消息的处理,尽量确保幂等性.
这样确保了消息最大的可靠性,完整性.

这里需要注意下生产发送到消息到多个镜像队列可能会引起一些性能问题,因为需要等待每个队列的ACK.

RabbitMQ高可用

Rabbit如何保证高可用?
通过镜像队列的方式,当然基于镜像队列还有一些技术保证了高可用,例如事务机制和发布确认机制,如何新增镜像,持久化存储策略等.

每个镜像的队列有一个MASTER以及一个或多个备用镜像.
其中队列都有自己的MASTER,MASTER会处理读写消息,备用镜像不会分担MASTER读写消息的负载.

每当接受到生产者生产的消息,MASTER首先会处理消息,然后推送到备用镜像.

HA-MODE

ha-mode 有三种策略:
ha-mode:Excaxtly 通过ha-param 指定具体设定镜像的个数的值.如ha-param:2那么将有集群中两个节点会建立备用镜像.推荐值为(N/2+1) N为集群当中的节点个数.
ha-mode:all 会在集群中的所有节点建立备用镜像.一般不推荐.
ha-mode:nodes 通过ha-param指定建立备用镜像节点的名称.如 ha-param:test,那么在test节点当中会建立镜像.

故障恢复机制

当MASTER发生故障后:
1.运行最长时间的备用镜像会成为MASTER.如果备用镜像中没有完全同步MASTER中消息,那么这些消息会被丢失.
2.镜像会认为之前的消费者都失去了连接,会把已经发送给消费者并等待ACK所有的消息重新入队.
3.消费者会被通知故障恢复
4.消费者会消费重复入队消息,这里需要注意
5.当选择镜像变为MASTER时,此时没有从MASTER同步到备用镜像的数据会丢失掉.如果MASTER发生故障,消息会被发送到镜像,一旦镜像成为MASTER,这些消息会被添加到队列当中.如果消息被发送到镜像上,那么镜像会被路由到MASTER进行处理.
6.生产者客户端发送的消息任然需要被确认发送到生产者.

RabbitMQ的安装

wget http://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm
安装rpm仓库
rpm -Uvh erlang-solutions-1.0-1.noarch.rpm‘’
安装erlang
yum install erlang -y

下载RabbitMQ的rpm,wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.6/rabbitmq-server-3.6.6-1.el6.noarch.rpm
yum install rabbitmq-server-3.6.6-1.el6.noarch.rpm
发现错误,安装依赖Requires: socat 。
更新源wget –no-cache http://www.convirture.com/repos/definitions/rhel/6.x/convirt.repo -O /etc/yum.repos.d/convirt.repo
yum install socat
yum install rabbitmq-server-3.6.6-1.el6.noarch.rpm
rabbitmq-server start

启动web管理界面
rabbitmq-plugins enable rabbitmq-management
增加外网访问用户,默认用户guest只能本地访问。
rabbitmqctl add_user admin 123456
设置用户组
rabbitmqctl set_user_tags admin administrator
设置默认vhost(”/”)访问权限
rabbitmqctl set_permissions -p “/” admin “.” “.” “.*”

注意修改在iptables修改相应的端口号

浏览器访问:http://IP:15672

其它

需要注意的是消息、队列、交换机的持久化默认是未开启的,需要满足的三个条件
1.需要将消息的 delivery mode 设置为2
2.消息被送入可持久化的交换机中
3.到达可持久化的队列中

如何查看没有ACK的消息

sudo rabbitmqctl list_queues name messages_ready messages_unacknowledged

消费者需要注意处理在故障恢复情况下的重复消息的处理,保证处理的幂等性.在一些场景尤为注意,如下单,转账等.

你可能感兴趣的:(RabbitMQ)