• Docker搭建RabbitMQ集群


    目录

    1. 集群形成的要求
    2. 集群中的节点
    3. CLI如何验证节点
    4. RabbitMQ集群搭建
    5. Nginx实现负载均衡
    6. 测试

    集群形成的要求

    ① 主机名解析

    RabbitMQ节点使用短域名或全限定域名 (FQDN) 相互寻址。因此,所有集群成员的主机名必须可以从所有集群节点以及可能使用rabbitmqctl等命令行工具的机器上解析。

    主机名解析可以使用任何标准操作系统提供的方法:

    • DNS 记录
    • 本地主机文件(例如/etc/hosts)

    其中对于本地主机文件的主机名解析使用docker run --link 可在创建容器时,添加一个所连接容器的主机名到容器内 /etc/hosts 中。

    ② 端口访问

    RabbitMQ 节点绑定到端口(打开服务器 TCP 套接字)以接受客户端和 CLI 工具连接。

    集群中的节点

    RabbitMQ代理操作所需的所有数据/状态都在所有节点之间复制。一个例外是消息队列,默认情况下它们驻留在一个节点上,尽管它们对所有节点都是可见和可访问的。

    RabbitMQ 集群中的所有节点都是平等的:RabbitMQ核心中没有特殊节点。

    CLI如何验证节点:Erlang Cookie

    RabbitMQ节点和 CLI 工具(例如rabbitmqctl)使用cookie来确定是否允许它们相互通信。

    为了使两个节点能够通信,它们必须具有相同的共享密钥,称为 Erlang cookie。cookie 只是一串最多 255 个字符的字母数字字符。

    每个集群节点都必须有相同的cookie。

    在 UNIX 系统上,cookie 通常位于 /var/lib/rabbitmq/.erlang.cookie(由服务器使用)和$HOME/.erlang.cookie(由 CLI 工具使用)。这里 Home 可以通过查看日志看到(docker logs CONTAINER_NAME)。

    详见:RabbitMQ Clustering Guide
    在这里插入图片描述

    RabbitMQ集群搭建

    下面将统一使用node01的cookie,以保证每个节点有相同的cookie。

    1. 创建并运行容器

    # 拉取Rabbimq镜像
    docker pull rabbitmq:3.9-management
    
    # node01
    docker run --name rabbitmqNode01 --hostname=node01 
    -v /home/data/rabbitmqCluster/rabbitmq01:/var/lib/rabbitmq 
    -p 5673:5672 
    -p 15673:15672 
    -d rabbitmq:3.9-management
    
    # 把rabbitmqNode01容器中的/var/lib/rabbitmq/.erlang.cookie复制到宿主机中储存
    docker cp rabbitmqNode01:/var/lib/rabbitmq/.erlang.cookie /home/data/rabbitmqCluster/.erlang.cookie
    
    # node02
    docker run --name rabbitmqNode02 --hostname=node02 
    -v /home/data/rabbitmqCluster/rabbitmq02:/var/lib/rabbitmq 
    -p 5674:5672 
    -p 15674:15672 
    --link rabbitmqNode01:node01 
    -d rabbitmq:3.9-management
    
    docker cp /home/data/rabbitmqCluster/.erlang.cookie rabbitmqNode02:/var/lib/rabbitmq/.erlang.cookie
    
    # node03
    docker run --name rabbitmqNode03 --hostname=node03 
    -v /home/data/rabbitmqCluster/rabbitmq03:/var/lib/rabbitmq 
    -p 5675:5672 
    -p 15675:15672 
    --link rabbitmqNode01:node01 
    --link rabbitmqNode02:node02 
    -d rabbitmq:3.9-management
    
    docker cp /home/data/rabbitmqCluster/.erlang.cookie rabbitmqNode03:/var/lib/rabbitmq/.erlang.cookie
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    2. 容器节点加入集群

    # 进入第一个rabbitmq节点容器
    docker exec -it rabbitmqNode01 /bin/bash
    # rabbitmqctl stop 会将 Erlang 虚拟机关闭,rabbitmqctl stop_app只关闭RabbitMQ 服务
    rabbitmqctl stop_app
    # 重置节点,将 RabbitMQ 节点返回到其原始状态。
    rabbitmqctl reset
    # 只启动应用服务
    rabbitmqctl start_app
    # 退出容器
    exit
    
    # 进入第二个rabbitmq节点容器
    docker exec -it rabbitmqNode02 /bin/bash
    rabbitmqctl stop_app
    rabbitmqctl reset
    rabbitmqctl join_cluster rabbit@node01
    rabbitmqctl start_app
    exit
    
    # 进入第三个rabbitmq节点容器
    docker exec -it rabbitmqNode03 /bin/bash
    rabbitmqctl stop_app
    rabbitmqctl reset
    rabbitmqctl join_cluster rabbit@node01
    rabbitmqctl start_app
    exit
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    3. 查看集群状态

    # 进入任一节点容器
    docker exec -it rabbitmqNode01 /bin/bash
    rabbitmqctl cluster_status
    
    • 1
    • 2
    • 3

    cluster status

    4. 重新设置用户

    # 进入任一节点容器创建
    # 创建账号
    rabbitmqctl add_user user password
    # 设置用户角色
    rabbitmqctl set_user_tags user administrator
    # 设置用户权限
    rabbitmqctl set_permissions -p "/" user ".*" ".*" ".*"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    访问以下任意一个登录查看
    http://host-ip:15673
    http://host-ip:15674
    http://host-ip:15675
    user

    5. 解除集群节点(按需求处理)

    # 例如解除rabbitmqNode02
    docker exec -it rabbitmqNode02 /bin/bash
    rabbitmqctl stop_app
    rabbitmqctl reset
    rabbitmqctl start_app
    exit
    
    docker exec -it rabbitmqNode01 /bin/bash
    rabbitmqctl forget_cluster_node rabbit@node02
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Nginx实现负载均衡

    # 拉取nginx镜像
    docker pull nginx:1.20
    # 创建nginx配置文件并使用以下配置
    vim /home/data/nginx/nginx_rabbitmq_01.conf
    
    • 1
    • 2
    • 3
    • 4

    nginx_rabbitmq_01.conf

    user  nginx;
    worker_processes  1;
    
    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;
    
    
    events {
        worker_connections  1024;
    }
    
    
    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
    
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';
    
        access_log  /var/log/nginx/access.log  main;
    
        sendfile        on;
        #tcp_nopush     on;
    
        keepalive_timeout  65;
    
        #gzip  on;
    	
    	proxy_redirect          off;
    	proxy_set_header        Host $host;
    	proxy_set_header        X-Real-IP $remote_addr;
    	proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    	client_max_body_size    10m;
    	client_body_buffer_size   128k;
    	proxy_connect_timeout   5s;
    	proxy_send_timeout      5s;
    	proxy_read_timeout      5s;
    	proxy_buffer_size        4k;
    	proxy_buffers           4 32k;
    	proxy_busy_buffers_size  64k;
    	proxy_temp_file_write_size 64k;
    
    	# rabbitmq管理界面
    	upstream rabbitManage {
    		server 120.37.100.249:15673;
    		server 120.37.100.249:15674;
            server 120.37.100.249:15675;
    	}
    	server {
            listen          15676;
            server_name     120.37.100.249;
            location / {  
                proxy_pass   http://rabbitManage;
                index  index.html index.htm;  
            }  
        }
    }
    
    # rabbitmq通信
    stream{
    	upstream rabbitTcp{
            server 120.37.100.249:5673;
    		server 120.37.100.249:5674;
            server 120.37.100.249:5675;
        }
    
        server {
            listen 5676;
            proxy_pass rabbitTcp;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    根据配置文件创建自定义镜像
    Dockerfile

    FROM nginx:1.20
    
    COPY nginx_rabbitmq_01.conf /etc/nginx/nginx.conf
    
    EXPOSE 5676 15676
    
    
    # 根据Dockerfile构建新的镜像
    docker build -t nginx-rabbitmq:v1 .
    
    # 使用新的镜像创建nginx容器
    docker run -d --name nginxRabbitmq1 
    -p 5676:5676 
    -p 15676:15676 
    -v /home/data/nginx/nginx_rabbitmq_01.conf:/ect/nginx/nginx.conf 
    nginx-rabbitmq:v1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    测试

    建立一个简单的SpringBoot项目进行测试。

    项目结构
    springboot-project

    pom.xml

    
        
            org.springframework.boot
            spring-boot-starter-amqp
        
        
            org.springframework.boot
            spring-boot-starter-web
        
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    application.yml

    spring:
      application:
        name: demo-10-cluster-simple
      rabbitmq:
        username: user
        password: password
        host: 120.37.100.249
        port: 5676
    # 应用服务 WEB 访问端口
    server:
      port: 8080
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    RabbitMqConfig

    @Configuration
    public class RabbitMqConfig {
        public static final String X_EXCHANGE = "xExchange";
        public static final String Y_EXCHANGE = "yExchange";
        public static final String QUEUE_A = "queueA";
        public static final String QUEUE_B = "queueB";
    
        @Bean
        public DirectExchange xExchange() {
            return new DirectExchange(X_EXCHANGE);
        }
    
        @Bean
        public DirectExchange yExchange() {
            return new DirectExchange(Y_EXCHANGE);
        }
    
    
        @Bean
        public Queue queueA() {
            return QueueBuilder.durable(QUEUE_A).build();
        }
    
        @Bean
        public Binding aQueueBindingX(@Qualifier("queueA") Queue queueA, @Qualifier("xExchange") DirectExchange exchange) {
            return BindingBuilder.bind(queueA).to(exchange).with("routingKey");
        }
    
        @Bean
        public Queue queueB() {
            return QueueBuilder.durable(QUEUE_B).build();
        }
    
        @Bean
        public Binding bQueueBindingX(@Qualifier("queueB") Queue queueB, @Qualifier("yExchange") DirectExchange exchange) {
            return BindingBuilder.bind(queueB).to(exchange).with("routingKey");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    SendMsgController

    @RestController
    public class SendMsgController {
        @Autowired
        private RabbitTemplate rabbitTemplate;
    
        @GetMapping("sendMsg/x/{msg}")
        public void sendMsg1(@PathVariable String msg) {
            rabbitTemplate.convertAndSend("xExchange", "routingKey", msg);
            System.out.println(msg);
        }
    
        @GetMapping("sendMsg/y/{msg}")
        public void sendMsg2(@PathVariable String msg) {
            rabbitTemplate.convertAndSend("yExchange", "routingKey", msg);
            System.out.println(msg);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    http://localhost:8080/sendMsg/x/hello
    http://localhost:8080/sendMsg/y/world

    15676端口
    在这里插入图片描述

  • 相关阅读:
    【Maven教程】(十一):使用 Maven 构建 Web应用 —— 使用 jetty-maven-plugin 进行测试、使用 Cargo 实现自动化部署~
    关于http请求、文件处理以及空间地理信息处理的工具类介绍
    cookie、session、token的区别
    【函数式编程实战】(四)流-Stream API原理解析
    Functional equation (L-function)
    面向对象设计介绍和代码示例
    【JVM笔记】导出内存映像(dump)文件
    六爻排盘神机
    TypeScript中的泛型使用详解
    MybatisPlus(简单CURD,MP的实体类注解,MP条件查询,MP分页查询,MP批量操作,乐观锁,代码生成器)
  • 原文地址:https://blog.csdn.net/hjseo_seg/article/details/126327577