最近生产环境发现Mycat(version 1.5.1) hung住2分钟,然后应用就叫了!最后发现这个hung的时间由Mycat脚本配置文件wrapper.conf
里面的某个参数控制,虽然hung住的原因还没有分析到,趋向于猜测为Mycat内部的bug引起。
基于上面的背景,需要充分理解Mycat启动的原理,守护进程原理和hung住检测的原理,以及wrapper.conf
配置选项,所以写下以下文章,作为记录:
我们知道,可通过源码编译打包方式得到mycat软件包,目录结构大致如下:
/bin
/catlet
/conf
/lib
/logs
其中bin目录下包含了启动mycat的脚本,默认脚本命名为mycat。这个脚本可以将mycat以后台程序的方式运行,并且具有守护进程的作用,能够在mycat应用程序发生异常,如crash,jvm hung,deadlock之后将mycat应用重启,最大化地保证mycat服务高可靠
这个功能实际上是Java Service Wrapper(JSW)提供的, 包括bin里面的启动脚本,也是JSW写好提供给我们用的
注意mycat使用的JSW版本为: Version 3.2.3,目前这个版本已经偏低了
我们知道mycat源码使用maven构建,build的依赖里面引入appassembler-maven-plugin
插件来辅助构建,正是这个插件引入了JSW
关于JSW的介绍和原理,请参考另外一篇文章:Java Service Wrapper 详解
通过启动脚本,调用JSW守护进程启动,然后带动我们的mycat程序启动,守护进程实时检测mycat服务的状态,发生异常及时抢救。通过ps -ef | grep wrapper
可以看到wrapper守护进程与mycat进程之间的关系:
mysql 3467 1 0 Jun15 ? 00:12:19 /dba/app/mycat/mycat/bin/./wrapper-linux-x86-64 /dba/app/mycat/mycat/conf/shivatds_wrapper.conf wrapper.syslog.ident=shivatds wrapper.pidfile=/dba/app/mycat/mycat/logs/shivatds.pid wrapper.daemonize=TRUE
mysql 3469 3467 1 Jun15 ? 03:04:03 java -DMYCAT_HOME=. -server -XX:MaxPermSize=64M -XX:+AggressiveOpts -XX:MaxDirectMemorySize=2G -XX:+UseParallelGC -Xss512K -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1984 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Xmx4G -Xms2G -Djava.library.path=lib -classpath lib/wrapper.jar:conf:lib/slf4j-log4j12-1.7.12.jar:lib/minlog-1.2.jar:lib/libwrapper-linux-ppc-64.so:lib/libwrapper-linux-x86-32.so:lib/json-20151123.jar:lib/univocity-parsers-1.5.4.jar:lib/ehcache-core-2.6.11.jar:lib/log4j-1.2.17.jar:lib/mapdb-1.0.7.jar:lib/curator-client-2.9.0.jar:lib/leveldb-api-0.7.jar:lib/dom4j-1.6.1.jar:lib/sequoiadb-driver-1.12.jar:lib/leveldb-0.7.jar:lib/objenesis-1.2.jar:lib/zookeeper-3.4.6.jar:lib/fastjson-1.2.7.jar:lib/jsr305-2.0.3.jar:lib/druid-1.0.14.jar:lib/jline-0.9.94.jar:lib/asm-4.0.jar:lib/snakeyaml-1.16.jar:lib/hamcrest-library-1.3.jar:lib/h2-1.4.192.jar:lib/guava-18.0.jar:lib/netty-3.7.0.Final.jar:lib/xml-apis-1.0.b2.jar:lib/wrapper.jar:lib/libwrapper-linux-x86-64.so:lib/hamcrest-core-1.3.jar:lib/kryo-2.10.jar:lib/mongo-java-driver-2.11.4.jar:lib/slf4j-api-1.7.12.jar:lib/jtar-2.3.jar:lib/reflectasm-1.03.jar:lib/Mycat-server-1.5.3.0-RELEASE.jar:lib/curator-framework-2.9.0.jar -Dwrapper.key=loiVbopWE6KVjsik -Dwrapper.port=32000 -Dwrapper.jvm.port.min=31000 -Dwrapper.jvm.port.max=31999 -Dwrapper.pid=3467 -Dwrapper.version=3.2.3 -Dwrapper.native_library=wrapper -Dwrapper.service=TRUE -Dwrapper.cpu.timeout=10 -Dwrapper.jvmid=1 org.tanukisoftware.wrapper.WrapperSimpleApp org.opencloudb.MycatStartup start
JSW有一个比较重要的配置文件,默认叫做wrapper.conf
。通过这个配置文件,配置JSW守护进程和wrapper的一些行为,并且,还可以控制mycat jvm的一些启动参数(如-Xms和-Xmx这些)。
这个文件默认放到/conf目录下
下面我们将重点放在这个文件的配置选项里面:
贴上mycat编译打包后默认生成的wrapper.conf
(位于conf子目录下),然后对每个配置参数作出解释,如下所示:
#********************************************************************
# Wrapper Properties
#********************************************************************
# Java执行命令,默认即可
wrapper.java.command=java
# 用于定位wrapper程序目录,默认即可
wrapper.working.dir=..
# JSW wrapper类,JSW将使用这个类来包装Mycat启动类(MycatStartup.java),并控制Mycat的执行,
# 即在WrapperSimpleApp的main方法里面加入一些控制逻辑,
# 然后执行MycatStartup的main方法,从而跑其Mycat
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp
# 设置环境变量,参考https://wrapper.tanukisoftware.com/doc/english/props-envvars.html
# 在后面的配置wrapper.java.classpath.3被使用
set.default.REPO_DIR=lib
# 不知道哪里会用到这个环境变量
set.APP_BASE=.
# Java Classpath (include wrapper.jar) Add class path elements as
# needed starting from 1
# 配置Java应用的classpath,必须要包含wrapper.jar,参数下标从1开始
wrapper.java.classpath.1=lib/wrapper.jar
wrapper.java.classpath.2=conf
wrapper.java.classpath.3=%REPO_DIR%/*
# Java Library Path (location of Wrapper.DLL or libwrapper.so)
# 默认参数,不用修改
wrapper.java.library.path.1=lib
# 配置Java启动参数,参数下标从1开始,包括一系列Java环境变量设定以及JVM参数配置
#wrapper.java.additional.1=
wrapper.java.additional.1=-DMYCAT_HOME=.
wrapper.java.additional.2=-server
wrapper.java.additional.3=-XX:MaxPermSize=64M
wrapper.java.additional.4=-XX:+AggressiveOpts
wrapper.java.additional.5=-XX:MaxDirectMemorySize=8G
wrapper.java.additional.6=-XX:+UseParallelGC
wrapper.java.additional.7=-Xss512K
wrapper.java.additional.8=-Dcom.sun.management.jmxremote
wrapper.java.additional.9=-Dcom.sun.management.jmxremote.port=1984
wrapper.java.additional.10=-Dcom.sun.management.jmxremote.authenticate=false
wrapper.java.additional.11=-Dcom.sun.management.jmxremote.ssl=false
wrapper.java.additional.12=-Xmx4G
wrapper.java.additional.13=-Xms4G
# Initial Java Heap Size (in MB) 等价于 -Xms3M
#wrapper.java.initmemory=3
# Maximum Java Heap Size (in MB) 等价于 -Xmx64M
#wrapper.java.maxmemory=64
# 程序启动参数,下标从1开始,第1个参数指定wrapper需要包装的Java应用主程序入口,
# 对于Mycat而言,这里指定为MycatStartup,默认即可,不需要修改
wrapper.app.parameter.1=org.opencloudb.MycatStartup
# 默认即可,不需要修改
wrapper.app.parameter.2=start
#********************************************************************
# Wrapper Logging Properties
#********************************************************************
# wrapper 控制台日志输出格式
# 仅当使用mycat console启动时候,会将log输出到控制台,这个参数是控制这个时候log的输出格式
# 格式详见: https://wrapper.tanukisoftware.com/doc/english/prop-console-format.html
wrapper.console.format=PM
# wrapper 控制台输出日志级别
# 仅当使用mycat console启动时候,会将log输出到控制台,这个参数是控制这个时候log的级别, 默认为INFO即可
wrapper.console.loglevel=INFO
# wrapper 输出日志文件
# 仅当使用mycat start启动时,会将log输出到这个指定的文件里
wrapper.logfile=logs/wrapper.log
# wrapper 输出到log文件的日志输出格式
# 控制当使用mycat start启动方式下log输出格式
# 格式参考: https://wrapper.tanukisoftware.com/doc/english/prop-logfile-format.html
wrapper.logfile.format=LPTM
# wrapper 输出到log文件的日志级别
# 控制当使用mycat start启动方式下log输出级别
wrapper.logfile.loglevel=INFO
# 配置滚动日志大小,默认为0,表示不支持滚动日志,即日志都往一个日志文件里面写,并且不限制文件大小
# May abbreviate with the 'k' (kb) or 'm' (mb) suffix. For example: 10m = 10 megabytes.
wrapper.logfile.maxsize=0
# 配置滚动日志最大文件个数,默认为0表示不限制个数
wrapper.logfile.maxfiles=0
# 输出到sys/event log的日志级别,默认为NONE表示不输出到sys/event log
wrapper.syslog.loglevel=NONE
#********************************************************************
#********************************************************************
# Title to use when running as a console
wrapper.console.title=Mycat-server
# 以下这些参数在Windows平台下起作用,一般应用都部署在Linux平台,可忽略这些配置
#********************************************************************
# Wrapper Windows NT/2000/XP Service Properties
#********************************************************************
# WARNING - Do not modify any of these properties when an application
# using this configuration file has been installed as a service.
# Please uninstall the service before modifying this section. The
# service can then be reinstalled.
# Name of the service
wrapper.ntservice.name=mycat
# Display name of the service
wrapper.ntservice.displayname=Mycat-server
# Description of the service
wrapper.ntservice.description=The project of Mycat-server
# Service dependencies. Add dependencies as needed starting from 1
wrapper.ntservice.dependency.1=
# Mode in which the service is installed. AUTO_START or DEMAND_START
wrapper.ntservice.starttype=AUTO_START
# Allow the service to interact with the desktop.
wrapper.ntservice.interactive=false
# 重要参数,控制wrapper ping Mycat hung住的超时时间,单位是s,120s = 2min
wrapper.ping.timeout=120
# JSW官网上目前找不到这个参数!
configuration.directory.in.classpath.first=conf
注意最后面这个wrapper.ping.timeout
参数(wrapper默认这个参数配置为30s,不知道mycat为何把这个参数调得这么高),可控制wrapper对于Mycat hung住的判定时间,这里配置为2min,表示2min内没有收到Mycat的ping响应,即认为Mycat hung住,这时候wrpper将会把Mycat重起,观察到wrapper.log里面的日志,如下所示:
INFO | jvm 1 | 2017/06/16 00:16:02 | log4j 2017-06-16 00:16:02 [./conf/log4j.xml] load completed.
INFO | jvm 1 | 2017/06/16 00:16:03 | MyCAT Server startup successfully. see logs in logs/mycat.log
ERROR | wrapper | 2017/06/21 17:43:21 | JVM appears hung: Timed out waiting for signal from JVM.
ERROR | wrapper | 2017/06/21 17:43:21 | JVM did not exit on request, terminated
INFO | wrapper | 2017/06/21 17:43:21 | JVM exited on its own while waiting to kill the application.
STATUS | wrapper | 2017/06/21 17:43:21 | JVM exited in response to signal SIGKILL (9).
STATUS | wrapper | 2017/06/21 17:43:25 | Launching a JVM...
INFO | jvm 2 | 2017/06/21 17:43:25 | Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org
INFO | jvm 2 | 2017/06/21 17:43:25 | Copyright 1999-2006 Tanuki Software, Inc. All Rights Reserved.
INFO | jvm 2 | 2017/06/21 17:43:25 |
INFO | jvm 2 | 2017/06/21 17:43:26 | log4j 2017-06-21 17:43:26 [./conf/log4j.xml] load completed.
INFO | jvm 2 | 2017/06/21 17:45:27 | MyCAT Server startup successfully. see logs in logs/mycat.log
其中部分参数是由mycat中pom.xml的appassembler-maven-plugin
配置带入的,如下所示:
<plugin>
<groupId>org.codehaus.mojogroupId>
<artifactId>appassembler-maven-pluginartifactId>
<version>1.7version>
<configuration>
<configurationDirectory>confconfigurationDirectory>
<includeConfigurationDirectoryInClasspath>trueincludeConfigurationDirectoryInClasspath>
<repositoryLayout>flatrepositoryLayout>
<useWildcardClassPath>trueuseWildcardClassPath>
<daemons>
<daemon>
<id>mycatid>
<mainClass>org.opencloudb.MycatStartupmainClass>
<commandLineArguments>
<commandLineArgument>startcommandLineArgument>
commandLineArguments>
<platforms>
<platform>jswplatform>
platforms>
<jvmSettings>
<maxStackSize>128maxStackSize>
<systemProperties>
<systemProperty>MYCAT_HOME=.systemProperty>
systemProperties>
<extraArguments>
<extraArgument>-server extraArgument>
<extraArgument>-XX:MaxPermSize=64MextraArgument>
<extraArgument>-XX:+AggressiveOptsextraArgument>
<extraArgument>-XX:MaxDirectMemorySize=2GextraArgument>
<extraArgument>-XX:+UseParallelGCextraArgument>
<extraArgument>-Xss512KextraArgument>
<extraArgument>-Dcom.sun.management.jmxremote extraArgument>
<extraArgument>-Dcom.sun.management.jmxremote.port=1984extraArgument>
<extraArgument>-Dcom.sun.management.jmxremote.authenticate=false extraArgument>
<extraArgument>-Dcom.sun.management.jmxremote.ssl=false extraArgument>
<extraArgument>-Xmx4GextraArgument>
<extraArgument>-Xms1GextraArgument>
extraArguments>
jvmSettings>
<generatorConfigurations>
<generatorConfiguration>
<generator>jswgenerator>
<includes>
<include>aix-ppc-32include>
<include>aix-ppc-64include>
<include>hpux-parisc-64include>
<include>linux-x86-32include>
<include>linux-x86-64include>
<include>linux-ppc-64include>
<include>macosx-ppc-32include>
<include>macosx-x86-universal-32include>
<include>macosx-universal-32include>
<include>macosx-universal-64include>
<include>solaris-sparc-32include>
<include>solaris-sparc-64include>
<include>solaris-x86-32include>
<include>windows-x86-32include>
<include>windows-x86-64include>
includes>
<configuration>
<property>
<name>configuration.directory.in.classpath.firstname>
<value>confvalue>
property>
<property>
<name>wrapper.ping.timeoutname>
<value>120value>
property>
<property>
<name>set.default.REPO_DIRname>
<value>libvalue>
property>
<property>
<name>wrapper.logfilename>
<value>logs/wrapper.logvalue>
property>
configuration>
generatorConfiguration>
generatorConfigurations>
daemon>
daemons>
configuration>
<executions>
<execution>
<id>generate-jswid>
<phase>packagephase>
<goals>
<goal>generate-daemonsgoal>
goals>
execution>
executions>
plugin>