微服务架构-分布式消息中间件-090:RocketMQ-RocketMQ集群部署原理与顺序消息原理

1 rocketmq架构原理简单技术回顾

课程内容:

  1. Broker如何实现多主集群模式
  2. Broker单个主题分为多个不同队列模式
  3. 生产者手写投递分片策略算法
  4. RocketMQ顺序消息实现原理

2 rocketmq集群四种模式架构

RocketMQ 四种集群部署方式

  1. 单个Master节点,缺点:负载压力大,如果宕机之后可能整个服务不可用;
  2. 多个Master节点,分摊存放消息,缺点:没有Slave节点,主的Master节点宕机之后没有备份消息数据可能会丢失;
  3. 多个Master和Slave节点,采用同步形式实现主从数据同步,主备节点都存放队列消息才返回ack表示投递成功,效率比较低,数据不会产生延迟、不会丢失;
  4. 多个Master和Slave节点,采用异步形式实现主从数据同步,效率非常高,数据同步可能短暂产生延迟(毫秒级别的)、数据可能丢失;

3 rocketmqBroker集群的方式

RocketMQ 集群部署

cd /usr/local/rocketmq/conf
vi broker.conf
#集群名称,可以区分不同集群,不同的业务可以建多个集群
brokerClusterName=mayikt
# Broker 的名称, Master 和Slave 通过使用相同的Broker 名称来表明相互关系,以说明某个Slave 是哪个Master 的Slave。
brokerName=broker-a
#  一个Master Barker 可以有多个Slave, 0 表示Master ,大于0 表示不同Slave 的ID。
brokerId=0 
#与fileReservedTim巳参数呼应,表明在几点做消息删除动作,默认值04 表示凌晨4点。
deleteWhen=04
namesrvAddr=mqnameserver1:9876;mqnameserver2:9876
autoCreateTopicEnable=true
#topic默认创建的队列数
defaultTopicQueueNums=4
#是否允许Broker自动创建订阅组,建议线下开启,线上关闭,默认【true】
autoCreateSubscriptionGroup=true
#Broker 监听的端口号,如果一台机器上启动了多个Broker,则要设置不同的端口号,避免冲突。
listenPort=10911
brokerIp=192.168.1.1

集群搭建
在这里插入图片描述
集群效果
在这里插入图片描述

4 rocketmq如何实现实现动态扩容

rocketmq动态扩容原理
新增的节点统一注册到相同的nameServer上,Producer从nameServer动态获取节点地址,再本地实现rpc负载均衡调用投递消息。

5 rocketmq如何实现topic拆分多个不同队列

RocketMQ单机版本情况下,默认情况下创建一个topic会将该topic分成四个队列存放;优点:高吞吐量
需要注意的问题:消息的顺序消费问题。
在这里插入图片描述

6 rocketmq如何保证消息的顺序的问题

顺序消息产生背景:
生产者向同一个主题中投递的消息行为每次可能不同
基于消息中间件投递消息 订单相关
新增订单、修改订单、删除订单 必然产生顺序性问题
最大的难点:消费者集群、队列集群
解决顺序问题核心思路:

  1. 相同的业务逻辑一定要存放到同一个队列(先进先出);
  2. 每个队列必须要对应同一个消费者消费;
  3. RocketMQ每个队列1:1均等匹配消费者;

单机版本中如何增加rocketMQ吞吐量?只需增加队列总数即可,消费者数量1:1增加。

7 rocketmq.代码形式解决消息顺序性问题

maven依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.0.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-spring-boot-starter</artifactId>
        <version>2.0.3</version>
    </dependency>
</dependencies>

application.yml

rocketmq:
  ###连接地址nameServer
  name-server: 192.168.206.57:9876
  producer:
    group: mayikt_producer
server:
  port: 8089

核心代码

@RestController
public class ProducerController {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @RequestMapping("/sendMsg")
    public String sendMsg() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
        Long orderId = System.currentTimeMillis();
        String insertSql = getSqlMsg("insert", orderId);
        String updateSql = getSqlMsg("update", orderId);
        String deleteSql = getSqlMsg("delete", orderId);
        Message insertMsg = new Message("mayikt-topic", insertSql.getBytes());
        Message updateMsg = new Message("mayikt-topic", updateSql.getBytes());
        Message deleteMsg = new Message("mayikt-topic", deleteSql.getBytes());
        DefaultMQProducer producer = rocketMQTemplate.getProducer();
//        producer.send(insertMsg);
//        producer.send(updateMsg);
//        producer.send(deleteMsg);
        rocketMQTemplate.getProducer().send(insertMsg
                , new MessageQueueSelector() {
                    /**
                     * @param mqs 集群队列总数
                     * @param msg 消息内容
                     * @param arg
                     * @return 传递orderId
                     */
                    @Override
                    public MessageQueue select(List<MessageQueue> mqs, Message msg,
                                               Object arg) {
                        // 该消息存放到队列0中
                        return mqs.get(0);
                    }
                }, orderId);
        rocketMQTemplate.getProducer().send(updateMsg
                , new MessageQueueSelector() {
                    @Override
                    public MessageQueue select(List<MessageQueue> mqs, Message msg,
                                               Object arg) {
                        // 该消息存放到队列0中
                        return mqs.get(0);
                    }
                }, orderId);
        rocketMQTemplate.getProducer().send(deleteMsg
                , new MessageQueueSelector() {
                    @Override
                    public MessageQueue select(List<MessageQueue> mqs, Message msg,
                                               Object arg) {
                        // 该消息存放到队列0中
                        return mqs.get(0);
                    }
                }, orderId);

        return orderId + "";
    }

    public String getSqlMsg(String type, Long orderId) {
        JSONObject dataObject = new JSONObject();
        dataObject.put("type", type);
        dataObject.put("orderId", orderId);
        return dataObject.toJSONString();
    }
}
@Service
@RocketMQMessageListener(topic = "mayikt-topic", consumerGroup = "mayiktTopic", consumeMode = ConsumeMode.ORDERLY, consumeThreadMax = 1)
public class OrderConsumer implements RocketMQListener<MessageExt> {
    // consumeMode = ConsumeMode.ORDERLY一个队列对应一个Thread线程
    // consumeThreadMax设置最大线程数

    @Override
    public void onMessage(MessageExt message) {
        System.out.println(Thread.currentThread().getName() + "," +
                "队列" + message.getQueueId() + "," + new String(message.getBody()));
    }
}
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class AppRocketMQ {
    public static void main(String[] args) {
        SpringApplication.run(AppRocketMQ.class);
    }
}

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值