十二、RocketMQ BEST PRACTICE

一、概述

这篇主要是对官网上的BEST PRACTICE进行翻译
参考链接
http://rocketmq.apache.org/docs/core-concept/
http://rocketmq.apache.org/docs/best-practice-broker/
http://rocketmq.apache.org/docs/best-practice-producer/
http://rocketmq.apache.org/docs/best-practice-consumer/
http://rocketmq.apache.org/docs/system-config/
https://www.kernel.org/doc/Documentation/sysctl/vm.txt
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/ch06s04s02.html

二、核心概念图

十二、RocketMQ BEST PRACTICE_第1张图片
RocketMQ核心概念

三、Best Practice For Broker (Broker部署最佳实践)

  • 1、broker 角色:
    ASYNC_MASTER :异步Master
    SYNC_MASTER :同步Master
    SLAVE:从Slave
    官方推荐,如果不能容忍丢失数据,建议使用 SYNC_MASTER + SLAVE 模式
    如果要效率,容忍数据丢失,可以考虑 ASYNC_MASTER + SLAVE 模式
    简单来的话,ASYNC_MASTER 模式就OK
  • FlushDiskType
    建议使用 ASYNC_FLUSH

四、Best Practice For Producer (Producer部署最佳实践)

1、SendResult返回的状态

默认情况下,isWaitStoreMsgOK = true,从名字上能看出来:是否等待消息存储完毕
这个属性如果不设置的话,只要没有异常,SendResult永远返回 SEND_OK,下面列出其他的几种返回状态:

  • FLUSH_DISK_TIMEOUT:写入磁盘超时
    如果FlushDiskType=SYNC_FLUSH(默认是ASYNC_FLUSH),并且在5秒(默认配置时间)内没有完成固化,则会返回这个状态
  • FLUSH_SLAVE_TIMEOUT:写入从机超时
    消息固化主从复制超时,返回这个错误
  • SLAVE_NOT_AVAILABLE:从机不可用
    如果配置了SYNC_MASTER,但是没有配置SLAVE,返回这个错误码
  • SEND_OK: I am fine,thank you ,and you?
    SEND_OK并不是真的OK,要想不丢数据,还是配置SYNC_MASTER 或者 SYNC_FLUSH吧

2、数据重复或丢失

如果收到了FLUSH_DISK_TIMEOUT 或者 FLUSH_SLAVE_TIMEOUT ,并且在这个时候Broker 还挂了,那么数据就丢失了。两种做法

  • 丢掉消息,不要了
  • 重新发送 重新发送需要考虑幂等性
    切记,如果出现了SLAVE_NOT_AVAILABLE,就算重发也是无济于事的,你应该检查下你的集群配置

3、 建议的消息大小

建议不要超过 512KB,并且发送的超时时间不要太小(默认是3秒),也可以通过send(msg, timeout) 在发送的时候指定超时时间,超时时间不要太小,因为发送后固化还需要一定的时间,此外,如果发送超时时间远远超过了syncFlushTimeout,那么就没啥用了,FLUSH_SLAVE_TIMEOUT 及 FLUSH_SLAVE_TIMEOUT会先于发送超时冒出来

4、Producer Group

通常情况下,这个没啥用,事务性消息才有用。通常情况下,一个JVM下(一个应用)中只需要实例化一个producer就够了,这玩意儿是线程安全的。如果数据量真的是Very Very Very Big,那么,可以建立 3~5个producer,并且通过 setInstanceName 为每一个producer指定一个Name

五、Best Practice For Consumer (消费者部署最佳实践)

切记,切记,切记,同一个Consumer Group下的消费者,必须持有相同的Topic+Tag!!!
下面这几个是官网说的,有些不太理解,先写上吧

1、消息监听器 MessageListener

  • 顺序消费
    Consumer会锁住每一个MessageQueue来保证消息的有序性,这会造成性能下降。
    消费失败的话,不建议抛出异常,建议返回 ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT
  • 并发消费
    不建议抛出异常,建议返回 ConsumeConcurrentlyStatus.RECONSUME_LATER
  • 消费状态
    对于 MessageListenerOrderly ,因为消息是有序的,所以你不能跳过,但是可以
    返回SUSPEND_CURRENT_QUEUE_A_MOMENT ,让消费者等一下
  • 阻塞
    不建议阻塞Listener,不然最终会导致线程池耗尽,消费者使用一个ThreadPoolExecutor来并发消费,可以通过 setConsumeThreadMin 和 setConsumeThreadMax来调整最小和最大线程数。

2、ConsumeFromWhere

新增一个Consumer Group,可以通过以下几个配置来决定消费的起始位置:

  • CONSUME_FROM_LAST_OFFSET :不会消费历史消息,新的消息会被消费
  • CONSUME_FROM_FIRST_OFFSET :消费所有历史消息以及新的消息
  • CONSUME_FROM_TIMESTAMP :从指定的时间戳后开始消费
    切记,无论如何还是有一定的情况产生重复数据,所以一定要做好消息的幂等。

六、Best Practice For NameServer(NameServer最佳部署实践)

NameServer主要的作用是协调,主要包含两个部分:

  • Broker定期从NameServer拉取最新的 Meta 信息
  • 为 producer、conmuser、command line client提供最新的路由信息

1、引用NameServer的方式

  • 编程方式引入
// 生产者
DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
producer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");
// 消费者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
consumer.setNamesrvAddr("name-server1-ip:port;name-server2-ip:port");
// 命令行
sh mqadmin command-name -n name-server-ip1:port;name-server-ip2:port -X OTHER-OPTION
  • Java Options(Java 属性引入)
    rocketmq.namesrv.addr = name-server-ip1:port;name-server-ip2:port
  • 环境变量引入
    NAMESRV_ADDR = name-server-ip1:port;name-server-ip2:port
    这个在第一章中使用过: export NAMESRV_ADDR=10.1.11.155:9876
  • HTTP Endpoint
    这个Endpoint我一直不知道该怎么翻译,很多源码都有这种命名
    其实上面的几种引用方式,最终(end point吧),都会调用这个方式进行指定,在启动10秒后,会调用 http://jmenv.tbsite.net:8080/rocketmq/nsaddr 更新NameSrv的配置,并且每 2分钟 扫描一次。
    在生产环境,建议使用这种方式引入NameSrv,因为他是底层的玩意儿,可以动态指定,扩展性好。
  • 优先级
    如果上面四种方式同时指定,优先级如下:
    Programmatic Way > Java Options > Environment Variable > HTTP Endpoint

七、RocketMQ JVM/Linux Configuration(JVM/操作系统配置)

官网的配置是基于 JDK1.8 的,Github上有基于 JDK1.9 的配置,JDK12的现在也应该有了吧。

1、JVM配置

  • 堆内存设置
    建议不小于8g,并且最大和最小一致(防止jvm resize影响效率)
-server -Xms8g -Xmx8g -Xmn4g
  • AlwaysPreTouch
    如果能忍受启动时间加长,可以指定AlwaysPreTouch=true,让JVM在启动的时候就将内存加载到堆中:
-XX:-UseBiasedLocking
  • 使用G1垃圾回收机制
-XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30

-XX:MaxGCPauseMillis 不要设置的太小,不然JVM 会使用 年轻代(young generation)来清理垃圾,导致频繁的 minor GC,如果写入GC文件导致Broker延迟,可以考虑使用将文件写到内存文件系统?(后续完善)

-Xloggc:/dev/shm/mq_gc_%p.log

2、Linux Kernel Parameters (Linux内核参数设置)

在bin目录下的os.sh是一些操作系统的最低配置,下面列出一些需要特别注意的配置:
这些参数不太熟悉,生产环境配置的时候补充近来

  • vm.extra_free_kbytes
  • vm.min_free_kbytes
  • vm.max_map_count
  • vm.swappiness
  • File descriptor limits
    建议大小 655350
  • Disk scheduler
    参考链接:
    https://www.kernel.org/doc/Documentation/sysctl/vm.txt
    https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/ch06s04s02.html

你可能感兴趣的:(十二、RocketMQ BEST PRACTICE)