RocketMQ部署以及调优
RocketMQ的部署
RocketMQ的部署,这里不做太多的说明,因为官方文档上面写的已经非常清晰了,可以照着官方文档一顿操作,下面为官方文档的地址:
https://github.com/apache/rocketmq/tree/master/docs/cn
RocketMQ的调优
RocketMQ的调优其实在官方文档的最佳实践中也写的挺清晰的,可以直接参考官方文档,笔者记录的这主要是自己消化后,自己理解的一些东西。
对RocketMQ集群OS内核参数对调整
备注:以下几个参数对所有的中间件都起作用,比如redis、kafka等
-
vm.overcommit_memory
使用如下命令进行调整
echo 'vm.overcommit_memory=1' >> /etc/sysctl.conf
该参数有三个值可以选择:0、1、2
"0":在中间件系统申请内存对时候,os内核会检查可用内存是否足够,如果足够的话就分配给你,如果感觉剩余内存不是太够,干脆就直接拒绝申请,从而导致中间件申请内存失败,出现异常。
"1":所有可用的物理内存都允许分配给你,只要有内存就给你用,这样可以避免内存申请失败的问题,一般将这个参数的值调整为1。
"2":表示内核允许分配超过所有物理内存和交换空间总和的内存
-
vm.max_map_count
使用如下命令进行调整
echo 'vm.max_map_count=655360' >> /etc/sysctl.conf
该参数影响中间件系统可以开启线程的数量,如果参数的值太少,可能会造成有些中间无法开启足够的线程,从而导致出错,然后使中间件系统挂掉。该参数的默认值为:65536,这个默认值有时候是不够的,建议这个参数值调大10倍,为655360。
-
vm.swappiness
使用如下命令进行调整
echo 'vm.swappiness=10' >> /etc/sysctl.conf
该参数是用来控制swap行为的,这个简单的来说,就是os会把一部分磁盘空间作为swap区域,然后如果有的进程现在可能是不太活跃,就会被操作系统把进程调整为睡眠状态,把进程中的数据放入磁盘上的swap区域,然后让该进程原来占有的内存空间腾出来,交给其他活跃的进程来使用。
将该参数的值设置为0:意思就是尽量别把任何一个进程放到磁盘swap区域,尽量大家都用物理内存。
将该参数的值设置为100:意思是尽量把一些进程给放到swap区域去,内存腾出来给活跃的进程使用。
默认该参数的值为60:有点偏高,可能会导致我们的中间件运行不活跃的时候被迫腾出内存空间然后放磁盘swap区域去。因此一般在生产环境建议将该值调小一些,比如10,让进程尽量使用物理内存,别放磁盘swap区域去。
-
ulimit
使用如下命令进行调整
echo 'ulimit -n 1000000' >> /etc/profile
该参数是用来控制linux上的最大文件链接数的,默认值为1024,一般肯定是不够的,因为在大量频繁的读写磁盘文件的时候或进行网络通信的时候,都会和这个参数有关系。如果采用默认值,可能会出现如下错误:error: too many openfiles。
总结:
- 中间件系统如果要开启大量的线程对应的os内核参数:跟vm.max_map_count有关
- 如果有大量的网络通信和磁盘io:跟ulimit有关
- 大量的使用内存:跟vm.swappiness和vm.overcommit_memory有关
对JVM的调优
因为RocketMQ是用java语言编写的所以在启动的时候需要使用虚拟机,所以对JVM进行调优。
在runbroker.sh启动脚本中可以看到如下内容:
JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g -Xmn4g"
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0"
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/mq_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy"
JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch"
JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=15g"JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking"
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"
#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"
对上面参数对解释:
-server:以服务器的模式启动。
-Xms8g -Xmx8g -Xmn4g: 默认的堆大小是8g,新生代是4g,这里根据实际生产服务器的内存大小,然后进行调整,比如:物理机是48g内存,堆内存可以给到20g,新生代给到8g,剩下的一些留给操作系统。
-XX:+UseG1GC -XX:G1HeapRegionSize=16m:选择G1垃圾回收器来做分代回收,对新生代和老年代都用G1回收。这里把G1的region设置为16m,是因为物理内存比较大,如果物理内存不多时,可以设置成2m,设置大,是可以防止region数量过多。region的含义是:G1的各代存储地址是不连续的,每一代都使用了n个不连续的大小相同的Region,每个Region占有一块连续的虚拟内存地址,如下图所示:
-XX:G1ReservePercent=25:在G1管理的老年代里预留25%的空闲内存,保证新生代对象,晋升到老年代代时候有足够的空间,避免老年代内存都满了,新生代进入代老年代没有足够的内存。默认值为10%,略微偏小,所以这里给增加了一些,在RocketMQ中。
-XX:InitiatingHeapOccupancyPercent=30:当堆内存的使用率达到30%之后,就会自动启动G1的并发垃圾回收,开始尝试回收一些垃圾对象。默认值为45%,RocketMQ给调低了一些,提高了GC的频率,避免垃圾对象太多时,一次垃圾回收时间太长问题。
-XX:SoftRefLRUPolicyMSPerMB=0 :该参数默认值为0,建议这个参数不要设置成0,避免频繁回收一些软引用的Class对象,这里可以调整为比如1000
-verbose:gc -Xloggc:/dev/shm/mq_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy"
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m":这些参数是控制GC日志的输出,确定GC日志文件的地址,要打印那些信息,然后控制每个GC日志文件的大小是30m,最多保留5个GC日志文件。
-XX:-OmitStackTraceInFastThrow:有时候JVM会抛弃一些异常的堆栈信息,设置这个参数之后,就是告诉JVM不能丢弃这些异常堆栈信息,需要打印完整的异常堆栈信息。
-XX:+AlwaysPreTouch:不设置该参数的时候,对象首先会先分配在年轻代,因为之前在程序启动的时候分配的只是虚拟内存,所以每次新建对象都需要操作系统来先分配物理内存,分配对象速度自然就降低了,只有等第一次新生代GC后,该被分配的内存空间都已经分配了,之后分配对象的速度才会加快。那么老年代也是同理,老年代的空间何时真正使用,自然是对象需要晋升到老年代时,所以新生代GC的时候,对象要从新生代晋升到老年代,操作系统也需要为老年代先分配物理内存,这样就间接影响了新生代GC的效率。
设置该参数之后,就是让程序启动的时候真实的分配物理内存给JVM,而不是虚拟内存,优点的是加快代码的运行效率,缺点是影响jvm进程的启动时间,导致启动的时间降低几个数量级。
-XX:MaxDirectMemorySize=15g:RocketMQ中大量用了NIO中的direct buffer,这里限定了direct buffer最多申请多少,如果物理机器的内存比较大,可以适当的调大该值。
-XX:-UseLargePages -XX:-UseBiasedLocking:禁用大内存页和偏向锁。
对RocketMQ核心参数的调整
在rocketmq/distribution/target/apache-rocketmq/conf/dledger目录下面的配置文件中,可以找到sendMessageThreadPoolNums=16参数,该参数的意思是:RocketMQ内部用来发送消息的线程池的线程数量,默认是16,如果机器的CPU是24核的话,该参数的值可以设置成24或者30