rabbitMQ插件Federation配置(数据同步)

扣扣技术分享交流群:1125844267

概述

Federation插件的最高目标是在节点间交换信息而不需要集群,这是使用这个插件最大的原因。

一、federation可以做什么?

这个插件允许绑定虚拟主机和队列,一个绑定的虚拟主机和队列可以接收一个或多个上游(upstreams)的信息。一个绑定的交换机可以过滤上游发布的信息到本地。一个绑定的队列可以让一个本地的消费者接收上游队列的信息。

二、特点

1、这个插件可以交换节点或者集群间的信息;

2、可以有不同的用户和虚拟主机;

3、可以是不同版本的RabbitMQ和Erlang;

4、插件使用AMQP协议,可以容忍网络的间歇性连接;

5、扩展性很好,不会限制节点个数;

三、使用步骤

1.安装rabbitMQ

安装socat:yum install socat;再安装erlang:yum install erlang;最后:yum install rabbitmq-server。同时也不用复制配置文件,/etc下会自己创建,默认安装的是最新版。

2.启动插件

rabbitmq-plugins enable rabbitmq_federation(直接执行命令)

rabbitmq-plugins enable rabbitmq_federation_management(直接执行命令)

启动rabbitMQ之后,管理平台会多出这两个配置选项:

rabbitMQ插件Federation配置(数据同步)_第1张图片

3.分启别动rabbitMQ服务

systemctl start rabbitmq-server

4.创建新的用户

服务器32的mq上添加新用户test,另外一个服务器114的mq配置用户test1。注意用户的tags,选择administrator,否则无法用新建用户登录管理平台,那么也就无法用管理平台来配置federation了,相对来说,管理平台来配置还是要直观简单一些。

5.配置需要交换机的mq

1、两个mq需要配置相同名称的虚拟主机(virtualForTestExchange),同时将虚拟主机与我们新创建的用户绑定。刚开始虚拟主机名称不一样,无法同步数据,状态总是报错。所以,为了确保正确运行,两个mq的虚拟主机名称、交换机名称、队列名称、Federation Upstreams名称、Policies名称都保持一致

rabbitMQ插件Federation配置(数据同步)_第2张图片

2、创建相同名称的交换机(exchangeForTest)

rabbitMQ插件Federation配置(数据同步)_第3张图片

3、创建相同名称的队列(queueForTestExchange)

rabbitMQ插件Federation配置(数据同步)_第4张图片

4、将队列绑定到交换机上

rabbitMQ插件Federation配置(数据同步)_第5张图片

注意:一个交换机可以绑定多个队列,每次绑定指定具体Routing key(路由键),消费者消费的时候通过指定具体的Routing key来确定消费哪个队列中的数据。当然,同一个队列中的数据只可以消费一次,之前的理解有误,以为发布/订阅模式下不管是不是同一个队列都可以消费多次,这是不对的。发布/订阅是交换机相对于不同的队列来说的,不同的队列可以获取到同一个交换机相同的数据,但是同一个队列中的数据只能消费一次。

5、创建Federation Upstreams

创建Federation Upstreams,这个其实可以是单向的,也可以是双向的。所以,可以一个mq配置,也可以两个都配置。如果是32上配置的话,其实是同步114上的数据,将114当做是上游,而114无法同步32的数据。

rabbitMQ插件Federation配置(数据同步)_第6张图片

Expires:过期时间,如果长时间未与上游连接,到了过期时间后,上游的队列会被删除,不填的话为永远不删除;

Message TTL:消息过期时间,如果长时间未取上游的信息,会造成上游队列信息堆积,设置过期时间后,队列中的信息会被清理,避免信息堆积。不填的话为永远不删除;

注意:因为是在32上配置的,会去拉取114上的数据,所以这个URI是指向114的连接amqp://test1(mq新创建的用户名):test1(密码)@114的ip地址:5672

6、配置Policies(policyForTestExchange)

一开始以为这个不是必须的,但是不配还不行。这是一个配置的例子,不是我们实际配置的内容。

rabbitMQ插件Federation配置(数据同步)_第7张图片

这是实际配置好的:

rabbitMQ插件Federation配置(数据同步)_第8张图片

Pattern:正则匹配交换机;

Apply to:可以根据自己的配置选择,这个可以只选Exchanges;

Definition:这个还是个必填项,federation-upstream-set=all,也可以针对具体上游名称的单个upstream

rabbitMQ插件Federation配置(数据同步)_第9张图片

6.配置不需要交换机的,直接到队列

配置方式和配置有交换机的类似,只是不再配置交换机了,不再记录具体配置过程。

翻译:联邦交换机的方式会复制上游的消息到一个或者多个下游,联邦队列则是消费者在哪儿数据就移动到哪儿,经常是偏向本地的消费者(就近原则)。联邦队列被认为是平等的,它不像联邦交换机那样有“领导者”和“跟随者”。

* 刚刚配置完的时候,分别启动两个消费者去消费两个mq联邦队列的消息,本以为会和有交换机一样,两个消费者都会收到消息,但实际是给哪个队列发的消息,哪个消费者就收到了消息,另外一个没有收到。那么从上边官方文档我们可以看出,它遵循就近原

则,其实就是一个队列,一条消息只能消费一次,虽然配置了federation。那么把收到消息的消费者停掉后再发消息,另外一个消费者就能收到消息了。

rabbitMQ插件Federation配置(数据同步)_第10张图片rabbitMQ插件Federation配置(数据同步)_第11张图片

四、java通过httpClient获取mq的某些参数

通过java代码获取rabbitmq的一些参数,其实最简单的办法就是利用web管理页面的请求地址,java通过后台http请求来获取页面参数。同时也可以点击队列下的HTTP API来查看官方给定的api。需要注意的是,后端请求需要basic验证

rabbitMQ插件Federation配置(数据同步)_第12张图片rabbitMQ插件Federation配置(数据同步)_第13张图片

例如获取指定队列的深度(因为是模拟管理平台请求,所以端口是15672,官方给定的api文档也是15672)

我们可以在管理平台中点击进queue页面,java模拟这个请求http://ip:15672/api/queues/虚拟主机名称/队列名称,那么可以请求到页面的数据,也就可以获取到例如Total、Ready这些数据。

rabbitMQ插件Federation配置(数据同步)_第14张图片

public static void main(String[] args) throws IOException {
        String url = "http://ip:15672/api/queues/虚拟主机名称/队列名称";
        String userName = "xxx";
        String password = "xxx";
        getMQQueueDeepth(url,userName,password);
    }

    public static CloseableHttpClient getBasicHttpClient(String username,String password){
        CredentialsProvider provider = new BasicCredentialsProvider();
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        AuthScope scope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM);
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username,password);
        provider.setCredentials(scope, credentials);
        httpClientBuilder.setDefaultCredentialsProvider(provider);
        return httpClientBuilder.build();
    }

    /**
     * 获取当前指定队列的深度
     * 获取当前指定队列的消费者个数
     * @param url
     * @param username
     * @param password
     * @return
     */
    private static void getMQQueueDeepth(String url,String username,String password) {
        HttpGet httpGet = new HttpGet(url);
        CloseableHttpClient client = getBasicHttpClient(username,password);
        CloseableHttpResponse response = null;
        Long queueDeepth = 0L;
        Integer queueCustomers = 0;
        try {
            response = client.execute(httpGet);
            int state = response.getStatusLine().getStatusCode();
            if (state == HttpStatus.SC_OK) {   //等于200
                InputStream inputStream = response.getEntity().getContent();
                InputStreamReader isr = new InputStreamReader(inputStream);
                char[] buffer = new char[1024];
                StringBuilder sb = new StringBuilder();
                int length = 0;
                while ((length = isr.read(buffer)) > 0) {
                    sb.append(buffer, 0, length);
                }
                String contentStr = sb.toString();
                System.out.println("返回的内容:" + contentStr);
                JSONObject contentJson = JSON.parseObject(contentStr);
                queueDeepth = contentJson.get("messages") == null ? 0 : Long.valueOf(String.valueOf(contentJson.get("messages")));
                queueCustomers = contentJson.get("consumers") == null ? 0 : Integer.valueOf(String.valueOf(contentJson.get("consumers")));
                System.out.println("指定队列的深度:"+queueDeepth);
                System.out.println("指定队列的消费者:"+queueCustomers);
            } else {
                System.out.println("请求返回的状态值:" + state);
            }
        }catch (Exception e){
            e.printStackTrace();
        } finally {
            closeAll(response,client);
        }
    }
    private static void closeAll(CloseableHttpResponse response,CloseableHttpClient client){
        try {
            if(response != null){
                response.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if(client != null){
                client.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


感谢打赏!!!

你可能感兴趣的:(消息中间件,rabbitmq,java,后端)