RabbitMq 普通集群搭建

一、集群概念

RabbitMQ集群是一个或多个节点的逻辑分组,每个节点共享用户、虚拟主机、队列、交换、绑定路由、运行时参数和其他分布式状态。集群中的节点可以动态地添加/删除,RabbitMQ代理一开始都运行在单个节点上,可以将这些节点连接到集群中,然后再将其转换回各个代理。

  1. 默认情况下,RabbitMq将复制除消息队列外的所有数据至集群中的每一个节点。而消息队列的完整数据只会存放于创建该队列的节点上,其余节点仅保存该队列的元数据和指针(类似于索引)。如果需要复制队列,则需要启用镜像队列集群。

  2. 集群中每个节点是平等的,不存在主从和特殊的节点。

  3. 集群中的节点通过Erlang Cookie相互通信,每个节点必须具有相同的cookie

  4. 节点分为磁盘节点和RAM节点,RAM节点只在RAM中存储内部数据库表,并不存储包括消息、消息存储索引、队列索引和其他节点状态等数据,RAM节点的性能更加高效,但是由于数据是非持久化的,一旦宕机将无法恢复。默认创建的都是磁盘节点。

  5. 单节点拓扑图如下,集群的拓扑是基于多个Node节点的扩展。

    单节点拓扑图

二、配置需求

  1. 配置方式
    • config 文件配置
    • rabbitmqctl命令配置(下文中使用此方法配置)
  2. 集群中的节点名必须是唯一的
    • 可以在启动时使用环境变量RABBITMQ_NODENAME设置
    • 节点名由[节点名称]@[host]组成
  3. 各个节点的启动端口可以被成功连接
  4. 节点之间通过节点名相互访问,要求各个节点之间的host可以相互进行DNS解析
  5. 每个节点之间必须配置相同的Erlang Cookie(多机环境需要额外配置)

三、集群配置

  1. 启动多个独立的节点

    RABBITMQ_NODE_PORT=5674 RABBITMQ_NODE_IPDDRESS=192.168.0.235  RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15673}]" RABBITMQ_NODENAME="clusterRabbit1@VM235"  /usr/local/rabbitmq/3.1.3/sbin/rabbitmq-server -detached
    RABBITMQ_NODE_PORT=5675 RABBITMQ_NODE_IPDDRESS=192.168.0.235  RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15674}]" RABBITMQ_NODENAME="clusterRabbit2@VM235" /usr/local/rabbitmq/3.1.3/sbin/rabbitmq-server -detached
    

    执行完成后,分别创建了名称为clusterRabbit1@VM235,clusterRabbit2@VM235的两个节点。

    VM235需要提前配置host文件,确保各个节点之间的host可以相互进行DNS解析。

  2. 创建集群

    1. 关闭节点clusterRabbit1@VM235
      ./rabbitmqctl -n clusterRabbit1@VM235 stop_app
      
    2. 重置节点clusterRabbit1@VM235
      ./rabbitmqctl -n clusterRabbit1@VM235 reset
      

      必须重置节点才能加入现有集群,重置节点将删除该节点上以前存在的所有资源和数据。这意味着节点不能在成为集群的成员时保留其现有数据,节点中的数据需要进行额外的备份和恢复。

    3. 将节点clusterRabbit1@VM235加入clusterRabbit2@VM235的集群

      ./rabbitmqctl -n clusterRabbit1@VM235 join_cluster clusterRabbit2@VM235
      
    4. 启动节点clusterRabbit1@VM235
      ./rabbitmqctl -n clusterRabbit1@VM235 start_app
      
    5. 查看集群信息
      ./rabbitmqctl -n clusterRabbit1@VM235 cluster_status
      结果:
      Cluster status of node clusterRabbit1@VM235 ...
      [{nodes,[{disc,[clusterRabbit1@VM235,clusterRabbit2@VM235]}]},
      {running_nodes,[clusterRabbit2@VM235,clusterRabbit1@VM235]},
      {partitions,[]}]
      ...done.
      
  3. 集群中节点的关闭与重启
    1. 节点关闭并重启之后会选择一个在线的集群成员(只考虑磁盘节点)进行同步。在重新启动节点时,默认情况下将尝试与该成员联系10次,并有30秒的响应超时。如果该成员在时间间隔内可用则节点将成功启动,并与该成员同步所需内容后继续运行。如果该成员无法响应,则重新启动的节点将放弃同步数据并启动。
    2. 以下情况将导致节点无法重新加入集群:
    • 修改节点名/主机名,节点的数据目录路径会因此更改。
    • 重置节点数据/更换节点数据目录
  4. 移除集群中的节点
    1. 关闭该节点
    2. 重置该节点
    3. 再次启动该节点

四、集群测试

  1. 创建用户、vhostexchangequeue,并启动消费者。【测试基础】
    1. 用户:api_managementmanagement标签,开放虚拟主机cluster所有权限)
    2. vhostcluster
    3. exchangecluster(直连交换机)
    4. queue
      1. 节点一 clusterRabbit1
        1. 队列一:
        • nameclusterRabbit1Queue1
        • routing_keyclusterRabbit1key
        1. 队列二:
        • nameclusterRabbit1Queue2
        • routing_keyclusterRabbitCommonKey
      2. 节点二 clusterRabbit2
        1. 队列三:
        • nameclusterRabbit2Queue1
        • routing_keyclusterRabbit2key
        1. 队列四:
        • nameclusterRabbit2Queue2
        • routing_keyclusterRabbitCommonKey(与队列二 相同)
    5. consumer
      1. 消费者一:
      • 连接节点:节点一 clusterRabbit1
      • 消费队列:队列一 clusterRabbit1Queue1
        1. 消费者二:
      • 连接节点:节点一 clusterRabbit1
      • 消费队列:队列二 clusterRabbit1Queue2
        1. 消费者三(非此节点的队列):
      • 连接节点:节点一 clusterRabbit1
      • 消费队列:队列三 clusterRabbit2Queue1
        1. 消费者四:
      • 连接节点:节点二 clusterRabbit2
      • 消费队列:队列四 clusterRabbit2Queue2
  2. 连接节点二 clusterRabbit2,再次声明队列名和队列一同名的队列clusterRabbit1Queue1。【同名队列再次声明】
    • 结果:声明不成功,节点二中没有生成新的clusterRabbit1Queue1队列,而节点一中clusterRabbit1Queue1队列多出了新绑定的routing_key,这意味着在同一集群中不同节点之间的队列名是唯一的,在一个节点中可以操作另一个节点的队列数据。
  3. 生产者连接节点一 clusterRabbit1,发布clusterRabbit1key消息。【发布此节点队列消息】
    • 消费者一 成功接收到消息
  4. 生产者连接节点二 clusterRabbit2,发布clusterRabbit1key消息。【发布非此节点队列消息】
    • 消费者一 成功接收到消息
  5. 生产者连接节点一 clusterRabbit1,发布clusterRabbitCommonKey消息。【多个节点队列绑定相同消息】
    • 消费者二 成功接收到消息
    • 消费者四 成功接收到消息
  6. 生产者连接节点一 clusterRabbit1,发布clusterRabbit2key消息。【消费非此节点队列消息】
    • 消费三 成功接收到消息
  7. 关闭节点二 clusterRabbit2,连接节点一,发布clusterRabbit2key消息【投递消息给集群中意外退出的节点】
    • 关闭节点二 clusterRabbit2之后,消费者三、四异常退出
    • 投递消息至集群成功
    • 再次启动节点二 clusterRabbit2以及消费者三、四,之前投递的消息没有成功接收

五、使用总结

  1. 同一集群中不同节点之间的队列名是唯一的,在一个节点中可以操作另一个节点的队列数据。
  2. 生产者可以发布集群中任一节点队列绑定的消息,集群将自动匹配出符合条件的节点队列,并投递给消费者进行消费。
  3. 集群中不同节点的队列如果绑定了相同的routing_key,消息将投递到集群中所有符合路由匹配条件的节点队列中。
  4. 消费者可以订阅集群中任意节点的队列。
  5. 集群中某个节点异常退出后,生产者投递到集群中的消息将无法送达至该节点,但是不影响其他节点的接收。(解决这个问题需要使用镜像队列集群)

六、错误记录

  1. 启动新的节点报错:could_not_start,rabbitmq_management

    解决:

    rabbitmq_management插件默认使用的是15672端口,这个端口已被之前启动的节点占用,修改启动命名为 rabbitmq_management插件指定一个新的端口即可。

    RABBITMQ_NODE_PORT=5674 RABBITMQ_NODE_IPDDRESS=192.168.0.235  RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15673}]" RABBITMQ_NODENAME="clusterRabbit1@VM235"  /usr/local/rabbitmq/3.1.3/sbin/rabbitmq-server -detached
    
  2. 【认知错误】rabbitmq_management管理后台Overview中节点的Memory表示使用的内存,Disk space表示剩余可用的磁盘空间,不是已使用的磁盘空间。

  3. 修改节点的host后启动失败:``ERROR: epmd error for host "VM235": nxdomain (non-existing domain)`

    解决:

    VM235需要预先添加到 HOST文件,确保可以被正确解析。

  4. 节点一 clusterRabbit1 退出集群后重新加入集群,再次声明之前的队列提示routing_key绑定不成功

    NOT_FOUND - no binding clusterRabbitCommonKey between exchange 'cluster' in vhost 'cluster' and queue 'clusterRabbit1Queue2' in vhost 'cluster'
    

    此问题是rabbitMq集群本身的问题,且未得到官方明确的解决方案。

    一些临时解放方案:

《RabbitMq 普通集群搭建》上有2条评论

发表评论