rabbitmq配置镜像模式

原文地址,转载请注明出处: http://blog.csdn.net/qq_34021712/article/details/72634055     ©王赛超

《rabbitmq集群搭建(多机)》《rabbitmq单机多实例集群搭建》博文中讲到了如果做集群,那么集群是成功了,但是queue是如何存放的呢?消息又是怎么同步呢。

默认的,也就是什么也不配置,直接在某个节点中添加一个queue,那么它仅仅是属于这个节点的。其它节点有的只是它的影子。所以像断线重连、操作恢复是无法做到的,实验证明确实是这样的。声明queue的节点宕机那么是无法再进行发布消息与消费的。这自然失去了集群的意义。

默认模式我们一般是不会使用的,我们使用镜像模式,queue mirror 会有一个 主节点 对应零个或多个从节点,也可以说成主从复制,每个节点都有着相同的数据,某个节点挂掉了,另一个可以立即顶上。



1.镜像的配置是通过 policy 策略的方式
rabbitmqctl set_policy  ha-all "test_queue" '{"ha-mode":"all"}'
                    ha-all 是同步模式,指同步给所有节点,还有另外两种模式ha-exactly表示在指定个数的节点上进行镜像,节点的个数由ha-params指定,ha-nodes表示在指定的节点上进行镜像,节点名称通过ha-params指定;

                    test_queue 是同步的队列名,可以用正则表达式匹配;

                    {"ha-mode":"all"} 表示同步给所有,同步模式的不同,此参数也不同。

执行上面命令后,可以在web管理界面查看queue 页面,里面test_queue队列的node节点后会出现+2标签,表示有2个从节点,而主节点则是当前显示的node






2.也可以使用web控制台来添加策略



                     Ha mode 同步方式

                    Ha params 选择其它同步方式的参数 比如节点名

                    Ha async mode 同步方式,这个需要详细说明的,默认的情况下。当节点断线后那么这个节点就已经是落后的版本,当我们再去启动节点的时候数据我们需要去手动的同步,这自然是不好的,做到自动化是最完美的,所以设置成automatic是最佳选择



3.测试
设置完毕后,就可以通过代码来看看效果了,因为使用了集群,所以创建connection的时候需要做些变化了,创建连接的时候把节点的ip放了进去(如果是多机,修改为对应的ip端口)
Producer类
package com.rabbitmq.test.T_helloworld;


import com.rabbitmq.client.Address;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.test.util.ConnectionUtil;


/**
 * helloworld
 * @author lenovo
 *
 */
public class Producer {


	private final static String QUEUE_NAME = "test_queue";


    public static void main(String[] argv) throws Exception {
    	//定义一个链接工厂
		ConnectionFactory factory=new ConnectionFactory();		
		//账号
		factory.setUsername("admin");
		//密码
		factory.setPassword("admin");
		//断线重连,也就是如果当前的连接断开了,将会尝试重连
		factory.setAutomaticRecoveryEnabled(true);
		//重连后恢复当前的工作进程,比如channel、queue、发布的消息进度等
		factory.setTopologyRecoveryEnabled(true);
		//vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
		//factory.setVirtualHost("/testrabbit");
		// 获取到连接以及mq通道
		Address[] address={new Address("192.168.1.103", 5672),new Address("192.168.1.103", 5673),new Address("192.168.1.103", 5674)};
		Connection connection = factory.newConnection(address);
        
        // 从连接中创建通道
        Channel channel = connection.createChannel();


        /*
         * 声明(创建)队列
         * 参数1:队列名称
         * 参数2:为true时server重启队列不会消失
         * 参数3:队列是否是独占的,如果为true只能被一个connection使用,其他连接建立时会抛出异常
         * 参数4:队列不再使用时是否自动删除(没有连接,并且没有未处理的消息)
         * 参数5:建立队列时的其他参数
         */
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);


        // 消息内容
        String message = "Hello World888888!";
        /*
         * 向server发布一条消息
         * 参数1:exchange名字,若为空则使用默认的exchange
         * 参数2:routing key
         * 参数3:其他的属性
         * 参数4:消息体
         * RabbitMQ默认有一个exchange,叫default exchange,它用一个空字符串表示,它是direct exchange类型,
         * 任何发往这个exchange的消息都会被路由到routing key的名字对应的队列上,如果没有对应的队列,则消息会被丢弃
         */
        channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
        System.out.println(" [生产者] Sent '" + message + "'");


        //关闭通道和连接
        channel.close();
        connection.close();
    }
}

Consumer类
package com.rabbitmq.test.T_helloworld;


import com.rabbitmq.client.Address;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.test.util.ConnectionUtil;


public class Consumer {


	private final static String QUEUE_NAME = "test_queue";


    public static void main(String[] argv) throws Exception {


    	//定义一个链接工厂
		ConnectionFactory factory=new ConnectionFactory();		
		//账号
		factory.setUsername("admin");
		//密码
		factory.setPassword("admin");
		//断线重连,也就是如果当前的连接断开了,将会尝试重连
		factory.setAutomaticRecoveryEnabled(true);
		//重连后恢复当前的工作进程,比如channel、queue、发布的消息进度等
		factory.setTopologyRecoveryEnabled(true);
		//vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
		//factory.setVirtualHost("/testrabbit");
		// 获取到连接以及mq通道
		Address[] address={new Address("192.168.1.103", 5672),new Address("192.168.1.103", 5673),new Address("192.168.1.103", 5674)};
		Connection connection = factory.newConnection(address);
		
        // 从连接中创建通道
        Channel channel = connection.createChannel();


        // 声明队列(如果你已经明确的知道有这个队列,那么下面这句代码可以注释掉,如果不注释掉的话,也可以理解为消费者必须监听一个队列,如果没有就创建一个)
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);


        // 定义队列的消费者
        QueueingConsumer consumer = new QueueingConsumer(channel);
       /*
         * 监听队列
         * 参数1:队列名称
         * 参数2:是否发送ack包,不发送ack消息会持续在服务端保存,直到收到ack。  可以通过channel.basicAck手动回复ack
         * 参数3:消费者
         */ 
        channel.basicConsume(QUEUE_NAME, true, consumer);


        // 获取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" [消费者] Received '" + message + "'");
        }
    }
}

4.然后把主节点杀掉,继续使用以上代码测试,可以使用




  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值