正文
一、什么是消息中间件
消息队列已经逐渐成为企业IT系统内部通信的核心手段。它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。当今市面上有很多主流的消息中间件,如老牌的ActiveMQ、RabbitMQ,炙手可热的Kafka,阿里巴巴自主开发RocketMQ等。
RabitMQ是使用Erlang编写的一个开源的消息队列,本身支持很多的协议:AMQP,XMPP, SMTP,STOMP,也正是如此,使的它变的非常重量级,更适合于企业级的开发。同时实现了Broker架构,核心思想是生产者不会将消息直接发送给队列,消息在发送给客户端时先在中心队列排队。对路由(Routing),负载均衡(Load balance)、数据持久化都有很好的支持。多用于进行企业级的ESB(企业服务总线)整合。
消息中间件的组成
Broker:消息服务器,作为server提供消息核心服务。
Producer:消息生产者,业务的发起方,负责生产消息传输给broker。
Consumer:消息消费者,业务的处理方,负责从broker获取消息并进行业务逻辑处理。
Topic:主题,发布订阅模式下的消息统一汇集地,不同生产者向topic发送消息,由MQ服务器分发到不同的订阅者,实现消息的广播。
Queue:队列,PTP模式下,特定生产者向特定queue发送消息,消费者订阅特定的queue完成指定消息的接收。
Message:消息体,根据不同通信协议定义的固定格式进行编码的数据包,来封装业务数据,实现消息的传输。
二、应用场景
解耦
如上图,未使用MQ的情况下,如果B、C、D三个系统,有需求改变,那么A系统都会响应的更改,使用MQ之后,我们只需要把数据发送的MQ中,B、C、D自己根据需求去mq订阅响应的内容即可,从而达到系统耦合的结果。
异步
如果某些需求场景不需要立即返回数据结果,那么就可以采用MQ的形式,对消息异步的处理,这样可以提高系统的响应速度。
削峰填谷
如果请求超过了服务器承受的最大值,那么就可能会击垮服务器,这时候,把请求通过mq队列缓存起来,来限制请求的峰值,从而达到保护服务器的目的。
三、消息中间件选型
四、RabitMQ环境搭建
单机模式
#拉取镜像 docker pull rabbitmq:3.9-management #创建容器并启动 [root@bogon ~]# docker run -d -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.9-management
登录 http://192.168.139.154:15672/#/ 默认账号密码是guest,guest
注意:如果安装过程出现这个错误,重启一下docker就可以解决了systemctl restart docker。
iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 15672 -j DNAT --to-destination 172.17.0.2:15672 ! -i docker0: iptables: No chain/target/match by that name
集群模式
安装容器
[root@bogon ~]# docker run -d --hostname rabbit1 --name rabbitmq1 -p 15672:15672 -p 5672:5672 -e RABBITMQ_ERLANG_COOKIE='rabbitmq_cookie' rabbitmq:3.9-management [root@bogon ~]# docker run -d --hostname rabbit2 --name rabbitmq2 -p 5673:5672 --link rabbitmq1:rabbit1 -e RABBITMQ_ERLANG_COOKIE='rabbitmq_cookie' rabbitmq:3.9-management [root@bogon ~]# docker run -d --hostname rabbit3 --name rabbitmq3 -p 5674:5672 --link rabbitmq1:rabbit1 --link rabbitmq2:rabbit2 -e RABBITMQ_ERLANG_COOKIE='rabbitmq_cookie' rabbitmq:3.9-management
添加节点
#节点1 [root@bogon ~]# docker exec -it rabbitmq1 bash root@rabbit1:/# rabbitmqctl stop_app RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead. Stopping rabbit application on node rabbit@rabbit1 ... root@rabbit1:/# rabbitmqctl reset RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead. Resetting node rabbit@rabbit1 ... root@rabbit1:/# rabbitmqctl start_app RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead. Starting node rabbit@rabbit1 ... root@rabbit1:/#
#节点2 [root@bogon ~]# docker exec -it rabbitmq2 bash root@rabbit2:/# rabbitmqctl stop_app RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead. Stopping rabbit application on node rabbit@rabbit2 ... root@rabbit2:/# rabbitmqctl reset RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead. Resetting node rabbit@rabbit2 ... root@rabbit2:/# rabbitmqctl join_cluster --ram rabbit@rabbit1 root@rabbit2:/# rabbitmqctl start_app
#节点3 [root@bogon ~]# docker exec -it rabbitmq3 bash root@rabbit3:/# rabbitmqctl stop_app RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead. Stopping rabbit application on node rabbit@rabbit3 ... root@rabbit3:/# rabbitmqctl reset RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead. Resetting node rabbit@rabbit3 ... root@rabbit3:/# rabbitmqctl join_cluster --ram rabbit@rabbit1 RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead. Clustering node rabbit@rabbit3 with rabbit@rabbit1 13:45:31.790 [warn] Feature flags: the previous instance of this node must have failed to write the `feature_flags` file at `/var/lib/rabbitmq/mnesia/rabbit@rabbit3-feature_flags`: 13:45:31.790 [warn] Feature flags: - list of previously disabled feature flags now marked as such: [:maintenance_mode_status] 13:45:32.000 [error] Failed to create a tracked connection table for node :rabbit@rabbit3: {:node_not_running, :rabbit@rabbit3} 13:45:32.001 [error] Failed to create a per-vhost tracked connection table for node :rabbit@rabbit3: {:node_not_running, :rabbit@rabbit3} 13:45:32.001 [error] Failed to create a per-user tracked connection table for node :rabbit@rabbit3: {:node_not_running, :rabbit@rabbit3} root@rabbit3:/# rabbitmqctl start_app RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead. Starting node rabbit@rabbit3 ...
此时安装完成的为普通集群模式
Exchange 的元数据信息在所有节点上是一致的,而 Queue(存放消息的队列)的完整数据则只会存在于创建它的那个节点上。其他节点只知道这个 queue 的 metadata 信息和一个指向 queue 的 owner node 的指针;
RabbitMQ 集群会始终同步四种类型的内部元数据(类似索引):
队列元数据:队列名称和它的属性;
交换器元数据:交换器名称、类型和属性;
绑定元数据:一张简单的表格展示了如何将消息路由到队列;
vhost元数据:为 vhost 内的队列、交换器和绑定提供命名空间和安全属性;因此,当用户访问其中任何一个 RabbitMQ 节点时,通过 rabbitmqctl 查询到的元数据信息都是相同的。
无法实现高可用性,当创建 queue 的节点故障后,其他节点是无法取到消息实体的。如果做了消息持久化,那么得等创建 queue 的节点恢复后,才可以被消费。如果没有持久化的话,就会产生消息丢失的现象。
配置镜像集群模式
概念:
把队列做成镜像队列,让各队列存在于多个节点中,属于 RabbitMQ 的高可用性方案。镜像模式和普通模式的不同在于,queue和 message 会在集群各节点之间同步,而不是在 consumer 获取数据时临时拉取。
特点:
(1)实现了高可用性。部分节点挂掉后,不会影响 rabbitmq 的使用。
(2)降低了系统性能。镜像队列数量过多,大量的消息同步也会加大网络带宽开销。
(3)适合对可用性要求较高的业务场景。
name:随便取,策略名称
Pattern:^ 匹配符,只有一个^代表匹配所有
Definition:ha-mode=all 为匹配类型,分为3种模式:all(表示所有的queue)
或者使用命令:
#rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
添加一个队列
可见队列已经同步到其他节点上。