关于java:手把手教你搭建-RabbitMQ-集群

13次阅读

共计 5077 个字符,预计需要花费 13 分钟才能阅读完成。

@[toc]
单个的 RabbitMQ 必定无奈实现高可用,要想高可用,还得上集群。

明天松哥就来和大家聊一聊 RabbitMQ 集群的搭建。

1. 两种模式

说到集群,小伙伴们可能第一个问题是,如果我有一个 RabbitMQ 集群,那么是不是我的音讯集群中的每一个实例都保留一份呢?

这其实就波及到 RabbitMQ 集群的两种模式:

  • 一般集群
  • 镜像集群

1.1 一般集群

一般集群模式,就是将 RabbitMQ 部署到多台服务器上,每个服务器启动一个 RabbitMQ 实例,多个实例之间进行音讯通信。

此时咱们创立的队列 Queue,它的元数据(次要就是 Queue 的一些配置信息)会在所有的 RabbitMQ 实例中进行同步,然而队列中的音讯只会存在于一个 RabbitMQ 实例上,而不会同步到其余队列。

当咱们生产音讯的时候,如果连贯到了另外一个实例,那么那个实例会通过元数据定位到 Queue 所在的地位,而后拜访 Queue 所在的实例,拉取数据过去发送给消费者。

这种集群能够进步 RabbitMQ 的音讯吞吐能力,然而无奈保障高可用,因为一旦一个 RabbitMQ 实例挂了,音讯就没法拜访了,如果音讯队列做了长久化,那么等 RabbitMQ 实例复原后,就能够持续拜访了;如果音讯队列没做长久化,那么音讯就丢了。

大抵的流程图如下图:

1.2 镜像集群

它和一般集群最大的区别在于 Queue 数据和原数据不再是独自存储在一台机器上,而是同时存储在多台机器上。也就是说每个 RabbitMQ 实例都有一份镜像数据(正本数据)。每次写入音讯的时候都会主动把数据同步到多台实例下来,这样一旦其中一台机器产生故障,其余机器还有一份正本数据能够持续提供服务,也就实现了高可用。

大抵流程图如下图:

1.3 节点类型

RabbitMQ 中的节点类型有两种:

  • RAM node:内存节点将所有的队列、交换机、绑定、用户、权限和 vhost 的元数据定义存储在内存中,益处是能够使得交换机和队列申明等操作速度更快。
  • Disk node:将元数据存储在磁盘中,单节点零碎只容许磁盘类型的节点,避免重启 RabbitMQ 的时候,失落零碎的配置信息

RabbitMQ 要求在集群中至多有一个磁盘节点,所有其余节点能够是内存节点,当节点退出或者来到集群时,必须要将该变更告诉到至多一个磁盘节点。如果集群中惟一的一个磁盘节点解体的话,集群依然能够放弃运行,然而无奈进行其余操作(增删改查),直到节点复原。为了确保集群信息的可靠性,或者在不确定应用磁盘节点还是内存节点的时候,倡议间接用磁盘节点。

2. 搭建一般集群

2.1 准备常识

大抵的构造理解了,接下来咱们就把集群给搭建起来。先从一般集群开始,咱们就应用 docker 来搭建。

搭建之前,有两个准备常识须要大家理解:

  1. 搭建集群时,节点中的 Erlang Cookie 值要统一,默认状况下,文件在 /var/lib/rabbitmq/.erlang.cookie,咱们在用 docker 创立 RabbitMQ 容器时,能够为之设置相应的 Cookie 值。
  2. RabbitMQ 是通过主机名来连贯服务,必须保障各个主机名之间能够 ping 通。能够通过编辑 /etc/hosts 来手工增加主机名和 IP 对应关系。如果主机名 ping 不通,RabbitMQ 服务启动会失败(如果咱们是在不同的服务器上搭建 RabbitMQ 集群,大家须要留神这一点,接下来的 2.2 小结,咱们将通过 Docker 的容器连贯 link 来实现容器之间的拜访,略有不同)。

2.2 开始搭建

执行如下命令创立三个 RabbitMQ 容器:

docker run -d --hostname rabbit01 --name mq01 -p 5671:5672 -p 15671:15672 -e RABBITMQ_ERLANG_COOKIE="javaboy_rabbitmq_cookie" rabbitmq:3-management
docker run -d --hostname rabbit02 --name mq02 --link mq01:mylink01 -p 5672:5672 -p 15672:15672 -e RABBITMQ_ERLANG_COOKIE="javaboy_rabbitmq_cookie" rabbitmq:3-management
docker run -d --hostname rabbit03 --name mq03 --link mq01:mylink02 --link mq02:mylink03 -p 5673:5672 -p 15673:15672 -e RABBITMQ_ERLANG_COOKIE="javaboy_rabbitmq_cookie" rabbitmq:3-management

运行后果如下:

三个节点当初就启动好了,留神在 mq02 和 mq03 中,别离应用了 --link 参数来实现容器连贯,对于这个参数,如果大家不懂,能够在公众号江南一点雨后盾回复 docker,由松哥写的 docker 入门教程,里边有讲这个。这里我就不啰嗦了。另外还须要留神,mq03 容器中要既可能连贯 mq01 也可能连贯 mq02。

接下来进入到 mq02 容器中,首先查看一下 hosts 文件,能够看到咱们配置的容器连贯曾经失效了:

未来在 mq02 容器中,就能够通过 mylink01 或者 rabbit01 拜访到 mq01 容器了。

接下来咱们开始集群的配置。

别离执行如下命令将 mq02 容器退出集群中:

rabbitmqctl stop_app
rabbitmqctl join_cluster rabbit@rabbit01
rabbitmqctl start_app

接下来输出如下命令咱们能够查看集群的状态:

rabbitmqctl cluster_status

能够看到,集群中曾经有两个节点了。

接下来通过雷同的形式将 mq03 也退出到集群中:

rabbitmqctl stop_app
rabbitmqctl join_cluster rabbit@rabbit01
rabbitmqctl start_app

接下来,咱们能够查看集群信息:

能够看到,此时集群中曾经有三个节点了。

其实,这个时候,咱们也能够通过网页来查看集群信息,在三个 RabbitMQ 实例的 Web 端首页,都能够看到如下内容:

2.3 代码测试

接下来咱们来简略测试一下这个集群。

咱们创立一个名为 mq_cluster_demo 的父工程,而后在其中创立两个子工程。

第一个子工程名为 provider,是一个音讯生产者,创立时引入 Web 和 RabbitMQ 依赖,如下:

而后配置 applicaiton.properties,内容如下(留神集群配置):

spring.rabbitmq.addresses=localhost:5671,localhost:5672,localhost:5673
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

接下来提供一个简略的队列,如下:

@Configuration
public class RabbitConfig {
    public static final String MY_QUEUE_NAME = "my_queue_name";
    public static final String MY_EXCHANGE_NAME = "my_exchange_name";
    public static final String MY_ROUTING_KEY = "my_queue_name";

    @Bean
    Queue queue() {return new Queue(MY_QUEUE_NAME, true, false, false);
    }

    @Bean
    DirectExchange directExchange() {return new DirectExchange(MY_EXCHANGE_NAME, true, false);
    }

    @Bean
    Binding binding() {return BindingBuilder.bind(queue())
                .to(directExchange())
                .with(MY_ROUTING_KEY);
    }
}

这个没啥好说的,都是根本内容,接下来咱们在单元测试中进行音讯发送测试:

@SpringBootTest
class ProviderApplicationTests {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Test
    void contextLoads() {rabbitTemplate.convertAndSend(null, RabbitConfig.MY_QUEUE_NAME, "hello 江南一点雨");
    }

}

这条音讯发送胜利之后,在 RabbitMQ 的 Web 治理端,咱们会看到三个 RabbitMQ 实例上都会显示有一条音讯,然而实际上音讯自身只存在于一个 RabbitMQ 实例。

接下来咱们再创立一个音讯消费者,音讯消费者的依赖以及配置和音讯生产者都是截然不同,我就不反复了,音讯消费者中减少一个音讯接收器:

@Component
public class MsgReceiver {@RabbitListener(queues = RabbitConfig.MY_QUEUE_NAME)
    public void handleMsg(String msg) {System.out.println("msg =" + msg);
    }
}

当音讯消费者启动胜利后,这个办法中只收到一条音讯,进一步验证了咱们搭建的 RabbitMQ 集群是没问题的。

2.4 反向测试

接下来松哥再举两个反例,以证实音讯并没有同步到其余 RabbitMQ 实例。

确保三个 RabbitMQ 实例都是启动状态,敞开掉 Consumer,而后通过 provider 发送一条音讯,发送胜利之后,敞开 mq01 实例,而后启动 Consumer 实例,此时 Consumer 实例并不会生产音讯,反而会报错说 mq01 实例连贯不上,这个例子就能够阐明音讯在 mq01 上,并没有同步到另外两个 MQ 上。相同,如果 provider 发送音讯胜利之后,咱们没有敞开 mq01 实例而是敞开了 mq02 实例,那么你就会发现音讯的生产不受影响。

3. 搭建镜像集群

所谓的镜像集群模式并不需要额定搭建,只须要咱们将队列配置为镜像队列即可。

这个配置能够通过网页配置,也能够通过命令行配置,咱们别离来看。

3.1 网页配置镜像队列

先来看看网页上如何配置镜像队列。

点击 Admin 选项卡,而后点击左边的 Policies,再点击 Add/update a policy,如下图:

接下来增加一个策略,如下图:

各参数含意如下:

  • Name: policy 的名称。
  • Pattern: queue 的匹配模式 (正则表达式)。
  • Definition:镜像定义,次要有三个参数:ha-mode, ha-params, ha-sync-mode。

    • ha-mode:指明镜像队列的模式,有效值为 all、exactly、nodes。其中 all 示意在集群中所有的节点上进行镜像(默认即此);exactly 示意在指定个数的节点上进行镜像,节点的个数由 ha-params 指定;nodes 示意在指定的节点上进行镜像,节点名称通过 ha-params 指定。
    • ha-params:ha-mode 模式须要用到的参数。
    • ha-sync-mode:进行队列中音讯的同步形式,有效值为 automatic 和 manual。
  • priority 为可选参数,示意 policy 的优先级。

配置实现后,点击上面的 add/update policy 按钮,实现策略的增加,如下:

增加实现后,咱们能够进行一个简略的测试。

首先确认三个 RabbitMQ 都启动了,而后用下面的 provider 向音讯队列发送一条音讯。

发完之后敞开 mq01 实例。

接下来启动 consumer,此时发现 consumer 能够实现音讯的生产(留神和后面的反向测试辨别),这就阐明镜像队列曾经搭建胜利了。

3.2 命令行配置镜像队列

命令行的配置格局如下:

rabbitmqctl set_policy [-p vhost] [--priority priority] [--apply-to apply-to] {name} {pattern} {definition}

举一个简略的配置案例:

rabbitmqctl set_policy -p / --apply-to queues my_queue_mirror "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}'

4. 小结

好啦,这就是松哥和大家分享的 RabbitMQ 中的集群搭建,感兴趣的小伙伴连忙去试试吧~

正文完
 0