RabbitMQ持久化机制(二)

前面写的RabbitMQ的东西还是很简单的,百度资料一堆,看看一会就能学会,之所以写前面的文章是想让还不怎么会用RabbitMQ的朋友可以系统看下,但做为架构师关注的重点应该是RabbitMQ的持久化机制及磁盘管理,接下来要写的东西就是关于这些的;在讲下面内容前先来说一点现在的RabbitMQ的环境,目前环境是单机环境,如果消息中间件挂了这是一场灾难事件,所以高可用架构是必不可少的;

一、单一模式

 即单机情况不做集群,就单独运行一个rabbitmq而已;在上一篇幅中已经说明了安装方法;

二、普通模式

 2.1、RabbitMQ集群元数据的同步

RabbitMQ集群会始终同步四种类型的内部元数据:
1.队列元数据:队列名称、属性;
2.交换器元数据:交换器名称、类型和属性;
3.绑定元数据:交换器与队列绑定关系,如binding_key;
4.vhost元数据:虚拟主机内部配置和属性;
因此,当用户访问其中任何一个RabbitMQ节点时,通过rabbitmqctl查询到的queue/user/exchange/ vhost等信息都是相同的。

注意:队列只同步元数据信息,不会同步存储的消息,消息只会存在于创建该队列的节点上,其它节点只知道这个队列的元数据信息和一个指向队列的owner node的地址。

2.2、为何RabbitMQ集群仅采用元数据同步的方式

RabbitMQ这么设计主要是基于集群本身的性能和存储空间上来考虑。
第一,存储空间,如果每个集群节点都拥有所有Queue的完全数据拷贝,那么每个节点的存储空间会非常大,集群的消息积压能力会非常弱(无法通过集群节点的扩容提高消息积压能力);
第二,性能,消息的发布者需要将消息复制到每一个集群节点,对于持久化消息,网络和磁盘同步复制的开销都会明显增加。

2.3、RabbitMQ集群的基本原理

 

 

 

场景1、客户端直接连接队列所在节点
如果有一个消息生产者或者消息消费者通过amqp-client的客户端连接至节点1进行消息的发布或者订阅,那么此时的集群中的消息收发只与节点1相关。

场景2、客户端连接的是非队列数据所在节点
如果消息生产者所连接的是节点2或者节点3,此时队列1的完整数据不在该两个节点上,那么在发送消息过程中这两个节点主要起了一个路由转发作用,根据这两个节点上的元数据(也就是上文提到的:指向queue的owner node的指针)转发至节点1上,最终发送的消息还是会存储至节点1的队列1上。同样,如果消息消费者所连接的节点2或者节点3,那这两个节点也会作为路由节点起到转发作用,将会从节点1的队列1中拉取消息进行消费。

2.4、单机多节点集群搭建

2.4.1、启动单节点Rabbit MQ

docker run -d --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:management

2.4.2、多节点集群模式(安装 Docker Compose)

安装dnf

#CentOS 安装
#安装 epel-release 依赖:
yum install epel-release
​
#安装 DNF 包:
yum install dnf
​
----------------
#Fedora 安装:
dnf install dnf

安装python2-pip

dnf install python2-pip

安装python3-pip(一般选择python3)

dnf install python3-pip

安装docker-compose

pip3 install docker-compose

我在安装docker-compose报了错,错误当时忘记截图了现在找不到了,但我是用下面命令解决了安装错误

pip3 install --upgrade pip

查看版本

docker-compose version

2.4.3、使用 Docker Compose 启动3个 RabbitMQ 节点

vi docker-compose.yml

写入如下配置

version: "2.0"
services:
  rabbit1:
    image: rabbitmq:management
    hostname: rabbit1
    ports:
      - 5672:5672 #集群内部访问的端口
      - 15672:15672 #外部访问的端口
    environment:
      - RABBITMQ_DEFAULT_USER=guest #用户名
      - RABBITMQ_DEFAULT_PASS=guest #密码
      - RABBITMQ_ERLANG_COOKIE='imoocrabbitmq'
​
  rabbit2:
    image: rabbitmq:management
    hostname: rabbit2
    ports:
      - 5673:5672
    environment:
      - RABBITMQ_ERLANG_COOKIE='imoocrabbitmq'
    links:
      - rabbit1
​
  rabbit3:
    image: rabbitmq:management
    hostname: rabbit3
    ports:
      - 5674:5672
    environment:
      - RABBITMQ_ERLANG_COOKIE='imoocrabbitmq'
    links:
      - rabbit1
      - rabbit2

2.4.4、将3个 RabbitMQ 节点搭建为集群

启动docker-compose,按照脚本启动集群

docker-compose up -d

上面命令可能会报端口占用,如果出现这个错那就把15672的docker先停下再执行上面命令就好了;进入2号节点

docker exec -it root_rabbit2_1 bash 

停止2号节点的rabbitmq

rabbitmqctl stop_app

配置2号节点,加入集群

rabbitmqctl join_cluster rabbit@rabbit1

停止3号节点的rabbitmq

rabbitmqctl stop_app

配置3号节点,加入集群

rabbitmqctl join_cluster rabbit@rabbit1

启动3号节点的rabbitmq

rabbitmqctl start_app 

2.4.5、打开客户端

 

 2.5、多机多节点部署

2.5.1、环境说明

本来想搞三个节点,但我自己的一台私有云今天不争气,不知道哪里问题一直启不来,就先搞两个节点吧;两个节点和多个节点原理是一样的

节点名称 IP地址
rabbitmq1 192.168.0.1
rabbitmq2 192.168.0.2

2.5.2、docker-compose 文件

 
version: '3'

services:
  rabbit1:
    container_name: rabbit1
    image: rabbitmq:management
    restart: always
    hostname: rabbit1
    extra_hosts:
      - "rabbit1:192.168.0.1"
      - "rabbit2:192.168.0.2"
    environment:
      - RABBITMQ_ERLANG_COOKIE=MY_COOKIE
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS=admin
    ports:
      - "4369:4369"
      - "5671:5671"
      - "5672:5672"
      - "15671:15671"
      - "15672:15672"
      - "25672:25672"

这样,192.168.0.1 上的 docker-compose 文件就写好了,部署另一台时,只要将 rabbit1 改成 rabbit2 就可以了。如果是更多台服务器的话,也是同样的道理,将 IP 配置到 extra_hosts 参数下即可。

2.5.3、启动服务

在两台服务器上分别执行:

docker-compose up -d

2.5.4、加入集群

如果将 rabbit1 作为主节点的话,需要在 rabbit2 上执行命令,将其加入到集群,如下:

# docker exec -it rabbit2 /bin/bash

rabbit2# rabbitmqctl stop_app
rabbit2# rabbitmqctl reset
rabbit2# rabbitmqctl join_cluster rabbit@rabbit1
rabbit2# rabbitmqctl start_app

默认情况下,RabbitMQ 启动后是磁盘节点,如果想以内存节点方式加入,可以加 --ram 参数。如果想要修改节点类型,可以使用命令:

# rabbitmqctl change_cluster_node_type disc(ram)

修改节点类型之前需要先 rabbitmqctl stop_app

通过下面命令来查看集群状态:

# rabbitmqctl cluster_status

注意,由于 RAM 节点仅将内部数据库表存储在内存中,因此在内存节点启动时必须从其他节点同步这些数据,所以一个集群必须至少包含一个磁盘节点。

2.5.5、HAProxy 负载均衡

ha 同样采用 Docker 方式来部署,先看一下 haproxy.cfg 配置文件:

# Simple configuration for an HTTP proxy listening on port 80 on all
# interfaces and forwarding requests to a single backend "servers" with a
# single server "server1" listening on 127.0.0.1:8000

global
    daemon
    maxconn 256

defaults
    mode http
    timeout connect 5000ms
    timeout client 5000ms
    timeout server 5000ms

listen rabbitmq_cluster
    bind 0.0.0.0:5677
    option tcplog
    mode tcp
    balance leastconn
    server  rabbit1 192.168.0.1:5672 weight 1 check inter 2s rise 2 fall 3
    server  rabbit2 192.168.0.2:5672 weight 1 check inter 2s rise 2 fall 3

listen http_front
    bind 0.0.0.0:8002
    stats uri /haproxy?stats

listen rabbitmq_admin
    bind 0.0.0.0:8001
    server rabbit1 192.168.0.1:15672
    server rabbit2 192.168.0.2:15672

再看一下 docker-compose 文件:

version: '3'

services:
  haproxy:
    container_name: rabbit-haproxy
    image: haproxy
    restart: always
    hostname: haproxy
    network_mode: rabbitmq_default
    volumes:
      - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
    ports:
      - "5677:5677"
      - "8001:8001"
      - "8002:8002"
 

启动之后,就可以通过 ha 的地址来访问 RabbitMQ 集群管理页面了。如果公司内部有现成的负载均衡,比如 LVS,那么也可以省略这一步。

三、镜像队列模式集群

镜像队列属于RabbitMQ 的高可用方案,见:https://www.rabbitmq.com/ha.html#mirroring-arguments;通过前面的步骤搭建的集群属于普通模式集群,是通过共享元数据实现集群;

3.1、开启镜像队列模式

开启镜像队列模式需要在管理页面添加策略,添加方式如下:

 

 

 

参数说明:
name: 策略名称,如果使用已有的名称,保存后将会修改原来的信息
Apply to:策略应用到什么对象上
Pattern:策略应用到对象时,对象名称的匹配规则(正则表达式)
Priority:优先级,数值越大,优先级越高,相同优先级取最后一个
Definition:策略定义的类容,对于镜像队列的配置来说,只需要包含3个部分: ha-mode 、ha-params 和 ha-sync-mode 。其中, ha-sync-mode 是同步的方式,自动还是手动,默认是自动。 ha-mode 和 ha-params 组合使用。组合方式如下:
ha-mode 
ha-params
说明
all 
(empty) 
队列镜像到集群类所有节点
exactly
count 
队列镜像到集群内指定数量的节点。如果集群内节点数少于此
值,队列将会镜像到所有节点。如果大于此值,而且一个包含镜
像的节点停止,则新的镜像不会在其它节点创建。
nodes
nodename
队列镜像到指定节点,指定的节点不在集群中不会报错。当队列
申明时,如果指定的节点不在线,则队列会被创建在客户端所连
接的节点上。
  • 镜像队列模式相比较普通模式,镜像模式会占用更多的带宽来进行同步,所以镜像队列的吞吐量会低于普通模式。
  • 但普通模式不能实现高可用,某个节点挂了后,这个节点上的消息将无法被消费,需要等待节点启动后才能被消费。
 
posted @ 2021-10-13 11:47  童话述说我的结局  阅读(803)  评论(0编辑  收藏  举报