在生产环境中由于一些不明原因,导致rabbitmq重启,在RabbitMQ重启期间生产者消息投递失败,导致消息丢失,需要手动处理和恢复。于是,我们开始思考,如何才能进行RabbitMQ的消息可靠投递呢?特别是在这样比较极端的情况,RabbitMQ集群不可用的时候,无法投递的消息该如何处理呢:
确保生产者与交换机的消息不丢失
在配置文件当中需要添加
spring.rabbitmq.publisher-confirm-type=
NONE
禁用发布确认模式,是默认值
CORRELATED
发布消息成功或失败到交换器后会触发回调方法
SIMPLE 性能差
经测试有两种效果,其一效果和CORRELATED值一样会触发回调方法,
其二在发布消息成功后使用rabbitTemplate调用waitForConfirms或waitForConfirmsOrDie方法 等待broker节点返回发送结果,根据返回结果来判定下一步的逻辑,要注意的点是 waitForConfirmsOrDie方法如果返回false则会关闭channel,则接下来无法发送消息到broker
配置文件
spring.rabbitmq.host=192.168.6.100
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=123
spring.rabbitmq.publisher-confirm-type=correlated
#队列发布确认 失败会回调
#spring.rabbitmq.publisher-returns=true
负责接收回调的配置类
package com.lzq.config;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Slf4j
@Configuration
public class ConfirmConfig implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback {
@Autowired
private RabbitTemplate rabbitTemplate;
//设置当前类实现到RabbitTemplate中
@PostConstruct //后置处理
public void last(){
rabbitTemplate.setConfirmCallback(this);
rabbitTemplate.setReturnCallback(this);
}
//交换机回调
@Override
public void confirm(CorrelationData correlationData, boolean ack, String s) {
System.out.println("交换机回调");
if (ack){
//成功
log.info("应答成功,原因{},回调信息{}",s, JSONObject.toJSON(correlationData));
}else {
log.error("应答失败,原因{},回调信息{}",s, JSONObject.toJSON(correlationData));
}
}
//队列回调
@Override
public void returnedMessage(Message message, int i, String s, String s1, String s2) {
log.error("接收到的消息是:{}",new String(message.getBody()));
log.error("状态码",i);
log.error("原因",s);
log.error("交换机{}",s1);
log.error("RoutingKey:{}",s2);
}
}
将实现类注入到RabbitTemplate中
RabbitMQ集群
先将原来的虚拟机在克隆2份
克隆时出错: 打不开此虚拟磁盘的父磁盘
重启一下虚拟机就好了
1.修改3台机器的主机名称
sudo vi /etc/hostname 若文件为只读
vi /etc/hostnamereboot 重启
2.配置各个节点的 hosts 文件,让各个节点都能互相识别对方
查看ip ip addr
因为之前设置的固定ip地址所以ip都一样,需要改一下
设置固定ip 此处不需要配置
打开VMware--编辑--虚拟网络编辑器--VMnet8--修改子网ip--修改NAT设置-确定
打开终端输入
vim /etc/sysconfig/network-scripts/ifcfg-ens33
修改里面文件
TYPE="Ethernet"
PROXY_METHOD="none"
BROWSER_ONLY="no"
BOOTPROTO="static"
DEFROUTE="yes"
IPV4_FAILURE_FATAL="no"
IPV6INIT="yes"
IPV6_AUTOCONF="yes"
IPV6_DEFROUTE="yes"
IPV6_FAILURE_FATAL="no"
IPV6_ADDR_GEN_MODE="stable-privacy"
NAME="ens33"
UUID="272285bb-12dd-4ef2-86ec-f0c04148a9e3"
DEVICE="ens33"
ONBOOT="yes"
#ip
IPADDR=192.168.6.100
#wg
GATEWAY=192.168.6.2
#YM
DNS1=192.168.6.2修改后重启网络
systemctl restart network
编辑3台服务的ip让互相可以访问到,确保各个节点的cookie文件使用的是同一个值
ip addr 先查看对应的ip
vim /etc/hosts
192.168.122.1 lzq
192.168.122.1 lzq2
192.168.122.1 lzq3
在1号机上出入命令
scp /var/lib/rabbitmq/.erlang.cookie root@lzq2:/var/lib/rabbitmq/.erlang.cookie
scp /var/lib/rabbitmq/.erlang.cookie root@lzq3:/var/lib/rabbitmq/.erlang.cookie
若没有权限同样加入sudo 然后按提示输入密码
启动RabbitMQ服务,顺带启动Erlang虚拟机和RbbitMQ应用服务(在三台节点上分别执行以下命令)
rabbitmq-server -detached
因为之前设置过自动启动,所以不用输入,输入会报错
此时执行以下命令,关机重置一下,并让2号机连接1号机以此类推,3号连2号
rabbitmqctl stop_app
(rabbitmqctl stop会将Erlang虚拟机关闭,rabbitmqctl stop_app只关闭RabbitMQ服务)
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@lzq
rabbitmqctl start_app(只启动应用服务)
查看集群状态
rabbitmqctl cluster_status
因为重置了还需要重新设置账号密码分配权限
创建账号
rabbitmqctl add_user admin 123
设置用户角色
rabbitmqctl set_user_tags admin administrator
设置用户权限
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
解除集群节点(node2和node3机器分别执行)
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
rabbitmqctl cluster_status
rabbitmqctl forget_cluster_node rabbit@node2(node1机器上执行)
HAProxy高可用代理
//下载依赖包
yum install gcc vim wget
//上传haproxy源码包; -C解压到指定的目录
tar -zxvf haproxy-1.6.5.tar.gz -C /usr/local
//进入目录、进行编译、安装
cd /usr/local/haproxy-1.6.5
// make 表示编译;TARGET=linux31 表示CentOS7系统;PREFIX=/usr/local/haproxy指定安装路径
// TARGET=linux310,内核版本,使用uname -r查看内核,如:3.10.0-514.el7,此时该参数就为linux310;
make TARGET=linux310 PREFIX=/usr/local/haproxy
make install PREFIX=/usr/local/haproxy
mkdir /etc/haproxy
//添加用户组:-r 创建一个系统组;-g 组ID
groupadd -r -g 149 haproxy
//添加用户:-g 新账户组的名称;-r 创建一个系统用户;-s 新用户的登录shell; -u 新账户的用户ID
useradd -g haproxy -r -s /sbin/nologin -u 149 haproxy
//创建haproxy配置文件
vim /etc/haproxy/haproxy.cfg
配置HAProxy
#全局配置
global
#日志输出配置,所有日志都记录在本机,通过local0输出
log 127.0.0.1 local0 info
#最大连接数
maxconn 5120
#改变当前的工作目录
chroot /usr/local/haproxy
#以指定的UID运行haproxy进程
uid 99
#以指定的GID运行haproxy进程
gid 99
#以守护进程方式运行haproxy
daemon
quiet
nbproc 20
#当前进程PID文件
pidfile /var/run/haproxy.pid
#默认配置
defaults
#应用全局的日志配置
log global
#默认的模式mode{tcp|http|health}
mode tcp
#日志类别
option tcplog
#不记录检查检查日志信息
option dontlognull
#3次失败则认为服务不可用
retries 3
option redispatch
#每个进程可用的最大连接数
maxconn 2000
#连接超时
contimeout 5s
#客户端超时
clitimeout 60s
#服务端超时
srvtimeout 15s
#绑定配置
listen rabbitmq_cluster
bind *:5677
#配置TCP模式
mode tcp
#balance url_param userid
#balance url_param session_id check_post 64
#balance hdr(User-Agent)
#balance hdr(host)
#balance hdr(Host) use_domain_only
#balance rdp-cookie
#balance leastconn
#balance source //ip
#简单的轮询
balance roundrobin
#server rabbit1 定义服务内部标识,
#127.0.0.1:5672 服务连接IP和端口,
#check inter 5000 定义每隔多少毫秒检查服务是否可用,
#rise 2 服务故障后需要多少次检查才能被再次确认可用,
#fall 2 经历多次失败的检查检查后,haproxy才会停止使用此服务
#weight 1 定义服务权重
server rabbit1 192.168.137.118:5672 check inter 5000 rise 2 fall 2 weight 1
server rabbit2 192.168.137.118:5673 check inter 5000 rise 2 fall 2 weight 1
server rabbit3 192.168.137.118:5674 check inter 5000 rise 2 fall 2 weight 1
#haproxy监控页面地址
listen stats
bind 192.168.137.118:8100
mode http
option httplog
stats enable
stats uri /rabbitmq-stats
stats refresh 5s
启动HAproxy负载
/usr/local/haproxy/sbin/haproxy -f /etc/haproxy/haproxy.cfg
//查看haproxy进程状态
ps -ef | grep haproxy
访问如下地址对mq节点进行监控
http://192.168.137.118:8100/rabbitmq-stats
springboot yml文件中访问mq集群地址:
spring:
rabbitmq:
host: 192.168.137.118
port: 5677
username: admin
password: 123456
virtual-host: /
#addresses: 192.168.137.118:5672,192.168.137.118:5673,192.168.137.118:5674