RocketMQ基本概念及优化

RocketMQ

一、RocketMQ基本组成

1、基本组成

在了解Rocket架构之前,我们先了解下RocketMQ中,各个角色分别是干什么的,起到了一个什么作用。

I、NameServer

1、主要用于存储topic,broker的关系,功能类似于zookeeper。

2、NameServer之间互相不通信,支持集群,一个挂掉之后不会影响其他的节点。

3、当Producer和Consumer都获取到Broker的信息后,就算NameServer宕机,也不会影响使用,但是路由信息未注册的,也就是在NameServer宕机之后注册的Producer、Consumer和Broker都是不能够正常工作的。

4、NameServer无状态,NameServer中存储的Broker、Topic的信息并不会持久化的存储,而是动态随Broker的上报而进行改变,虽然NameServer自身支持持久化的配置,但是一般意义不大。

5、Broker向NameServer发送心跳包时,会带上所有的Topic信息,如果Topic的信息量太大,而网络条件却又不太好时,就会导致心跳检测失败,NameServer会误以为Broker已经挂掉。

II、Broker

1、消息容器,接收provider推送的消息,并将对应的消息转发给指定的consumer消费,Broker就相当于时RocketMQ的处理逻辑的服务器。

	A、消息顺序写:在消息的写入过程中,所有的Topic共用一个文件,该文件大小为1G,如果文件大小没有满,是不会写入新的文件中的,这样能够保证顺序写盘,提高发消息的TPS;

	B、消息跳跃读:MQ读取消息依赖系统PageCache,PageCache命中率越高,读性能越高,Linux平时也会尽量预读数据,使得应用直接访问磁盘的概率降低。

(参见:https://blog.csdn.net/javahongxi/article/details/72956619)

2、负载均衡与动态伸缩

消息是存在queue中的,想要有更大的吞吐量,可以增加queue的数量,也可以增加Broker节点数量。

	A、如果Topic的消息量比较大,但是该集群节点的压力并不是很大,可以增加该Topic下面的queue数量,Topic的队列数跟发送、消费速度成正比。

	B、如果集群cpu的使用率已经到达85%以上,那么就需要通过增加集群节点来提高吞吐量,现有的节点数量已经无法满足业务需求了。

3、高可用、高可靠

	A、高可用:搭建集群,一台服务器宕机并不会影响整体的服务。

	B、高可靠:数据不允许丢失,有可靠的持久化机制。

4、心跳机制

心跳机制分为两个方面:

	A、Broker每隔30s向NameServer发送心跳包,包含改Broker所有的Topic信息。

	B、NameServer查询Broker心跳情况,如果某个Broker在2分钟内没有心跳,则认为该Broker已经宕机。

III、Producer

消息的生产者,一般有业务发起的一端发送MQ消息。

1、Producer Group

一类消费的的集合,一般发送同一类消息,且发送逻辑一致。

2、Producer的心跳机制

	A、Producer在启动的时候需要指定NameServer,启动后与NameServer保持长连接,并每隔30s从NameServer获取Topic的队列情况,获取到当前消费Topic和Broker的信息后,与相关的Broker保持长连接。

	B、Producer每隔30s向Broker发送心跳包,同时Broker也会每隔10s扫描一次当前的Producer,如果2分钟没有发生心跳,那么认为该Producer已经移除,将会断开连接。

3、Producer生产消息

发送消息是可以选择消息的类型,默认Producer会轮流向Broker发送消息,以达到负载均衡的目的。

(Producer发送的相关知识可以参考这篇博客:https://blog.csdn.net/a1084986263/article/details/81223689)

IV、Consumer

消息的消费者,一般由后台系统异步消费消息。

1、Consumer Group

概念与Producer Group类同。

2、Consumer心跳机制

概念与Producer类同。

3、Consumer消费模式

	A、MQPullConsumer:由用户控制线程,主动从服务端获取消息,需要自己维护offset,编程难度较大,不推荐使用。

	B、MQPushConsumer:底层同样由pull实现,由用户注册的MessageListener来消费消息,不用自己维护offset。

2、基本架构(来自RocketMQ官网)

在这里插入图片描述

在图中我们可以看到四个角色都可以搭建集群。

Producer和Consumer这个不用多说,可以通过我们业务系统的节点数控制,同时也可以增加Group中的成员数量来控制。

NameServer搭建集群的时候每个节点都会拥有一份完整的信息,所以一个NameServer宕机并不会影响整个系统的工作,同时为了做容灾,我们可以将NameServer的服务器不布在统一地区。

Broker可以可以通过增加Broker的数量来保证系统的吞吐量,同时也可以使用主从模式增加系统的可靠性,具体的配置在RocketMQ的包里面有示例。

二、RocketMQ优化

1、Producer优化

	1、一个应用尽可能只用一个 Topic,消息自类型可以用tags来标示,tags可以有应用自由设置,只需要producer和consumer使用一样的即可;

	2、发送消息时,尽量设置keys,这样方便定位消息丢失的问题,例如可以使用订单id这样的主键作为消息的keys,因为keys是一种哈希索引,保证keys的唯一行可以在最大程度上避免哈希冲突。

	3、如果消息的可靠性要求比较高,可以打印出消息日志进行追踪和定位。

	4、如果消息属于同一个tag,同时消息的信息量又比较大,我们可以通过发送批量消息进行处理,提升性能。

	5、建议消息大小不超过512K。

	6、发送消息有同步和异步两种方式,如果对消息的性能要求比较高,可以使用异步的方式,因为同步发送的方式会阻塞。

	7、send发送消息时,不抛异常,就代表发送成功。但是可以定义更加明确的返回状态。

在这里插入图片描述

	8、对于消息不可丢失的业务,例如转账,必须使用消息重发机制。

在这里插入图片描述
具体可参照分布式事务MQ保证一致性的做法,维护一张中间表保证事务的最终一致性。

2、Consumer优化

	1、消费组和订阅

在这里插入图片描述
2、消息监听器

在这里插入图片描述

public class Consumer {
    public static final String NAME_SERVER_ADDR = "*.*.*.*:9876";
    public static void main(String[] args) throws MQClientException {
        // 1. 创建消费者(Push)对象
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("GROUP_TEST");
        // 2. 设置NameServer的地址,如果设置了环境变量NAMESRV_ADDR,可以省略此步
        consumer.setNamesrvAddr(NAME_SERVER_ADDR);
        // 消费重试次数 -1代表16次
        consumer.setMaxReconsumeTimes(-1);
        // 3. 订阅对应的主题和Tag
        consumer.subscribe("TopicTest", "*");
        // 4. 注册消息接收到Broker消息后的处理接口
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
                try {
                    MessageExt messageExt = list.get(0);
                    System.out.printf("线程:%-25s 接收到新消息 %s --- %s %n", Thread.currentThread().getName(), messageExt.getTags(), new String(messageExt.getBody(), RemotingHelper.DEFAULT_CHARSET));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                return ConsumeConcurrentlyStatus.RECONSUME_LATER;
            }
        });
​
        // 5. 启动消费者(必须在注册完消息监听器后启动,否则会报错)
        consumer.start();
​
        System.out.println("已启动消费者");
    }
}
	 当消息消费失败时,消息的存储方式将会发生改变,当前的消息会变为一个延时消息,默认等级为3,延时时间为10s,并且随着消费失败的次数提升延时消息的等级,设置-1的时候默认尝试重新消费16次。

在这里插入图片描述
非顺序消息,如果处理慢,可以自己重新开一个线程,不要阻塞队列,但是如果是顺序消息,开启线程并不能够解决阻塞问题。
在这里插入图片描述

3、JVM和Linux配置

	1、JVM配置

在这里插入图片描述

	2、Linux配置

在这里插入图片描述
如果不清楚Linux配置和原理,最好保持默认参数。

发布了10 篇原创文章 · 获赞 23 · 访问量 941

猜你喜欢

转载自blog.csdn.net/yangchenhui666/article/details/90812746