十二、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 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