rocketmq 参数调优

277 阅读10分钟

2、对RocketMQ集群进行OS内核参数的调整

(1)vm.overcommit_memory (2)vm.max_map_count (3)vm.swappiness (4)ulimit

(1)vm.overcommit_memory

“vm.overcommit_memory”这个参数有三个值可以选择,0、1、2。

如果值是0的话,在你的中间件系统申请内存的时候,os内核会检查可用内存是否足够,如果足够的话就分配内存给你,如果感觉剩余 内存不是太够了,干脆就拒绝你的申请,导致你申请内存失败,进而导致中间件系统异常出错。

因此一般需要将这个参数的值调整为1,意思是把所有可用的物理内存都允许分配给你,只要有内存就给你来用,这样可以避免申请内 存失败的问题。

比如我们曾经线上环境部署的Redis就因为这个参数是0,导致在save数据快照到磁盘文件的时候,需要申请大内存的时候被拒绝了,进 而导致了异常报错。

可以用如下命令修改:echo 'vm.overcommit_memory=1' >> /etc/sysctl.conf。

(2)vm.max_map_count

这个参数的值会影响中间件系统可以开启的线程的数量,同样也是非常重要的

如果这个参数过小,有的时候可能会导致有些中间件无法开启足够的线程,进而导致报错,甚至中间件系统挂掉。 他的默认值是65536,但是这个值有时候是不够的,比如我们大数据团队的生产环境部署的Kafka集群曾经有一次就报出过这个异常,

说无法开启足够多的线程,直接导致Kafka宕机了。 因此建议可以把这个参数调大10倍,比如655360这样的值,保证中间件可以开启足够多的线程。

可以用如下命令修改:echo 'vm.max_map_count=655360' >> /etc/sysctl.conf。

(3)vm.swappiness

这个参数是用来控制进程的swap行为的,这个简单来说就是os会把一部分磁盘空间作为swap区域,然后如果有的进程现在可能不是太 活跃,就会被操作系统把进程调整为睡眠状态,把进程中的数据放入磁盘上的swap区域,然后让这个进程把原来占用的内存空间腾出 来,交给其他活跃运行的进程来使用。

如果这个参数的值设置为0,意思就是尽量别把任何一个进程放到磁盘swap区域去,尽量大家都用物理内存。

如果这个参数的值是100,那么意思就是尽量把一些进程给放到磁盘swap区域去,内存腾出来给活跃的进程使用。 默认这个参数的值是60,有点偏高了,可能会导致我们的中间件运行不活跃的时候被迫腾出内存空间然后放磁盘swap区域去。

因此通常在生产环境建议把这个参数调整小一些,比如设置为10,尽量用物理内存,别放磁盘swap区域去。

可以用如下命令修改:echo 'vm.swappiness=10' >> /etc/sysctl.conf。

(4)ulimit

这个是用来控制linux上的最大文件链接数的,默认值可能是1024,一般肯定是不够的,因为你在大量频繁的读写磁盘文件的时候,或 者是进行网络通信的时候,都会跟这个参数有关系

对于一个中间件系统而言肯定是不能使用默认值的,如果你采用默认值,很可能在线上会出现如下错误:error: too many open files。

因此通常建议用如下命令修改这个值:echo 'ulimit -n 1000000' >> /etc/profile。

3、对JVM参数进行调整 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="JAVAOPTXX:+UseGCLogFileRotationXX:NumberOfGCLogFiles=5XX:GCLogFileSize=30m"JAVAOPT="{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="JAVAOPTDjava.ext.dirs={JAVA_OPT} -Djava.ext.dirs={JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"

#JAVA_OPT="JAVAOPTXdebugXrunjdwp:transport=dtsocket,address=9555,server=y,suspend=n"JAVAOPT="{JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n" JAVA_OPT="{JAVA_OPT} ${JAVA_OPT_EXT}"

JAVA_OPT="JAVAOPTcp{JAVA_OPT} -cp {CLASSPATH}"

-server -Xms8g -Xmx8g -Xmn4g -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 - XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -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 -XX:-OmitStackTraceInFastThrow - XX:+AlwaysPreTouch -XX:MaxDirectMemorySize=15g -XX:-UseLargePages -XX:-UseBiasedLocking

-Xms8g -Xmx8g -Xmn4g:这个就是很关键的一块参数了,也是重点需要调整的,就是默认的堆大小是8g内存,新生代是4g内存, 但是我们的高配物理机是48g内存的

这些是Java虚拟机(JVM)的启动参数,用于配置堆内存的初始大小(-Xms)、最大大小(-Xmx)和新生代(Young Generation)的大小(-Xmn)。

-XX:+UseG1GC -XX:G1HeapRegionSize=16m:这几个参数也是至关重要的,这是选用了G1垃圾回收器来做分代回收,对新生代 和老年代都是用G1来回收

这里把G1的region大小设置为了16m,这个因为机器内存比较多,所以region大小可以调大一些给到16m,不然用2m的region,会 导致region数量过多的

-XX:G1ReservePercent=25:这个参数是说,在G1管理的老年代里预留25%的空闲内存,保证新生代对象晋升到老年代的时候有足 够空间,避免老年代内存都满了,新生代有对象要进入老年代没有充足内存了

默认值是10%,略微偏少,这里RocketMQ给调大了一些

G1ReservePercent是G1垃圾回收器的一个参数,用于配置G1垃圾回收器在JVM堆中保留的未使用空间的百分比。具体来说,这个参数指定了G1垃圾回收器在堆的预留空间的比例,这些空间不会被G1回收器使用,而是留作备用,以应对意外情况或者应用程序需求的突发增长。

通常情况下,G1ReservePercent的默认值是10%,即G1垃圾回收器默认将堆的10%作为预留空间。这意味着即使在堆的最大使用量达到限制时,G1垃圾回收器也会保留10%的空间,以应对额外的垃圾收集需求或者其他紧急情况。

通过调整G1ReservePercent参数,可以根据应用程序的需求和性能特征来调整G1垃圾回收器的行为,以达到更好的性能和稳定性。

-XX:InitiatingHeapOccupancyPercent=30:这个参数是说,当堆内存的使用率达到30%之后就会自动启动G1的并发垃圾回收,开 始尝试回收一些垃圾对象

InitiatingHeapOccupancyPercent是G1垃圾回收器的一个参数,用于指定G1垃圾回收器在何时启动混合收集(Mixed Collection)阶段。混合收集是G1垃圾回收器的一种特性,它允许在不同的区域采用不同的垃圾收集方式,以提高性能和减少暂停时间。

该参数指定了当堆内存中的某个区域达到指定的内存利用率时,G1垃圾回收器将启动混合收集阶段。具体来说,InitiatingHeapOccupancyPercent参数指定了堆内存被使用的百分比阈值。当堆内存使用达到或超过这个百分比时,G1垃圾回收器将启动混合收集以回收内存。

默认情况下,InitiatingHeapOccupancyPercent参数的值是45%,即当堆内存利用率达到45%时,G1垃圾回收器将启动混合收集阶段。您可以根据应用程序的内存使用情况和性能需求来调整这个值,以达到更好的性能和稳定性。通常情况下,您可能需要在实际生产环境中进行调整和测试。

-XX:SoftRefLRUPolicyMSPerMB=0:这个参数默认设置为0了,在JVM优化专栏中,救火队队长讲过这个参数引发的案例,其实建 议这个参数不要设置为0,避免频繁回收一些软引用的Class对象,这里可以调整为比如1000

当SoftRefLRUPolicyMSPerMB参数的值被设置为0时,表示禁用了软引用对象的存活时间限制。换句话说,软引用对象将不受存活时间的限制,即它们可以在内存不足时一直保持存活状态,直到垃圾回收器确定它们是可以被回收的为止。

设置SoftRefLRUPolicyMSPerMB为0可能会导致应用程序在内存不足时出现更多的内存压力,因为软引用对象不再受到存活时间的限制,可能会长时间占用内存资源。这可能会影响应用程序的性能和稳定性,特别是在内存受限的环境下。

通常情况下,除非有特定的需求,否则不建议将SoftRefLRUPolicyMSPerMB设置为0。相反,建议根据应用程序的内存使用情况和性能需求,合理地设置软引用对象的最大存活时间,以平衡内存利用率和性能。

-XX:+AlwaysPreTouch:这个参数的意思是我们刚开始指定JVM用多少内存,不会真正分配给他,会在实际需要使用的时候再分配给 他

所以使用这个参数之后,就是强制让JVM启动的时候直接分配我们指定的内存,不要等到使用内存的时候再分配 AlwaysPreTouch是Java虚拟机(JVM)的一个参数,用于在Java应用程序启动时预先分配堆内存,以确保物理内存与虚拟内存之间的一致性。在某些情况下,如果没有预先分配内存,当Java应用程序开始使用堆内存时,操作系统可能需要花费额外的时间来动态分配和映射物理内存,这可能导致应用程序的性能下降。

当您设置AlwaysPreTouch参数为true时,Java虚拟机会在启动时立即分配并初始化整个堆内存。这意味着在应用程序启动时,Java虚拟机会迭代整个堆内存并访问每个内存页,从而导致操作系统分配和映射所有堆内存的物理页,确保了后续对堆内存的访问不会受到额外的延迟影响。

尽管AlwaysPreTouch可以帮助减少应用程序启动过程中的内存访问延迟,但它可能会导致启动时间增加,特别是对于大型堆内存来说。因此,是否启用AlwaysPreTouch应该根据具体应用程序的需求和性能特征进行评估。对于需要优化应用程序启动性能并且可以接受稍长启动时间的情况,可以考虑启用AlwaysPreTouch。

-XX:MaxDirectMemorySize=15g:这是说RocketMQ里大量用了NIO中的direct buffer,这里限定了direct buffer最多申请多少, 如果你机器内存比较大,可以适当调大这个值,

-XX:-UseLargePages -XX:-UseBiasedLocking:这两个参数的意思是禁用大内存页和偏向锁,这两个参数对应的概念每个要说清楚 都得一篇文章,所以这里大家直接知道人家禁用了两个特性即可。

4、对RocketMQ核心参数进行调整

之前讲解集群部署的时候给大家提过,在下面的目录里有dledger的示例配置文件:rocketmq/distribution/target/apache- rocketmq/conf/dledger

在这里主要是有一个较为核心的参数:sendMessageThreadPoolNums=16 这个参数的意思就是RocketMQ内部用来发送消息的线程池的线程数量,默认是16 其实这个参数可以根据你的机器的CPU核数进行适当增加,比如机器CPU是24核的,可以增加这个线程数量到24或者30,都是可以 的。