RabbitMQ入门(二)

RabbitMQ介绍

RabbitMQ是一个开源的消息代理和队列服务,用来通过普通协议在完全不同的应用之间共享数据,RabbitMQ是使用Erlang来开发的,并且RabbitMQ是基于AMQP协议的。RabbitMQ是部署最广泛的开源消息队列代理(Message Broker)。

什么是消息代理?其实就是一个中间软件模块,把消息从一个软件服务传递到另外一个软件服务上去。

为什么要这个消息代理?消息代理的主要作用是实现软件解耦,最大限度的减少程序之间的相互依赖,提高系统可用性以及可扩展性,同时还增加了消息的可靠传输和事务管理功能。

  • 角色:
生产者:生产消息的程序就是一个生产者(producer)

队列:RabbitMQ中保存消息的位置就是队列,队列会把消息发送给消费者

消费者:一个消费者(consumer)就是一个等待获取消息的程序
  • 核心概念:
Server:又称Broker,接收客户端的连接,实现AMQP实体服务

Connection:连接,应用程序与Server的网络连接

Channel:网络通道,几乎所有的操作都在Channel中进行,Channel是进行消息读写的通道。
         客户端可建立多个Channel,每个Channel代表一个会话任务
        
Message:消息,Server与应用程序之间传送的数据,由Properties和Body组成。Properties
         可以对消息进行修饰,比如消息的优先级、延迟等高级特性;Body则是消息体内容
        
Virtual Host:虚拟主机,用于进行逻辑隔离,最上层的消息路由。一个Virtual Host里面可以
              有若干个Exchange和Queue,同一个Virtual Host里面不能有相同名称的Exchange或Queue
        
Exchange:交换机,接收消息,根据routing key转发消息到绑定的Queue

Binding:Exchange和Queue之间的虚拟连接,binding中可以包含routing key

Routing key:一个路由规则,Exchange可用它来确定如何路由一个特定消息

Queue:也称为Message Queue,消息队列,保存消息并将它们转发给消费者
  • 工作模式:

在这里插入图片描述

1. 简单模式
    
这是一个最简单的生产者和消费者的队列,生产者把消息放入队列,消费者获得消息。这个模式只有一个消费者和一个生产者,
当然一个队列就够了,这种模式只需要配置虚拟主机参数即可,其他参数默认就可以通信。
2. work模式

这种模式出现了两个消费者,为了保证消费者之间的负载均衡和同步,需要在消息队列之间加上同步功能。工作队列(又名任务队列)
背后的主要思想是避免立即执行资源密集型任务,必须等待它完成。相反,我们计划稍后完成任务。我们将任务封装为消息并将其发送
到队列中,后台运行的一个工作进程将弹出任务并最终执行该任务。当你运行许多工人(消费者)时,任务将在他们之间分担。
3. 订阅模式

实际上前两种模式也使用了交换机,只是我们没有设置,使用了默认的参数。交换机参数是可以配置的,
如果消息配置的交换机参数和MQserver队列绑定(bind)的交换机名称相同则转发,否则丢弃。
4. 路由模式

交换机要配置为direct类型,转发的规则变为检查队列的routing key的值,如果routing key值相同则转发,否则丢弃。
5. topic模式

这种模式下交换机要配置为topic类型,routing key配置失效。发送到一个话题交换机(topic exchange)信息,不能是任意routing key,
它必须是一个单词的列表,用逗号分隔,这些词可以是任何东西,但通常它们指定连接到消息的某些特性。一些有效的路由键的例子:stock.usd.nyse、
nyse.vmw、"quick.orange.rabbit",它更有特点是是可以模糊匹配,匹配规则如下:*可以代替一个词;#可以代替零个或更多的单词。
6. RPC模式

这种模式主要使用在远程调用的场景下。一个应用程序需要另外一个应用程序来最终返回运行结果,这个过程可能是比较耗时的操作,
使用这种模式是最合适的。

一般情况下,使用更多的是前面5种工作模式。


RabbitMQ集群

RabbitMQ模式可分为三种:单一模式、普通模式、镜像模式

* 单一模式:即单机,不做集群,单独运行一个RabbitMQ而已。

* 普通模式:默认模式,以两个节点为例来进行说明。对于Queue来说,消息实体只存在于其中一个节点A(或者B),A和B两个节点仅有相同的元数据,即队列的结构。
           当消息进入A节点的Queue后,consumer从B节点消费时,RabbitMQ会临时在A、B间进行消息传输,把A中的消息实体取出并经过B发送给consumer。所以
           consumer应尽量连接每一个节点,从中取消息,即对于同一个逻辑队列,要在多个节点建立物理Queue。否则无论consumer连A或B,出口总在A,会产生瓶颈。
           当A节点故障后,B节点无法取到A节点中还未消费的消息实体。如果做了消息持久化,那么得等A节点恢复,然后才可被消费;如果没有持久化的话,就会产生
           消息丢失的现象。

* 镜像模式:把需要的队列做成镜像队列,存在与多个节点属于RabbitMQ的HA方案。该模式解决了普通模式中的问题,其实质和普通模式不同之处在于,消息实体会主动
           在镜像节点间同步,而不是在客户端取数据时临时拉取。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,
           集群内部的网络带宽将会被这种同步通讯大大消耗掉。所以在对可靠性要求较高的场合中适用。

RabbitMQ本身是基于Erlang编写的,Erlang天生支持分布式(通过同步Erlang集群各节点的cookie来实现),因此不需要像Kafka那样通过ZooKeeper来实现分布式集群。

  • 元数据:

RabbitMQ内部有各种基础构件,包括队列、交换器、绑定、虚拟主机等,他们组成了AMQP协议消息通信的基础,而这些构件以元数据的形式存在。

  • 内存节点与磁盘节点:

在集群中的每个节点,要么是内存节点,要么是磁盘节点。如果是内存节点,会将所有的元数据信息仅存储到内存中,而磁盘节点则不仅会将所有元数据存储到内存上, 还会将其持久化到磁盘。

在单节点RabbitMQ的时候,仅允许该节点是磁盘节点。一个集群至少有一个磁盘节点,在搭建集群的时候,为了保证数据的安全性和性能,最好是两种节点都要有。

规划
主机名IP节点类型
test1192.168.30.128磁盘节点
test2192.168.30.129内存节点
test3192.168.30.130内存节点
部署集群
  • 全部配置hostname和hosts:
hostnamectl set-hostname test1

hostnamectl set-hostname test2

hostnamectl set-hostname test2
vim /etc/hosts

192.168.30.128 test1
192.168.30.129 test2
192.168.30.130 test3
  • 全部关闭selinux和firewalld:
setenforce 0

sed -i 's/=enforcing/=disabled/g' /etc/selinux/config

systemctl stop firewalld && systemctl disable firewalld
  • 全部安装rabbitmq:
curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bash

yum install -y erlang

rpm --import https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey

rpm --import https://packagecloud.io/gpg.key

rpm --import https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc

vim /etc/yum.repos.d/rabbitmq.repo               #内容如下

[bintray-rabbitmq-server]
name=bintray-rabbitmq-rpm
baseurl=https://dl.bintray.com/rabbitmq/rpm/rabbitmq-server/v3.7.x/el/7/
gpgcheck=0
repo_gpgcheck=0
enabled=1

yum install -y rabbitmq-server
  • 全部启动rabbitmq:
systemctl enable rabbitmq-server && systemctl start rabbitmq-server
  • 全部安装management插件:
rabbitmq-plugins enable rabbitmq_management
  • 同步erlang cookie:
find / -name *.cookie
/var/lib/rabbitmq/.erlang.cookie

scp /var/lib/rabbitmq/.erlang.cookie test2:/var/lib/rabbitmq/.erlang.cookie

scp /var/lib/rabbitmq/.erlang.cookie test3:/var/lib/rabbitmq/.erlang.cookie

cat /var/lib/rabbitmq/.erlang.cookie                #查看是否一致
  • 分配节点,加入集群:

将test1作为磁盘节点,test2和test3作为内存节点。

test2和test3停止rabbitmq:

systemctl restart rabbitmq-server

rabbitmqctl stop_app

test2和test3作为内存节点加入集群:

rabbitmqctl join_cluster --ram rabbit@test1                 #不加 --ram 表示以磁盘节点加入集群

test2和test3启动rabbitmq:

rabbitmqctl start_app
  • 查看集群状态:
rabbitmqctl cluster_status

Cluster status of node rabbit@test1 ...
[{nodes,[{disc,[rabbit@test1]},{ram,[rabbit@test3,rabbit@test2]}]},
 {running_nodes,[rabbit@test3,rabbit@test2,rabbit@test1]},
 {cluster_name,<<"rabbit@test1">>},
 {partitions,[]},
 {alarms,[{rabbit@test3,[]},{rabbit@test2,[]},{rabbit@test1,[]}]}]

到web管理控制台查看

在这里插入图片描述

可以看到,三台机器成功形成集群,其中test1是磁盘节点,test2和test3是内存节点。

  • 设置镜像模式:

任选一台节点上执行:

rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'

将所有队列设置为镜像队列,即队列会被复制到各个节点,各个节点状态一致。

参数含义

rabbitmqctl set_policy [-p Vhost] Name Pattern Definition [Priority]

-p Vhost: 可选参数,针对指定vhost下的queue进行设置
Name: policy的名称
Pattern: queue的匹配模式(正则表达式)
Definition: 镜像定义,包括三个部分ha-mode, ha-params, ha-sync-mode
    ha-mode: 指明镜像队列的模式,有效值为 all/exactly/nodes
        all: 表示在集群中所有的节点上进行镜像
        exactly: 表示在指定个数的节点上进行镜像,节点的个数由ha-params指定
        nodes: 表示在指定的节点上进行镜像,节点名称通过ha-params指定
    ha-params: ha-mode模式需要用到的参数
    ha-sync-mode: 进行队列中消息的同步方式,有效值为automatic和manual
priority: 可选参数,policy的优先级

换其他节点上查看:

rabbitmqctl list_policies

Listing policies for vhost "/" ...
vhost	name	pattern	apply-to	definition	priority
/	ha-all	^	all	{"ha-mode":"all"}	0

在这里插入图片描述

此时镜像模式就设置完成了,可以在任意节点上创建队列,看看其他两个节点是否会同步。

在这里插入图片描述

随意创建队列,发现会自动同步到其它节点。

集群操作
  • 查看集群状态:
rabbitmqctl cluster_status
  • 加入集群:

假设集群名是rabbit@test1,在要加入的节点上执行

rabbitmqctl join_cluster --ram rabbit@test1                 #不加 --ram 表示以磁盘节点加入集群
  • 移除集群节点:

假设要移除的集群节点是rabbit@test2

rabbitmqctl forget_cluster rabbit@test2(具体节点)
  • 修改集群名(默认是master节点名):
rabbitmqctl set_cluster_name rabbitmq_cluster1

高可用负载均衡集群

但是还有一个问题,虽然已经搭建了集群,但是我们只能用两个内存节点提供服务。因此需要做一个负载均衡器,我们可以使用Nginx的tcp代理功能或者使用haproxy。除此之外,还可以加入keepalived做高可用。

规划
主机名IP节点类型
test1192.168.30.128磁盘节点
test2192.168.30.129内存节点
test3192.168.30.130内存节点
test4192.168.30.131haproxy/keepalived(主)
test5192.168.30.132haproxy/keepalived(备)
安装haproxy
  • 安装haproxy(test4/test5):
yum install -y gcc

yum install -y haproxy
  • 配置haproxy(test4/test5):
vim /etc/haproxy/haproxy.cfg
#logging options
global
    log 127.0.0.1 local0 info
    maxconn 5120
    chroot /var/lib/haproxy
    uid 99
    gid 99
    daemon
    quiet
    nbproc 20
    pidfile /var/run/haproxy.pid
    
defaults
    log global
    # 使用四层代理模式,"mode http" 为七层代理模式
    mode tcp
    # if you set mode to tcp,then you must change tcplog into httplog
    option tcplog
    option dontlognull
    retries 3
    option redispatch
    maxconn 2000
    contimeout 5s
    # 客户端空闲超时时间为60秒,过了该时间,HA发起重连机制
    clitimeout 60s
    # 服务端连接超时时间为15秒,过了该时间,HA发起重连机制
    srvtimeout 15s

listen rabbitmq_cluster
    # 定义监听地址和端口,本机的5672端口
    bind 0.0.0.0:5672
    # 配置 tcp 模式
    mode tcp
    # balance url_param userid
    # balance url_param session_id check_post 64
    # 简单的轮询
    balance roundrobin
    #rabbitmq集群节点配置 #inter 每隔五秒对mq集群做健康检查,2次正确证明服务器可用,
    #2次失败证明服务器不可用,并且配置主备机制
    server test1 192.168.30.128:5672 check inter 5000 rise 2 fall 2
    server test2 192.168.30.129:5672 check inter 5000 rise 2 fall 2
    server test3 192.168.30.130:5672 check inter 5000 rise 2 fall 2
        
# 配置 haproxy web 监控,查看统计信息
listen stats
    bind *:8100
    mode http
    option httplog
    stats enable
    # 设置 haproxy 监控地址为:http://localhost:8100/rabbitmq-stats
    stats uri /rabbitmq-stats
    stats refresh 5s
  • 启动haproxy(test4/test5):
systemctl enable haproxy                #开机启动haproxy

systemctl start haproxy

或

haproxy -f /etc/haproxy/haproxy.cfg

至此,haproxy配置成功,访问http://ip:8100/rabbitmq-stats,可以看到:

在这里插入图片描述

在使用haproxy做负载均衡后,客户端连接haproxy的IP地址即可,而不是连接rabbitmq的IP地址。

安装keepalived

利用keepalived做主备,避免单点问题,实现高可用。

  • 下载keepalived(test4/test5):
yum install -y keepalived
  • 配置keepalived(test4/test5):
vim /etc/keepalived/keepalived.conf

test4的配置如下:

! Configuration File for keepalived

global defs {
    router_id test4     ##标识节点的字符串,通常为hostname
}

vrrp_script chk_haproxy {
    script "/etc/keepalived/haproxy_check.sh"   ##执行脚本位置
    interval 2      ##检查时间间隔
    weight -20      ##如果条件成立则权重减20
}

vrrp_instance VI_1 {
    state MASTER    ##主节点为MASTER,备份节点为BACKUP
    interface ens33     ##绑定虚拟ip的网络接口(网卡)
    virtual_router_id 13    ##虚拟路由id号,主备节点相同
    mcast_src_ip 192.168.30.131     ##本机ip地址
    priority 100    ##优先级(0-254)
    nopreempt
    advert_int 1    ##组播信息发送间隔,两个节点必须一致,默认1s
    authentication {    ##认证匹配
        auth_type PASS
        auth_pass lzxlinux      ##自定义密码,主备相同即可
    }
    track_script {
        chk_haproxy
    }
    virtual_ipaddress {
        192.168.30.150      ##VIP地址,可以指定多个
    }
}

test5的配置如下:

! Configuration File for keepalived

global defs {
    router_id test5     ##标识节点的字符串,通常为hostname
}

vrrp_script chk_haproxy {
    script "/etc/keepalived/haproxy_check.sh"   ##执行脚本位置
    interval 2      ##检查时间间隔
    weight -20      ##如果条件成立则权重减20
}

vrrp_instance VI_1 {
    state BACKUP    ##主节点为MASTER,备份节点为BACKUP
    interface ens33     ##绑定虚拟ip的网络接口(网卡)
    virtual_router_id 13    ##虚拟路由id号,主备节点相同
    mcast_src_ip 192.168.30.132     ##本机ip地址
    priority 90    ##优先级低于主节点即可
    nopreempt
    advert_int 1    ##组播信息发送间隔,两个节点必须一致,默认1s
    authentication {    ##认证匹配
        auth_type PASS
        auth_pass lzxlinux      ##自定义密码,主备相同即可
    }
    track_script {
        chk_haproxy
    }
    virtual_ipaddress {
        192.168.30.150      ##VIP地址,可以指定多个
    }
}
  • 添加检查脚本 haproxy_check.sh(test4/test5):
vim /etc/keepalived/haproxy_check.sh

#!/bin/bash
COUNT=`ps -C haproxy --no-header | wc -l`
if [ $COUNT -eq "0" ]
then
    systemctl start haproxy
    sleep 2
    COUNT2=`ps -C haproxy --no-header | wc -l`
    if [ $COUNT2 -eq "0" ]
    then
        systemctl stop keepalived
    fi
fi

chmod +x /etc/keepalived/haproxy_check.sh
  • 启动keepalived(test4/test5):
systemctl enable keepalived && systemctl start keepalived
测试VIP切换
  • 查看VIP:
ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:ac:b2:82 brd ff:ff:ff:ff:ff:ff
    inet 192.168.30.131/24 brd 192.168.30.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet 192.168.30.150/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::5f9b:16d3:4d21:665/64 scope link 
       valid_lft forever preferred_lft forever

VIP位于test4上,说明test4是master节点。

  • 关闭haproxy(test4/test5):
netstat -lntp |grep haproxy

tcp        0      0 0.0.0.0:8100            0.0.0.0:*               LISTEN      1506/haproxy        
tcp        0      0 0.0.0.0:5672            0.0.0.0:*               LISTEN      1506/haproxy        

systemctl stop haproxy.service 

netstat -lntp |grep haproxy

tcp        0      0 0.0.0.0:8100            0.0.0.0:*               LISTEN      1248/haproxy        
tcp        0      0 0.0.0.0:5672            0.0.0.0:*               LISTEN      1248/haproxy

可以看到,关闭haproxy之后被keepalived自动拉起来。

  • 关闭keepalived(test4):

test4关闭keepalived,模拟宕机

systemctl stop keepalived

ip addr 

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:ac:b2:82 brd ff:ff:ff:ff:ff:ff
    inet 192.168.30.131/24 brd 192.168.30.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::5f9b:16d3:4d21:665/64 scope link 
       valid_lft forever preferred_lft forever

test5上查看

ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:50:56:38:f2:6b brd ff:ff:ff:ff:ff:ff
    inet 192.168.30.132/24 brd 192.168.30.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet 192.168.30.150/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::cb8e:2b86:790c:1fdb/64 scope link 
       valid_lft forever preferred_lft forever
    inet6 fe80::5f9b:16d3:4d21:665/64 scope link tentative dadfailed 
       valid_lft forever preferred_lft forever

可以看到,此时VIP在test5上,test5变成master节点。

  • 启动keepalived(test4):

test4重启keepalived,模拟服务恢复

systemctl start keepalived

ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:ac:b2:82 brd ff:ff:ff:ff:ff:ff
    inet 192.168.30.131/24 brd 192.168.30.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet 192.168.30.150/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::5f9b:16d3:4d21:665/64 scope link 
       valid_lft forever preferred_lft forever

可以看到,VIP又回到了test4,这是因为test4的优先级大于test5,只有在test4宕掉服务时test5才会成为master节点。

至此,基于Keepalived和Haproxy的rabbitmq集群搭建完成,高可用、负载均衡都没有问题。


更多参考资料:

RabbitMQ集群原理与部署

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值