暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

【Elasticsearch运维系列】Elasticsearch7.12.1启动指定版本JDK:你学废了吗?

2569

一、背景

一套生ES集群,版本为7.12.1,近期频繁告警,频繁出现索引分片异常,索引状态异常,导致应用无法正常写入ES,另外,也经常出现节点掉问题。通过分析相关ES日志,显示和当前JAVA GC有关。当前ES曾经过升级,从ES 6升级到ES 7,在ES应用服务器上除了部署ES本身,还部署运行了其它应用进程。为了方便JAVA管理,ES和其它应用都使用了相同的JDK,版本为1.8.0_202。而ES 7 在启动时会提示建议使用 JDK 11及以后版本。 因为采用JDK 1.8,GC垃圾回收还采用的是CMS方式,如下所示: [root@localhost ~]# java -XX:+PrintFlagsFinal -version | grep Use.*GC.*=.*true bool UseAdaptiveSizeDecayMajorGCCost = true {product} bool UseGCOverheadLimit = true {product} bool UseMaximumCompactionOnSystemGC = true {product} bool UseParallelGC := true {product} bool UseParallelOldGC = true {product} java version "1.8.0_202" Java(TM) SE Runtime Environment (build 1.8.0_202-b08) Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode) 当前JDK 1.8的JAVA_HOME是配置在/etc/profile文件中,作为全局变量使用的,如下所示: export JAVA_HOME=/usr/java/jdk1.8.0_221 export ES_JAVA_HOME=/usr/java/jdk1.8.0_221 export PATH=$ES_JAVA_HOME/bin:$PATH export PATH=$JAVA_HOME/bin:$PATH export JAVA8_HOME=/opt/lib/jdk1.8.0_202 CLASSPATH=/opt/lib/jdk1.8.0_202/lib JDK_HOME=/opt/lib/jdk1.8.0_202 JAVA_HOME=/opt/lib/jdk1.8.0_202 PATH=/opt/lib/jdk1.8.0_202/bin:/opt/lib/jdk1.8.0_202/jre/bin:$PATH export CLASSPATH JAVA_HOME JDK_HOME PATH 在和研发等相关人员分析沟通近期问题后,建议将ES采用自带的JDK,并将GC垃圾回收调整为 G1GC,并且对JDK的调整不能影响到当前ES服务器上的其它应用对原JDK 1.8版本的使用。 当前ES启动后信息如下:

image20240508102259141.png

二、测试过程

如何调整ES使用指定的JDK版本启动呢,我查询了相关资料,显示可以修改/bin/elasticsearch文件,在该文件中加入指定的JAVA_HOME,于是按照相关文档,我在测试环境上进行了验证,测试环境版本和生产版本相同。 为方便修改和管理,我将ES自带的JDK目录拷贝到了当前用户家目录下,如下所示: cp -a /home/esuser/deploy/elasticsearch-7.12.1-9300/jdk /home/esuser/OpenJDK16
对 /home/esuser/deploy/elasticsearch-7.12.1-9300/bin/elasticsearch文件进行修改,修改后的内容如下: #!/bin/bash #配置指定的JDK export ES_HOME=/home/esuser/OpenJDK16 export PATH=$ES_HOME/bin:$PATH #添加对JDK的判断 if [ -x "$ES_HOME/bin/java" ]; then JAVA="/home/esuser/jdk/bin/java" else JAVA=`which java` fi source "`dirname "$0"`"/elasticsearch-env CHECK_KEYSTORE=truepwd DAEMONIZE=false for option in "$@"; do case "$option" in -h|--help|-V|--version) CHECK_KEYSTORE=false ;; -d|--daemonize) DAEMONIZE=true ;; esac done if [ -z "$ES_TMPDIR" ]; then ES_TMPDIR=`"$JAVA" "$XSHARE" -cp "$ES_CLASSPATH" org.elasticsearch.tools.launchers.TempDirectory` fi unset KEYSTORE_PASSWORD KEYSTORE_PASSWORD= if [[ $CHECK_KEYSTORE = true ]] \ && bin/elasticsearch-keystore has-passwd --silent then if ! read -s -r -p "Elasticsearch keystore password: " KEYSTORE_PASSWORD ; then echo "Failed to read keystore password on console" 1>&2 exit 1 fi fi # 确保传递正确的两个参数到JvmOptionsParser ES_JAVA_OPTS=`export ES_TMPDIR; "$JAVA" "$XSHARE" -cp "$ES_CLASSPATH" org.elasticsearch.tools.launchers.JvmOptionsParser "$ES_PATH_CONF" "$ES_HOME/plugins"` # manual parsing to find out, if process should be detached if [[ $DAEMONIZE = false ]]; then exec \ "$JAVA" \ "$XSHARE" \ $ES_JAVA_OPTS \ -Des.path.home="$ES_HOME" \ -Des.path.conf="$ES_PATH_CONF" \ -Des.distribution.flavor="$ES_DISTRIBUTION_FLAVOR" \ -Des.distribution.type="$ES_DISTRIBUTION_TYPE" \ -Des.bundled_jdk="$ES_BUNDLED_JDK" \ -cp "$ES_CLASSPATH" \ org.elasticsearch.bootstrap.Elasticsearch \ "$@" <<<"$KEYSTORE_PASSWORD" else exec \ "$JAVA" \ "$XSHARE" \ $ES_JAVA_OPTS \ -Des.path.home="$ES_HOME" \ -Des.path.conf="$ES_PATH_CONF" \ -Des.distribution.flavor="$ES_DISTRIBUTION_FLAVOR" \ -Des.distribution.type="$ES_DISTRIBUTION_TYPE" \ -Des.bundled_jdk="$ES_BUNDLED_JDK" \ -cp "$ES_CLASSPATH" \ org.elasticsearch.bootstrap.Elasticsearch \ "$@" \ <<<"$KEYSTORE_PASSWORD" & retval=$? pid=$! [ $retval -eq 0 ] || exit $retval if [ ! -z "$ES_STARTUP_SLEEP_TIME" ]; then sleep $ES_STARTUP_SLEEP_TIME fi if ! ps -p $pid > /dev/null ; then exit 1 fi exit 0 fi exit $?
修改后,我在前台测试启动elasticsearch,elasticsearch启动后,我通过ps -ef|grep java查看了ES所使用的jdk,发现并未使用/home/esuser/jdk/bin/java,而是使用了 /home/esuser/deploy/elasticsearch-7.12.1-9300/jdk/bin/java,不符合我的要求,如下所示: [esuser@xsky-node1 ~]$ ps -ef|grep java esuser 8570 31437 99 16:10 pts/0 00:01:21 /home/esuser/deploy/elasticsearch-7.12.1-9300/jdk/bin/java -Xshare:auto -Des.networkaddress.cache.ttl=60 -Des.networkaddress.cache.negative.ttl=10 -XX:+AlwaysPreTouch -Xss1m -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djna.nosys=true -XX:-OmitStackTraceInFastThrow -XX:+ShowCodeDetailsInExceptionMessages -Dio.netty.noUnsafe=true -Dio.netty.noKeySetOptimization=true -Dio.netty.recycler.maxCapacityPerThread=0 -Dio.netty.allocator.numDirectArenas=0 -Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true -Djava.locale.providers=SPI,COMPAT --add-opens=java.base/java.io=ALL-UNNAMED -Xms8g -Xmx8g -XX:+UseG1GC -Des.networkaddress.cache.ttl=60 -Des.networkaddress.cache.negative.ttl=10 -XX:+AlwaysPreTouch -Xss1m -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djna.nosys=true -XX:-OmitStackTraceInFastThrow -Dio.netty.noUnsafe=true -Dio.netty.noKeySetOptimization=true -Dio.netty.recycler.maxCapacityPerThread=0 -Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true -Djava.io.tmpdir=/tmp/elasticsearch-1427292610172092269 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=data -XX:ErrorFile=logs/hs_err_pid%p.log -Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,pid,tags:filecount=32,filesize=64m -Djava.locale.providers=COMPAT -XX:UseAVX=2 -XX:MaxDirectMemorySize=4294967296 -XX:InitiatingHeapOccupancyPercent=30 -XX:G1ReservePercent=25 -Des.path.home=/home/esuser/deploy/elasticsearch-7.12.1-9300 -Des.path.conf=/home/esuser/deploy/elasticsearch-7.12.1-9300/config -Des.distribution.flavor=default -Des.distribution.type=tar -Des.bundled_jdk=true -cp /home/esuser/deploy/elasticsearch-7.12.1-9300/lib/* org.elasticsearch.bootstrap.Elasticsearch
根据脚本分析,发现是对环境变量 ES_HOME 的误用,在 Elasticsearch 中,ES_HOME 通常用来指代 Elasticsearch 的安装目录,而不是 JDK 的安装目录。应该使用 ES_JAVA_HOME 来设置 JDK 路径。这应该是导致 JDK 路径不正确的原因。 然后我对上面脚本进行了调整,使用 ES_JAVA_HOME 来设置 JDK 路径。 并确保所有引用 JDK 的地方都使用 ES_JAVA_HOME 而非 ES_HOME。
修改后的bin/elasticsearch脚本如下: #!/bin/bash #配置指定的JDK export ES_JAVA_HOME=/home/esuser/OpenJDK16 export PATH=$ES_JAVA_HOME/bin:$PATH #添加对JDK判断 if [ -x "$ES_JAVA_HOME/bin/java" ]; then JAVA="$ES_JAVA_HOME/bin/java" else JAVA=`which java` fi source "`dirname "$0"`"/elasticsearch-env CHECK_KEYSTORE=true DAEMONIZE=false for option in "$@"; do case "$option" in -h|--help|-V|--version) CHECK_KEYSTORE=false ;; -d|--daemonize) DAEMONIZE=true ;; esac done if [ -z "$ES_TMPDIR" ]; then ES_TMPDIR=`"$JAVA" "$XSHARE" -cp "$ES_CLASSPATH" org.elasticsearch.tools.launchers.TempDirectory` fi unset KEYSTORE_PASSWORD KEYSTORE_PASSWORD= if [[ $CHECK_KEYSTORE = true ]] \ && bin/elasticsearch-keystore has-passwd --silent then if ! read -s -r -p "Elasticsearch keystore password: " KEYSTORE_PASSWORD ; then echo "Failed to read keystore password on console" 1>&2 exit 1 fi fi # 确保传递正确的两个参数到JvmOptionsParser ES_JAVA_OPTS=`export ES_TMPDIR; "$JAVA" "$XSHARE" -cp "$ES_CLASSPATH" org.elasticsearch.tools.launchers.JvmOptionsParser "$ES_PATH_CONF" "$ES_HOME/plugins"` # manual parsing to find out, if process should be detached if [[ $DAEMONIZE = false ]]; then exec \ "$JAVA" \ "$XSHARE" \ $ES_JAVA_OPTS \ -Des.path.home="$ES_HOME" \ -Des.path.conf="$ES_PATH_CONF" \ -Des.distribution.flavor="$ES_DISTRIBUTION_FLAVOR" \ -Des.distribution.type="$ES_DISTRIBUTION_TYPE" \ -Des.bundled_jdk="$ES_BUNDLED_JDK" \ -cp "$ES_CLASSPATH" \ org.elasticsearch.bootstrap.Elasticsearch \ "$@" <<<"$KEYSTORE_PASSWORD" else exec \ "$JAVA" \ "$XSHARE" \ $ES_JAVA_OPTS \ -Des.path.home="$ES_HOME" \ -Des.path.conf="$ES_PATH_CONF" \ -Des.distribution.flavor="$ES_DISTRIBUTION_FLAVOR" \ -Des.distribution.type="$ES_DISTRIBUTION_TYPE" \ -Des.bundled_jdk="$ES_BUNDLED_JDK" \ -cp "$ES_CLASSPATH" \ org.elasticsearch.bootstrap.Elasticsearch \ "$@" \ <<<"$KEYSTORE_PASSWORD" & retval=$? pid=$! [ $retval -eq 0 ] || exit $retval if [ ! -z "$ES_STARTUP_SLEEP_TIME" ]; then sleep $ES_STARTUP_SLEEP_TIME fi if ! ps -p $pid > /dev/null ; then exit 1 fi exit 0 fi exit $?
修改上述脚本后,我再次前台启动elasticsearch验证测试,发现这次采用了我指定的JDK目录 /home/esuser/OpenJDK16,如下所示,红色箭头指向的是其中一个ES节点使用了指定的JDK目录,另一个节点使用了/etc/profile中配置的JAVA_HOME目录,如蓝色箭头所示。

image20240508101337556.png

在测试过程中,我对/home/esuser/deploy/elasticsearch-7.12.1-9300/config/下的GC参赛进行了调整,修改了如下参数: # -XX:+UseConcMarkSweepGC # -XX:CMSInitiatingOccupancyFraction=75 # -XX:+UseCMSInitiatingOccupancyOnly 将上述参数进行了注释, 然后添加 -XX:+UseG1GC 通过如下命令 /home/esuser/OpenJDK16/bin/java -XX:+PrintFlagsFinal -version | grep Use.*GC.*=.*true,查看到的信息如下: [esuser@xsky-node1 deploy]$ /home/esuser/OpenJDK16/bin/java -XX:+PrintFlagsFinal -version | grep Use.*GC.*=.*true bool UseAdaptiveSizeDecayMajorGCCost = true {product} {default} bool UseDynamicNumberOfGCThreads = true {product} {default} bool UseG1GC = true {product} {ergonomic} bool UseGCOverheadLimit = true {product} {default} bool UseMaximumCompactionOnSystemGC = true {product} {default} openjdk version "16" 2021-03-16 OpenJDK Runtime Environment AdoptOpenJDK (build 16+36) OpenJDK 64-Bit Server VM AdoptOpenJDK (build 16+36, mixed mode, sharing)

image20240508113701819.png

和修改前对比,显示已经使用了G1GC垃圾回收,接下来就是要在生产环境上进行验证测试。

注:JAVA_HOME在 ES 7中已经不推荐,建议使用ES_JAVA_HOME。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论