项目用的是SpringCloud全家桶,所以刚开始在调研调用链工具的时候,选择了zipkin,SpringSleuth内部就集成了zipkin,在集中到项目中使用了一段时间之后,发现功能太弱了,如apm、告警等,如果要增加功能,需要自己去定制。后面我们又增加了admin来监控微服务的状态,还有之前的durid可以查看sql的整体性能,随着业务增加,线上用sharding-jdbc作了分库分表,durid插件失效,无奈,需要一个新的调用链工具,同事能满足apm和告警的功能。
在网上找了一些对比的几个工具,一般比较常用的有Zipkin,Pinpoint,CAT,SkyWalking,Jaeger
其中Zipkin已经集成过,功能比较简单,需要定制开发,Jaeger由Zipkin发展而来,也是代码侵入式的,简单比较如下:
类别 | Zipkin | Jaeger | Pinpoint | SkyWalking | CAT |
---|---|---|---|---|---|
实现方式 | 拦截请求,发送(HTTP,mq)数据至zipkin服务 | 拦截请求,发送(HTTP,mq)数据至z服务 | java探针,字节码增强 | java探针,字节码增强 | 代码埋点(拦截器,注解,过滤器等) |
页面UI | ** | *** | ***** | **** | ***** |
数据存储 | ES,mysql,Cassandra,内存 | ES,mysql,Cassandra,内存 | Hbase | ES,H2,mysql | mysql,hdfs |
SkyWalking在UI和集成方式上比较有优势,还可以开发插件针对不同的端,ShardingSphere里可以支持SkyWalking(有ShardingSphere插件)。
SkyWalking有agent,collector,UI,其中agent需要通过javaagent在服务启动的时候加进去,collect和UI支持集群部署,完全是非侵入式的。
agent的部署配置,官方里支持4种方式,https://skyapm.github.io/document-cn-translation-of-skywalking/zh/master/setup/service-agent/java-agent/Setting-override.html
系统属性,agent选项,系统环境变量,配置文件,配置可有覆盖,
agent选项 > 系统属性(-D) > 系统环境变量 > 配置文件
SkyWalking在收集数据时需要区分不同来源的service_name,如果一个台机器部署有多个服务,用一个agent的时候用配置文件显然不同满足需求,如果复制多个agent客户端,其实完全没必要,维护替换成本更高,好的方式应该是用一个agent,然后各个微服务用各自的配置。
这样来看,agent选项算是最佳的方式了:
-javaagent:/path/to/skywalking-agent.jar=[option1]=[value1],[option2]=[value2]
示例:
-javaagent:/path/to/skywalking-agent.jar=agent.application_code=31200,logging.level=debug
每个服务可以在启动命令加上agent选项。
我们的微服务是用SpringBoot的jar方式启动的,有自己的启动命令,还有专门的脚本,通过yaml.sh工具获取服务名,可以实现动态的加载。
YamlParse__parse() {
local prefix=$2
local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
sed -ne "s|^\($s\):|\1|" \
-e "s|^\($s\)\($w\)$s:$s[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p" \
-e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" $1 |
awk -F$fs '{
indent = length($1)/2;
vname[indent] = $2;
for (i in vname) {if (i > indent) {delete vname[i]}}
if (length($3) > 0) {
vn=""; for (i=0; i{vn=(vn)(vname[i])("_")}
printf("%s%s%s=\"%s\"\n", "'$prefix'",vn, $2, $3);
}
}'
}
start.sh中加入变量
APPLICATION_NAME=${config_spring_application_name%% *}
application.yml中有如下参数:
spring:
application:
name: boot-platform-server
最后在启动命令中加入:
# java agent must be /injoy/server/apache-skywalking-apm-bin/agent
if [ -d "/injoy/server/apache-skywalking-apm-bin/agent" ]
then
export JAVA_OPTS="$JAVA_OPTS -javaagent:/injoy/server/apache-skywalking-apm-bin/agent/skywalking-agent.jar=agent.service_name=$APPLICATION_NAME,logging.level=info"
fi
这样就可以动态去实现了,约定大于配置,如果服务器上没有agent目录,可以不用加载,同时可以修改目录文件,更加灵活。
修改配置文件application.yml的storage配置项
storage:
# elasticsearch:
# nameSpace: ${SW_NAMESPACE:""}
# clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200}
# user: ${SW_ES_USER:""}
# password: ${SW_ES_PASSWORD:""}
# indexShardsNumber: ${SW_STORAGE_ES_INDEX_SHARDS_NUMBER:2}
# indexReplicasNumber: ${SW_STORAGE_ES_INDEX_REPLICAS_NUMBER:0}
# # Those data TTL settings will override the same settings in core module.
# recordDataTTL: ${SW_STORAGE_ES_RECORD_DATA_TTL:7} # Unit is day
# otherMetricsDataTTL: ${SW_STORAGE_ES_OTHER_METRIC_DATA_TTL:45} # Unit is day
# monthMetricsDataTTL: ${SW_STORAGE_ES_MONTH_METRIC_DATA_TTL:18} # Unit is month
# # Batch process setting, refer to https://www.elastic.co/guide/en/elasticsearch/client/java-api/5.5/java-docs-bulk-processor.html
# bulkActions: ${SW_STORAGE_ES_BULK_ACTIONS:2000} # Execute the bulk every 2000 requests
# bulkSize: ${SW_STORAGE_ES_BULK_SIZE:20} # flush the bulk every 20mb
# flushInterval: ${SW_STORAGE_ES_FLUSH_INTERVAL:10} # flush the bulk every 10 seconds whatever the number of requests
# concurrentRequests: ${SW_STORAGE_ES_CONCURRENT_REQUESTS:2} # the number of concurrent requests
# metadataQueryMaxSize: ${SW_STORAGE_ES_QUERY_MAX_SIZE:5000}
# segmentQueryMaxSize: ${SW_STORAGE_ES_QUERY_SEGMENT_SIZE:200}
# h2:
# driver: ${SW_STORAGE_H2_DRIVER:org.h2.jdbcx.JdbcDataSource}
# url: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db}
# user: ${SW_STORAGE_H2_USER:sa}
# metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}
mysql:
metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}
然后需要修改datasource-settings.properties配置文件,增加db配置
jdbcUrl=jdbc:mysql://xx.xx.xx.xx:3306/swtest?useSSL=false&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
dataSource.user=root
dataSource.password=iflytek
dataSource.cachePrepStmts=true
dataSource.prepStmtCacheSize=250
dataSource.prepStmtCacheSqlLimit=2048
dataSource.useServerPrepStmts=true
dataSource.useLocalSessionState=true
dataSource.rewriteBatchedStatements=true
dataSource.cacheResultSetMetadata=true
dataSource.cacheServerConfiguration=true
dataSource.elideSetAutoCommits=true
dataSource.maintainTimeStats=false
值得注意的是,由于监控数据很多,mysql的数据量增加的非常快,如果是线上环境需要1-3天清理一次。