RocketMQ 消息队列中间件

一、初识 RocketMQ

1、MQ简介

 MQ:MessageQueue 消息队列。是在互联网中广泛使用的一系列服务中间件。

  1. Message:信息。在不同进程间传递的数据。可以部署在不同机器上,也可在不同部分上。
  2. Queue:队列。原本指的是一种FIFO的数据结构,用来缓存数据。对于该服务中间件来讲,FIFO特性是否存在尚且考量,但服务中间件具有存储消息,让消息排队的能力。

  消息队列的三大作用:

  1. 异步:


    作用:异步能提高系统的响应速度、吞吐量。
     
  2. 解耦:
     

    作用:提高系统整体性和可扩展性。实现数据分发,生产者发送一个消息后,可以由一个或者多个消费者进行消费,且消费者的变化对于生产者没有任何影响。
     
  3. 削峰:

    以稳定的系统资源应对突发的流量冲击

 2、运行架构和消息队列

Topic只是逻辑存在的,真正存储消息的是MessageQueue,可以由可视化工具发现:Topic只作区分作用。

3、Kafka、RabbitMQ、RocketMQ、Plusar四者区别

二、Linux虚拟机部署

1、官网下载并进行安装(略) 

2、修改文件

  使用 vi runserver.sh 和 vi runbroker.sh指令进行修改:由于中间件自己配置的内存过大,除了硬件水平较高的Linux机器,虚拟机建议降低一些配置。如图:4g改为了1g,1g改为了512mb

3、启动服务

  运行如下指令,在Linux上启动NameServer服务: 

  运行如下指令,在配置好环境后在Linux上启动Broker服务: 

      进入vim配置环境     加载环境配置

  启动broker 
jps指令查看运行程序:

4、安装可视化工具

  在官网下载下来后,在idea里面package 并上传到服务器

修改打包后的jar包的application.yml配置文件,可以在目录下新建个配置文件,只写修改的部分即可。这里的vi application,yml就是这样


启动成功~~~

5、升级我的MQ - 分布式集群 

  要想布置多台NameServer和Broker需要多台Linux服务器。

  Producer和Consumer只需要和NameServer打交道,NameServer管理着Broker的信息。从单一到集群后,这样即使一个挂了,其他的也能继续工作,维护Broker

  Broker采用主从结构,指定一部分节点为Master,负责响应客户端请求。指令另一部分节点为Slave,负责备份Master的内容以防止意外发生后的损失。

例子:

  具体步骤:

  1.  部署NameServer服务 : 不需要特别配置,几台机器分别进行部署即可
  2.  对Broker服务进行集群配置: 这里再RocketMQ目录的conf下有着多样的配置模板
    1. 2m-noslave:2主无从,易产生单点故障。
    2. 2m-2s-async和2m-2s-sync:2主2从的集群配置。async和sync表示的是主从之间的同步关系是同步还是异步的。
    3. Dledger:具备主从切换功能的高可用集群。

6、总结

 这里由于虚拟机限制,我只进行阐述。

采用非Dledger的方式进行集群时,比如这里的:若worker2意外断开,则worker3虽然有broker-a的slave(备份),但因为只有master才能响应客户端的请求,因此并不具备高可用性。 

 这是Dledger的一个配置文件(Dledger需要在集群所有机器中部署),其中dLegerSelfId=n0就是该机器的唯一标识。在conf目录下新建broker.conf文件即可覆盖更新。

  消灭掉一个应用后,RocketMQ会使用Raft算法推举另一个机器为master ,注意:只允许半数机器运行正常时生效,否则slave还是slave。这也是为什么多数企业布置奇数个服务器(偶数多了一个也无法延长生效数嘛)。

  Dledger集群的所有机器都要同步来自客户端的消息日志文件,导致机器间要进行的网络操作很多,这不仅是极其耗时的,也是不安全的,因此该集群方式并不推荐。那么该采用什么方式呢?不要忘了我们的需求:能够在master挂掉的时候将他的slave推举为master即可。后续会有升级版的2m-2s-async和2m-2s-sync等着我们学习。

  NameServer的高可用性则做到了极致:因每个broker都会与所有NameServer建立长连接,定时注册Topic信息到所有NameServer上,因此只要存活一个NameServer就能使RocketMQ正常工作 

 三、客户端消息确认机制

1、Producer端的三种发送机制

  1. sendOneway(msg);只考虑发送,其他一概不知,因此性能最为彪悍;
  2. 返回值类型为SendResult类的send(msg)方法:考虑接收(send方法会接收来自consumer的响应),最为安全
  3. 最后一个:异步操作,new一个SendCallBack类进行监听,性能和安全性适中,但需要设定个时间间隔来长时间维护一个producer(多线程异步操作下,若没有一定的时间间隔让监听类完成工作,那么producer关闭后,该监听类也会立马shutdown,因此无法得到响应),其他都是用完立刻shutdown就行

2、Consumer端的接收机制

  这里的CONSUME_SUCCESS是枚举值,点击前面的状态类可以看到其他的响应值。 

一般一次消费通常会因为各种原因无法消费到所有的消息,也就是消费者位点偏离代理者位点的值,此时所有差值的和叫做延迟,当你下次启动consumer时,便会只消费延迟。 

FIRST_OFFSET意味着从头开始消费,还有LAST_OFFSET(注意:若最小位点是0,那么该配置无法生效),还有时间戳配置(不常用) 

其实上述配置有没有理解并不重要,重要的是实际开发中要关注消费者位点的变化,那是跟Consumer所需求的消息密切相关的。

3、广播模式

  在集群模式下,生产者发出的消息只会被消费者组中的某些个消费者接收;而广播模式则会将消息转发给所有关注该topic的消费组的所有消费者 

  在消费者实例中设置如下信息即可开启广播模式。

 设置好广播模式后,若生产者发送一条消息后,消费者收到后会在本地建立一个以该消费组组名命名的json文件,里面会随时更新消费者位点记录(每多发一条消息某个消费者就会提高他的消费者位点嘛),而服务器是不知道的,因此当你在消费者监听里面设置LATER(不停的回调消费者位点差值的消息)时,由于服务器并不知道最新的消费者位点是多少是谁的差值是多少,因此无法进行回调。

  有点破罐子破摔的感觉:对于不敏感的信息可以采用广播模式传给所有人,也有点懒散的感觉(懒得维护信息和顺序)。

4、过滤消息机制

  Topic能够做到区分许多消息的不同,但终究还是不够惊喜,这里就用到了Tag标签来过滤。

1、TagFilter

Producer:

 Consumer:只订阅tag为A和C的 

2、SqlFilter(能够接受更加复杂的过滤条件 )

  相比Tag能耗能多,Tag几乎可以忽略不记

  ShardingSphere来写即可。

  过滤只影响Consumer端接收的信息,broker该传送的还是会传送的,本地文件该维护也会去维护

5、顺序消息机制(!!!)

   当我使用生产者发送了20条订单Topic,每条有五个操作步骤的tag,共100条消息。由于我的模拟发送其实就是嵌套for循环,所以发送的顺序肯定是有序的。而如果使用之前我们认知里的Consumer进行接收时,会是无序的,订单的操作步骤必须是局部有序(业务步骤的顺序肯定是从小到大,但无法保证所有业务执行时间点的有序)的,因此我们要解决这个问题。

   假如我的某条队列里的某个操作失败了,普通Consumer里会跳过这个操作执行队列的下一条,这显然也是不行的。因此这里用到了SUSPEND整个队列的配置来暂停该队列。

  在最新版本的RocketMQ版本里,只需要为你的队列设置同样的组名即可实现有序。

        //顺序消息发送。
        MessageBuilder messageBuilder = new MessageBuilderImpl();;
        Message message = messageBuilder.setTopic("topic")
                //设置消息索引键,可根据关键字精确查找某条消息。
                .setKeys("messageKey")
                //设置消息Tag,用于消费端根据指定Tag过滤消息。
                .setTag("messageTag")
                //设置顺序消息的排序分组,该分组尽量保持离散,避免热点排序分组。
                .setMessageGroup("fifoGroup001")
                //消息体。
                .setBody("messageBody".getBytes())
                .build();
        try {
            //发送消息,需要关注发送结果,并捕获失败等异常
            SendReceipt sendReceipt = producer.send(message);
            System.out.println(sendReceipt.getMessageId());
        } catch (ClientException e) {
            e.printStackTrace();
        }
        //消费顺序消息时,需要确保当前消费者分组是顺序投递模式,否则仍然按并发乱序投递。
        //消费示例一:使用PushConsumer消费顺序消息,只需要在消费监听器处理即可。
        MessageListener messageListener = new MessageListener() {
            @Override
            public ConsumeResult consume(MessageView messageView) {
                System.out.println(messageView);
                //根据消费结果返回状态。
                return ConsumeResult.SUCCESS;
            }
        };
        //消费示例二:使用SimpleConsumer消费顺序消息,主动获取消息进行消费处理并提交消费结果。
        //需要注意的是,同一个MessageGroup的消息,如果前序消息没有消费完成,再次调用Receive是获取不到后续消息的。
        List<MessageView> messageViewList = null;
        try {
            messageViewList = simpleConsumer.receive(10, Duration.ofSeconds(30));
            messageViewList.forEach(messageView -> {
                System.out.println(messageView);
                //消费处理完成后,需要主动调用ACK提交消费结果。
                try {
                    simpleConsumer.ack(messageView);
                } catch (ClientException e) {
                    e.printStackTrace();
                }
            });
        } catch (ClientException e) {
            //如果遇到系统流控等原因造成拉取失败,需要重新发起获取消息请求。
            e.printStackTrace();
        }

6、延迟消息 与 批量消息

7、事务消息机制

   下面的例子有助于进一步的理解:

 

 下面是一道阿里的面试题,挑错。这里的话就是MySQL可以正常回滚进行事务的处理,但消息却无法同步。假如请求第三方支付服务失败,报错了,那么数据库可以回滚但消息却无法进行回滚,因此需要加入RocketMQ的事务处理机制。

8、ACL权限控制体系(不常用)

   除非要进行跨部门甚至跨公司的合作,一般用不到。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值