文章目录
RabbitMQ简介
RabbitMQ是目前非常热门的一款消息中间件,常见的还有Kafka,ActivieMQ,RocketMQ等,不管互联网行业还是传统行业消息中间件都是很常用的技术,RabbitMQ凭借其高可靠,易扩展,高可用以及丰富的功能特性收到越来越多企业的青睐,RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而群集和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。
RabbitMQ作用
解耦,异步,消峰,这几乎是所有消息中间件都具备的能力.
- 解耦
在项目启动之初来预测将来会碰到什么需求是极其困难的,消息中间件在处理过程中间插入了一个隐含的,基于数据的接口层,两边的处理过程都要实现这一接口,这允许你独立的扩展或者修改两边的处理过程,只要确保他们遵守同样的接口约束即可. - 异步
在很多时候应用不想也不需要立刻处理消息,消息中间件提供了异步处理机制,允许应用把一些消息放入消息中间件中,但并不立即处理它,在之后需要的时候再慢慢处理. - 消峰
在访问量剧增的情况下,应用仍然需要继续发挥作用牡丹石这样的突发流量并不常见,如果以能处理这类峰值为标准而去投入资源,无疑是巨大的浪费,使用消息中间件能够使关键组件至诚突发访问压力,不会因为突发的超负荷请求而造成完全崩溃. - 顺序保证
在大多数使用场景下,数据处理的顺序很重要,大部分消息中间件支持一定程度上的顺序性 - 可恢复性
当系统一部分组件失效时,不会影响到整个系统,消息中间件降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入消息中间件中的消息仍然可以再系统恢复后进行处理. - 缓冲
在任何重要的系统中,都会存在需要不同处理时间的元素,消息中间件通过一个缓冲层来帮助任务最高效率的执行,写入消息中间件的处理会尽可能快速,该缓冲层有助于控制和优化数据流经过系统的速度. - 拓展性
因为消息中间件解耦了应用的处理过程,所以提高消息入队和处理的效率是很容易的,只要另外增加处理过程即可,不需要改变代码,也不需要调节参数 - 冗余(存储)
有些情况下,处理数据的过程会失败,消息中间件可以把数据进行持久化直到他们已经被完全处理,通过这一方是规避了数据丢失的风险,在把一个消息从消息中间件中删除之前,需要你的处理系统明确指出该消息已经被处理完成,从而确保你的数据被安全的保存直到使用完毕.
RabbitMQ压缩包方式安装(高可用集群)
-
安装Erlang环境
yum install libtool libtool-ltdl-devel gcc-c++ erlang-doc erlang-jinterface // 安装依赖文件
yum install gcc glibc-devel make ncurses-devel openssl-devel xmlto // 安装依赖文件
wget -c http://erlang.org/download/otp_src_20.3.tar.gz // 安装erlang
tar -zxvf otp_src_20.3.tar.gz // 解压
cd otp_src_20.3/
./configure --enable-shared --prefix=/usr/local/erlang // 编译安装 ,编译后放在/usr/local/erlang目录里面
make && make install //make
cd /usr/local/erlang/bin/
./erl //运行 -
配置环境变量
vi /etc/profile
加入内容:
export PATH=$PATH:/usr/local/erlang/bin
source /etc/profile -
安装RabbitMQ(重点:erlang版本和rabbitmq版本遵循官网所述)
cd /usr/local/
wget -c http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.15/rabbitmq-server-generic-unix-3.6.15.tar.xz
xz -d rabbitmq-server-generic-unix-3.6.15.tar.xz
tar -xvf rabbitmq-server-generic-unix-3.6.15.tar
配置rabbitmq的环境变量
vi /etc/profile
export PATH=$PATH:/usr/local/rabbitmq_server-3.6.15/sbin
source /etc/profile
进入sbin目录
./rabbitmq-server -detached #守护进程启动
./rabbitmq-server #普通启动
./rabbitmq-plugins enable rabbitmq_management #开启web插件,也就是那个管理后台 -
开启远程访问和授权(集群节点变化时需要重新设置,而且防火墙需要打开对应端口)
添加用户: ./rabbitmqctl add_user rabbitmq 123456 //rabbitmq 是用户名, 123456是用户密码
添加权限: ./rabbitmqctl set_permissions -p “/” rabbitmq “." ".” “.*”
修改用户角色: ./rabbitmqctl set_user_tags rabbitmq administrator -
运行
./rabbitmq-server -detached #守护进程启动
./rabbitmq-server #普通启动
./rabbitmqctl stop #关闭节点和应用
./rabbitmqctl stop_app #关闭应用
./rabbitmqctl start_app #开启应用
./rabbitmqctl status #查看状态
./rabbitmqctl cluster_status #查看集群状态
./rabbitmqctl join_cluster --ram rabbit@主节点名 #以内存节点的方式加入集群,–disc是磁盘节点 -
HAProxy + Keepalived 高可用方案(RabbitMQ不依靠federation或者shovel插件的话只支持局域网同网段部署,不支持广域网)
6.1 配置hosts然后重启
进入你要使用的服务器,编辑/etc/hosts文件,在文件中加入以下配置:
规则: 你的服务器ip:有意义的别名
例如我这里有三台服务器,一个磁盘节点,两个内存节点:
192.168.2.80 rabbitmq1
192.168.2.81 rabbitmq2
192.168.2.82 rabbitmq3
6.2 拷贝.erlang.cookie
Cookie是保证不同节点可以互相通信的秘钥,要保证集群中的不同节点互相通信必须共享相同的Erlang Cookie
解压包安装方式下,cookie在用户目录下,是个隐藏文件,我这里是root账户,所以这个cookie就在这里/root
,必须要将所有节点的cookie文件同步,并且权限为400
如果是yum安装的,那cookie保存在/var/lib/rabbitmq下
6.3 加节点入集群(主机名和hosts对应,免得采坑)
大家都知道list,对于rabbitmq来说,它本身就是一个list,而这个list中只有自己一个元素,如果想组建成集群,那就需要把别的节点也加入进来.具体步骤如下:-
首先启动自己选中的主节点服务节点,我这里是192.168.2.80
rabbitmq-server -detached #守护进程方式启动 -
将其他两个节点加入到主节点的集群中加入集群也有两种方式(两个节点都执行以下命令)
首先启动这两个节点服务器
rabbitmq-server -detached
然后关闭应用
rabbitmqctl stop_app
以内存节点的方式加入
rabbitmqctl join_cluster --ram rabbit@rabbitmq1
以磁盘节点的方式加入
rabbitmqctl join_cluster --disc rabbit@rabbitmq1
最后启动应用
rabbitmqctl start_app -
在主节点查看集群状态
rabbitmqctl cluster_status #查看集群状态
-
新增管理账户,之前的账户会被重置,那个节点执行都可以,会自动同步
添加用户: ./rabbitmqctl add_user rabbitmq 123456 //rabbitmq 是用户名, 123456是用户密码
添加权限: ./rabbitmqctl set_permissions -p “/” rabbitmq “." ".” “.*”
修改用户角色: ./rabbitmqctl set_user_tags rabbitmq administrator -
设置镜像队列策略
rabbitmqctl set_policy ha-all “^” ‘{“ha-mode”:“all”}’
命令解释:
rabbitmqctl set_policy -p 虚拟机名 ha-all “^” ‘{“ha-mode”:“all”}’
给虚拟机创建一个策略,策略名称为ha-all,策略模式为all,即复制到所有节点,包含新增节点,策略表达式为"^",表示所有匹配所有队列名称.
查看策略:rabbitmqctl list_policies -p /
清除策略:rabbitmqctl clear_policy -p / ha-all -
设置HAproxy
-
设置Keepalived
一、HAProxy
将5672端口映射为5673端口,15672端口映射为15673端口。
-
1)在两个内存节点上安装HAProxy
yum install haproxy
2)编辑配置文件
vim /etc/haproxy/haproxy.cfg
内容修改为:
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
stats socket /var/lib/haproxy/stats
defaults
log global
option dontlognull
option redispatch
retries 3
timeout connect 10s
timeout client 1m
timeout server 1m
maxconn 3000
listen http_front
mode http
bind 0.0.0.0:1080 #监听端口
stats refresh 30s #统计页面自动刷新时间
stats uri /haproxy?stats #统计页面url
stats realm Haproxy Manager #统计页面密码框上提示文本
stats auth admin:123456 #统计页面用户名和密码设置
listen rabbitmq_admin
bind 0.0.0.0:15673
server node1 192.168.8.40:15672
server node2 192.168.8.45:15672
listen rabbitmq_cluster 0.0.0.0:5673
mode tcp
balance roundrobin
timeout client 3h
timeout server 3h
timeout connect 3h
server node1 192.168.8.40:5672 check inter 5s rise 2 fall 3
server node2 192.168.8.45:5672 check inter 5s rise 2 fall 3
3)启动HAProxy
haproxy -f /etc/haproxy/haproxy.cfg
二、在两个内存节点上安装Keepalived
VIP 为 192.168.8.201
1)安装Keepalived
yum -y install keepalived
2)修改配置文件
vim /etc/keepalived/keepalived.conf
内容改成(物理网卡和当前主机IP要修改):
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
vrrp_strict # 注释掉,不然访问不到VIP
vrrp_garp_interval 0
vrrp_gna_interval 0
}
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id LVS_DEVEL
vrrp_skip_check_adv_addr
vrrp_strict # 注释掉,不然访问不到VIP
vrrp_garp_interval 0
vrrp_gna_interval 0
}
检测任务
vrrp_script check_haproxy {
# 检测HAProxy监本
script “/etc/keepalived/script/check_haproxy.sh”
# 每隔两秒检测
interval 2
# 权重
weight 2
}
虚拟组
vrrp_instance haproxy {
state MASTER # 此处为主
,备机是 BACKUP
【此处要修改】
interface ens33 # 物理网卡,根据情况而定 【此处要修改】
mcast_src_ip 192.168.8.40 # 当前主机ip 【此处要修改】
virtual_router_id 51 # 虚拟路由id,同一个组内需要相同
priority 100 # 主机的优先权要比备机高
advert_int 1 # 心跳检查频率,单位:秒
authentication { # 认证,组内的要相同
auth_type PASS
auth_pass 1111
}
# 调用脚本
track_script {
check_haproxy
}
# 虚拟ip,多个换行
virtual_ipaddress {
192.168.8.201
}
}
3)启动keepalived
keepalived -D
- zabbix监控
RabbitMQ的使用
springboot整合方式
引入pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
RabbitMQ的原理
AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。
注意点:
- 当路由key和绑定key一样时,交换机会把消息分配给对应的队列进行消费
- 当消息和队列都设置过期时间时,以最小值为准
- 消息分发分两种:轮询和公平分发
- 交换机分三种:
交换机类型 | 特性 |
---|---|
直连交换机(Direct) | 当路由key和绑定key相同是分配到指定队列,相当于1对1 |
主题交换机(Topic) | 当路由key和绑定key匹配时,分配到对应的队列,相当于1对1和1对n,匹配规则有*(一个单词)和#(零个或多个单词) |
广播交换机(Fanout) | 没有路由key和绑定key的匹配过程,消息会分配给所有的队列去消费 |
- 会进入死信交换机的消息,有三种情况:
4.1 消息过期了,如果存在死信交换机就会进入,不存在会直接删除
4.2 消息被拒收了,并且requeue为fasle时,也就是拒收还不让重新入队列的时候,再有就是不应答的时候
4.3 队列达到最大长度和最大容量等,最先入队的消息就会 进入死信交换机 - 优先级队列默认级别是5,通过priority去设置
- 延迟队列,rabbitmq本身没有这种队列,可以通过插件,也可以通过TTL和死信队列来实现延迟队列
- 生产端确认支持事务模式设置方式如下:channel.txSelect()//设置成事务模式channel.txCommit()//提交事务channel.txRollback()//回滚事务,这是针对生产者的
- 生产端支持确认模式,channel.confirmSelect()//开启确认模式channel.waitForConfirms()//是否被确认
- 指定ReturnListener,当消息无法被交换机路由到队列的时候可以通过它把消息拿回来发给另一个交换机或者做单独处理,指定备份交换机可以通过设置exchangeDeclare方法的map参数实现,参数是mandatory=true
- 交换机和队列以及消息都支持持久化
- 消费者确认保证可靠有四种方式:1.自动应答2.手动应答basicAck3.单条拒绝basicReject4.批量拒绝basicNack
- 当自动应答时消息只要发送给消费者以后就会删除,而不是等到消费者处理完再删除
- 消费者回调,补偿机制(重发),消息幂等性,消息顺序性
- 默认占用内存超过40%,磁盘剩余小于1G的时候会停止接收消息
- 消费端限流可以通过prefetch count参数去设置
RabbitMQ总结
-
消息队列的作用与使用场景?
解耦,异步,消峰,限流,广播等等 -
创建队列和交换机的方法?
创建队列channel.queueDeclare()
创建交换机channel.exchangeDeclare() -
多个消费者监听一个队列时,消息如何分发?
3.1 轮询:
举例一下,也就是按照123的顺序去分发给3个队列,然后下一轮就是456,但是这个存在缺点,当某些消息处理时长比较大时,可能会造成某些队列一直很忙,某些队列一直很闲的情况
3.2 公平分发:
设置channel.basicQos(64),也就是说说目前最多处理64条没返回ack的消息,如果返回ack了,就继续接收消费 -
无法被路由的消息,去了哪里?
4.1 如果没有任何设置, 那就直接丢弃了
4.1 如果设置了mandatory是true时,配合ReturnListener去实现一个消息的回发
4.3 如果声明了备份交换机,可以指定备份交换机去处理 -
消息在什么时候会变成Dead Letter(死信)?
消息过期了,如果存在死信交换机就会进入,不存在会直接删除
消息被拒收了,并且requeue为fasle时,也就是拒收还不让重新入队列的时候,再有就是不应答的时候
队列达到最大长度(x-max-length)和最大容量(x-max-length-bytes)等,最先入队的消息就会进入死信交换机 -
RabbitMQ如何实现延迟队列?
通过插件去实现
本身是不提供延迟队列的,可以通过TTL加死信队列的方式去实现 -
如何保证消息的可靠性投递?
7.1 生产者发送消息到服务端提供了事务和确认模式来保证可靠,一般不推荐事务,因为它是阻塞的
7.2 保证交换机正确匹配消息到队列,其实也就是3.4.5问题的解释
7.3 交换机和队列都可以进行持久化和集群模式
7.4 消费者通过手工应答ack来确认消息消费 -
如何在服务端和消费端做限流?
-
如何保证消息的顺序性?
一个队列和一个消费者的时候是有序的
多个消费者的时候可以通过全局id去做业务逻辑实现,指定messageId去做分组排序,可以再生产端设计发送一条以后等确认消费以后再发下一条,设计消费端消费完上一条id以后再消费下一个id -
RabbitMQ的集群节点类型?
DISC(磁盘节点,至少一个)和RAM(内存节点)