zoukankan      html  css  js  c++  java
  • 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
    队列镜像到指定节点,指定的节点不在集群中不会报错。当队列
    申明时,如果指定的节点不在线,则队列会被创建在客户端所连
    接的节点上。
    • 镜像队列模式相比较普通模式,镜像模式会占用更多的带宽来进行同步,所以镜像队列的吞吐量会低于普通模式。
    • 但普通模式不能实现高可用,某个节点挂了后,这个节点上的消息将无法被消费,需要等待节点启动后才能被消费。
     
    这短短的一生我们最终都会失去,不妨大胆一点,爱一个人,攀一座山,追一个梦
  • 相关阅读:
    Excel两列查找重复值
    Docker容器的数据卷(data volume),数据卷容器,数据卷的备份和还原
    Ubuntu 搭建 GitLab 笔记 ***
    JIRA使用
    Android.mk文件LOCAL_MODULE_TAGS 说明
    Git Reset 三种模式
    Android常用的编译命令
    Android源码编译
    AOSP---"Android Open-Source Project"
    理解 Android Build 系统
  • 原文地址:https://www.cnblogs.com/xing1/p/15369801.html
Copyright © 2011-2022 走看看