同城机房
-
将RocketMQ部署到两个同城机房,一个用于对外流量,一个用于灾备切换(比如入口网络故障,导致所有系统不可用)。两个机房共同承担消息的写入和消费。 每个机房都有Produer,每个机房都有Consumer
-
目标:实现本机房的消费者优先消费本机房中的消息,避免跨机房消费
-
使用docker模拟多机房场景
机房 主机名 brokerName 端口 状态 机房A rocketmq-master1 rocketmq-master1-MachineRoomA 10911 正常 机房B rocketmq-master2 rocketmq-master2-MachineRoomB 10911 不正常 机房A rocketmq-slave1 rocketmq-master1-MachineRoomA 10911 正常 机房B rocketmq-slave2 rocketmq-master2-MachineRoomB 10911 正常 共用 rocketmq-nameserver1 9876 正常 共用 rocketmq-nameserver2 9876 正常 -
查看集群
生产者
-
不同机房的应用不同的配置,只需要在生产者配置一个额外的变量,然后通过自定义
MessageQueueSelector
来实现优先当前机房发送,当前机房不可用时,选择同城其他机房发送。注意:如果自定义MessageQueueSelector则需要自己实现重试和故障延迟机制@Test public void testSyncMachineRootA() { String namesrvAddr = "rocketmq-nameserver1:9876;rocketmq-nameserver2:9876"; String producerGroup = "ProducerGroupName"; final DefaultMQProducer defaultMQProducer = new DefaultMQProducer(producerGroup); try { defaultMQProducer.setInstanceName("producer"); defaultMQProducer.setSendMsgTimeout(20000); defaultMQProducer.setVipChannelEnabled(false); defaultMQProducer.setNamesrvAddr(namesrvAddr); defaultMQProducer.setRetryTimesWhenSendFailed(3); defaultMQProducer.start(); String topic = "MachineTopic"; String tag = "TagA"; String keys = "keys"; String machineRootNameEndWith = "-MachineRoomA"; for (int i = 0; i < 1000000; i++) { String msg = "hello world " + i; Message message = new Message(topic, tag, keys, msg.getBytes(RemotingHelper.DEFAULT_CHARSET)); SendResult sendResult = defaultMQProducer.send(message, new MessageQueueSelector() { @Override public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) { //A机房应用发送的A机房,B机房应用发送到B机房,如果A机房不可用,则发送到B机房 List<MessageQueue> currentMachineRoots = mqs.stream().filter(mq -> mq.getBrokerName().endsWith(machineRootNameEndWith)).collect(Collectors.toList()); if (CollectionUtils.isNotEmpty(currentMachineRoots)) { logger.info("从当前机房选择:{}", currentMachineRoots); return new SelectMessageQueueByHash().select(currentMachineRoots, msg, arg); } else { // 从同城机房中选择 logger.info("从同城机房选择:{}", mqs); return