问题:
中间件(这里是一个泛指包括 关系型数据库,Hbase、Reids、ClickHouse、RPC服务提供方,HTTP服务提供方等)超时导致可用率下降、RT飙高,真的是中间件的问题吗?
背景:
近期生产上多位同学反馈单表量级百万RT抖动;Hbase、Reids等中间件RT抖动报连接池满拿不到连接、超时异常监控飙升等问题,发现我们在中间件问题排查上大家过于怀疑中间件,排查思路上有些偏差。中间件问题(特别超时由超时引起的问题)排查的思路上首先要排查我们自身的使用方式、客户端应用上的问题,中间件大都经历过风雨考验,单业务场景很少有可能摸到中间件的性能问题(当然也有例外,不过不属于本篇幅的讨论范畴)。
怎样定位各种依赖中间件(或下游服务)的性能抖动问题?
首先我们来看一下请求的过程:
可能引发性能问题的原因:
- 服务端执行时间长超时(不做分析,本篇着重探讨客服端的问题)
- 客服端GC、STW请求尚无发出已经超时,或请求返回时STW导致超时(伴随GC次数预警)
- 客户端Load高,负载压力大,导致请求发布出去响应tcp buffer等(伴随load飙高预警)
- 线程卡卡住(伴随线程池满报错)
- TCP重传(TCP重传率预警)
如何定位是客服端问题还是服务端问题?
1.建立客户端多维度的依赖中间件监控
建立完整的依赖中间件RT、TP99、MAX、等指标监控。
当一个依赖方抖动了,第一个排除手段是看一下其他的依赖方是不是也抖动了,当所有的依赖方同步抖动时,大概率是客户端的问题。
2.熟悉服务端的监控体系
如果是单个依赖方抖动,则打开对应的服务端控制台进行排查,客户端监控与服务端监控不一致场景也大概率是客户端问题。
要基本熟练的掌握中间件控制台操作命令,最好建立可视化console界面。
客户端问题如何解决?
1.首先区分单机问题还是整体问题
可以建立单机预警,也可用通过监控日志分析确认是不是单机问题,单机问题摘流置换即可解决。
2.非单机问题如何解决
紧急情况下的首先判断是可否扩容解决,先解决问题再定位原因。
原因多种多样,排查方式却是一致的:监控&日志
应用维度监控:
CPU水位,网络状况,IO状况,LOAD等指标的监控大盘是必须的。
JVM监控排查:
java应用频繁fullGC往往会引发这种问题
对于在线服务低延迟应用FullGC的次数应当是0,较常见的是由于GC导致的。
提供一个JDK8 CMS参数的配置模板:
# if os memory <= 2G
if [ $memTotal -le 2048 ]; then
SERVICE_OPTS="${SERVICE_OPTS} -Xms1536m -Xmx1536m"
SERVICE_OPTS="${SERVICE_OPTS} -Xmn768m"
SERVICE_OPTS="${SERVICE_OPTS} -XX:SurvivorRatio=8"
SERVICE_OPTS="${SERVICE_OPTS} -XX:MaxDirectMemorySize=1g"
else
if [ $memTotal -le 10240 ]; then
# if os memory <= 10G
SERVICE_OPTS="${SERVICE_OPTS} -Xms5g -Xmx5g"
SERVICE_OPTS="${SERVICE_OPTS} -Xmn4g"
SERVICE_OPTS="${SERVICE_OPTS} -XX:SurvivorRatio=30"
SERVICE_OPTS="${SERVICE_OPTS} -XX:MaxDirectMemorySize=1g"
else
# if os memory 16G
SERVICE_OPTS="${SERVICE_OPTS} -Xms12g -Xmx12g"
SERVICE_OPTS="${SERVICE_OPTS} -Xmn10g"
SERVICE_OPTS="${SERVICE_OPTS} -XX:SurvivorRatio=30"
SERVICE_OPTS="${SERVICE_OPTS} -XX:MaxDirectMemorySize=2g"
fi
fi
SERVICE_OPTS="${SERVICE_OPTS} -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
SERVICE_OPTS="${SERVICE_OPTS} -XX:+UseConcMarkSweepGC -XX:CMSMaxAbortablePrecleanTime=5000"
SERVICE_OPTS="${SERVICE_OPTS} -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly"
SERVICE_OPTS="${SERVICE_OPTS} -XX:+ExplicitGCInvokesConcurrent -Dsun.rmi.dgc.server.gcInterval=2592000000 -Dsun.rmi.dgc.client.gcInterval=2592000000"
SERVICE_OPTS="${SERVICE_OPTS} -XX:ParallelGCThreads=${CPU_COUNT}"
if [[ "$JAVA_VERSION" -lt 9 ]]; then
SERVICE_OPTS="${SERVICE_OPTS} -Xloggc:${MIDDLEWARE_LOGS}/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps"
else
SERVICE_OPTS="${SERVICE_OPTS} -Xlog:gc*:${MIDDLEWARE_LOGS}/gc.log:time"
fi
SERVICE_OPTS="${SERVICE_OPTS} -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${MIDDLEWARE_LOGS}/java.hprof"
SERVICE_OPTS="${SERVICE_OPTS} -Djava.awt.headless=true"
SERVICE_OPTS="${SERVICE_OPTS} -Dsun.net.client.defaultConnectTimeout=10000"
SERVICE_OPTS="${SERVICE_OPTS} -Dsun.net.client.defaultReadTimeout=30000"
SERVICE_OPTS="${SERVICE_OPTS} -DJM.LOG.PATH=${MIDDLEWARE_LOGS}"
SERVICE_OPTS="${SERVICE_OPTS} -DJM.SNAPSHOT.PATH=${MIDDLEWARE_SNAPSHOTS}"
SERVICE_OPTS="${SERVICE_OPTS} -Dfile.encoding=${JAVA_FILE_ENCODING}"
SERVICE_OPTS="${SERVICE_OPTS} -Dhsf.publish.delayed=true"
SERVICE_OPTS="${SERVICE_OPTS} -Dproject.name=${APP_NAME}"
SERVICE_OPTS="${SERVICE_OPTS} -Dpandora.boot.wait=true -Dlog4j.defaultInitOverride=true"
SERVICE_OPTS="${SERVICE_OPTS} -Dserver.port=${TOMCAT_PORT} -Dmanagement.port=7002 -Dmanagement.server.port=7002"
SERVICE_OPTS="${SERVICE_OPTS} -Ddruid.load.spifilter.skip=true"
SERVICE_OPTS="${SERVICE_OPTS} -DlimitTime=30"
服务端问题如何解决?
反馈到中间件专家处解决,不同中间件的解决方案各有不同。业务上能建立降级能力最好。