作为一款APM和全链路监控平台,Skywalking算是挺出色的。Skywalking是APM监控平台的后起之秀,大有超越其他开源APM监控平台的趋势。它通过探针自动收集所需的指标,并进行分布式追踪。通过这些调用链路以及指标,Skywalking APM会感知应用间关系和服务间关系,并进行相应的指标统计。

    目前Skywalking支持h2、mysql、ElasticSearch作为数据存储,我就说一下,这三个种库的优缺点和使用要求:

    1、首先是默认的h2

    h2是Skywalking自带的,对应的jar包路径是Skywalking/oap-libs/h2-1.4.196.jar,h2是一种内存数据库,在Skywalking配置文件的默认配置如下:

    1. h2:
    2. driver: ${SW_STORAGE_H2_DRIVER:org.h2.jdbcx.JdbcDataSource}
    3. url: ${SW_STORAGE_H2_URL:jdbc:h2:mem:skywalking-oap-db}
    4. user: ${SW_STORAGE_H2_USER:sa}
    5. metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}

    作为内存数据库,当然是保存在内存中,只要服务重启或是Skywalking应用故障了,基本上所监控到的数据也就丢失了,所以h2的内存模式其实不适合于应用服务长时间监控的场景。但是h2也可以变为文件数据库,配置如下:

    1. h2:
    2. driver: ${SW_STORAGE_H2_DRIVER:org.h2.jdbcx.JdbcDataSource}
    3. url: ${SW_STORAGE_H2_URL:jdbc:h2:tcp://127.0.0.1/~/skywalking-oap-db;AUTO_SERVER=TRUE}
    4. user: ${SW_STORAGE_H2_USER:sa}
    5. metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}

    和内存模式的配置区别就是URL换成了文件的路径,默认路径是在用户目录下(如administrator或root或home/user等用户目录)自动创建数据库文件skywalking-oap-db。

    要使用文件数据库,有个前提是要先启动h2的TCP服务,因为默认skywalking调用的是内存数据库,如果没有启动h2 TCP,由于监听不到端口,oapService就会判断为连接故障而关闭。启动h2 TCP服务,可以在bin目录新建启动脚本,linux脚本如下:

    1. PRG="$0"
    2. PRGDIR=`dirname "$PRG"`
    3. [ -z "$OAP_HOME" ] && OAP_HOME=`cd "$PRGDIR/.." >/dev/null; pwd`
    4. OAP_LOG_DIR="${OAP_HOME}/logs"
    5. JAVA_OPTS=" -Xms64M -Xmx256M"
    6. if [ ! -d "${OAP_HOME}/logs" ]; then
    7. mkdir -p "${OAP_LOG_DIR}"
    8. fi
    9. _RUNJAVA=${JAVA_HOME}/bin/java
    10. [ -z "$JAVA_HOME" ] && _RUNJAVA=java
    11. CLASSPATH="$OAP_HOME/config:$CLASSPATH"
    12. for i in "$OAP_HOME"/oap-libs/h2*.jar
    13. do
    14. CLASSPATH="$i:$CLASSPATH"
    15. done
    16. OAP_OPTIONS=" -Doap.logDir=${OAP_LOG_DIR}"
    17. # 如果需要远程连接h2数据库,需将-tcp改为-tcpAllowOthers
    18. eval exec ""$_RUNJAVA" ${JAVA_OPTS} ${OAP_OPTIONS} -classpath $CLASSPATH org.h2.tools.Server -tcp
    19. 2>${OAP_LOG_DIR}/h2Tcp.log 1> /dev/null &"
    20. if [ $? -eq 0 ]; then
    21. sleep 1
    22. echo "SkyWalking h2Tcp started successfully!"
    23. else
    24. echo "SkyWalking h2Tcp started failure!"
    25. exit 1
    26. fi

    对应的windows脚本如下:

    1. @REM 如果需要远程查看h2数据库(tcp端口9092,页面访问端口8082),需将-tcp改为-tcpAllowOthers
    2. @echo off
    3. setlocal
    4. set OAP_PROCESS_TITLE=Skywalking-H2TcpServer
    5. set OAP_HOME=%~dp0%..
    6. set OAP_OPTS="-Xms64M -Xmx256M -Doap.logDir=%OAP_HOME%logs"
    7. set CLASSPATH=%OAP_HOME%config;.;
    8. set CLASSPATH=%OAP_HOME%oap-libs*;%CLASSPATH%
    9. if defined JAVA_HOME (
    10. set _EXECJAVA="%JAVA_HOME%binjava"
    11. )
    12. if not defined JAVA_HOME (
    13. echo "JAVA_HOME not set."
    14. set _EXECJAVA=java
    15. )
    16. start "%OAP_PROCESS_TITLE%" %_EXECJAVA% "%OAP_OPTS%" -cp "%CLASSPATH%" org.h2.tools.Server -tcp
    17. endlocal

    先启动h2文件数据库,确保9092端口能被监听,再启动Skywalking的其他服务。

    h2文件数据库虽然非常轻量级,毕竟skywalking自带了,但是稳定性却很差,一但文件损坏(大并发量和大吞吐量的监控数据,就会把它干坏),oapService服务就启动不了了,需要清除文件或是恢复及覆盖文件才能启动(对于一般应用者来说,这也是要命的事)。

    2、Mysql数据库

    启用mysql存储,有两个地方需要配置,一个是application.yml

    1. mysql:
    2. metadataQueryMaxSize: ${SW_STORAGE_H2_QUERY_MAX_SIZE:5000}

    另一个是datasource-settings.properties

    1. jdbcUrl=jdbc:mysql://localhost:3306/swtest
    2. dataSource.user=root
    3. dataSource.password=root@1234

    mysql数据库相对要稳定,毕竟是被大量使用的数据库,而且可以做相应的优化,配置缓存,加大数据吞吐量。但是基于mysql的查询速度我觉得不快,特别是skywalking中【追踪】查看,3万条以上的记录查询基本上觉得卡。但作为长时间的应用性能监控来说,mysql合适。而对于Linux下的部署来说,mysql偏重量级了(编译后的二进制mysql安装包就有好几百M)。

    3、ElasticSearch

    官网好像是推荐使用ElasticSearch,为什么推荐?我猜的,应该是快呀。ES(ElasticSearch)是一款分布式全文检索框架,底层基于Lucene实现,是给搜索引擎专用的,不快都不行。试了一下10万条的追踪记录,基本上很快就能查询展示。

    ElasticSearch不是自带的,需要安装,考虑到轻量级,我选用的是elasticsearch-6.2.4,原因是包小免安装,解压完也才30多M,而且目前最新版本的Skywalking 6.2.0是能够支持该版本的ElasticSearch。

    Skywalking启用ES,只需要配置文件设置如下:

    1. storage:
    2. elasticsearch:
    3. nameSpace: ${SW_NAMESPACE:""}
    4. clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:localhost:9200}
    5. user: ${SW_ES_USER:""}
    6. password: ${SW_ES_PASSWORD:""}
    7. indexShardsNumber: ${SW_STORAGE_ES_INDEX_SHARDS_NUMBER:2}
    8. indexReplicasNumber: ${SW_STORAGE_ES_INDEX_REPLICAS_NUMBER:0}
    9. # Those data TTL settings will override the same settings in core module.
    10. recordDataTTL: ${SW_STORAGE_ES_RECORD_DATA_TTL:7} # Unit is day
    11. otherMetricsDataTTL: ${SW_STORAGE_ES_OTHER_METRIC_DATA_TTL:45} # Unit is day
    12. monthMetricsDataTTL: ${SW_STORAGE_ES_MONTH_METRIC_DATA_TTL:18} # Unit is month
    13. bulkActions: ${SW_STORAGE_ES_BULK_ACTIONS:2000} # Execute the bulk every 2000 requests
    14. bulkSize: ${SW_STORAGE_ES_BULK_SIZE:20} # flush the bulk every 20mb
    15. flushInterval: ${SW_STORAGE_ES_FLUSH_INTERVAL:10} # flush the bulk every 10 seconds whatever the number of requests
    16. concurrentRequests: ${SW_STORAGE_ES_CONCURRENT_REQUESTS:2} # the number of concurrent requests
    17. metadataQueryMaxSize: ${SW_STORAGE_ES_QUERY_MAX_SIZE:5000}
    18. segmentQueryMaxSize: ${SW_STORAGE_ES_QUERY_SEGMENT_SIZE:200}

    另外如果,想让ES能同时被本地和远程访问到,可以改一下ES的配置文件,IP改为如下:

    1. network.host: 0.0.0.0

    我专门写了linux下的ES启动脚本(脚本放在skywalking的bin目录下,ES放在Skywalking的根目录下),由于ES不能以root用户启动,所以脚本里加了用户的自动创建:

    1. check_user()
    2. {
    3. #判断用户是否存在passwd中
    4. i=`cat /etc/passwd | cut -f1 -d':' | grep -w "$1" -c`
    5. if [ $i -le 0 ]; then
    6. echo "User $1 is not in the passwd"
    7. return 0
    8. else
    9. #显示用户存在
    10. echo "User $1 is in then use"
    11. return 1
    12. fi
    13. }
    14. uname=elsearch
    15. check_user $uname
    16. if [ $? -eq 0 ]
    17. then
    18. #添加此用户
    19. sudo useradd $uname
    20. passwd $uname --stdin "123456"
    21. echo "user $uname add!!!"
    22. fi
    23. Cur_Dir=$(cd "$(dirname "$0")"; pwd)
    24. chown $uname:$uname -R $Cur_Dir/../elasticsearch
    25. chmod -R 766 $Cur_Dir/../elasticsearch
    26. chmod -R 777 $Cur_Dir/../elasticsearch/bin
    27. su - $uname -c "nohup $Cur_Dir/../elasticsearch/bin/elasticsearch > $Cur_Dir/../elasticsearch/logs/output.log 2>&1 &"
    28. echo "elasticsearch start success!"

    考虑到ES也是需要先启动,确保端口监听正常了,才能启动oapService,所以我改造了skywalking自带的启动脚本,加了端口监听判断:

    1. check_port()
    2. {
    3. grep_port=`netstat -tlpn | grep "b$1b"`
    4. echo "grep port is $grep_port"
    5. if [ -n "$grep_port" ]
    6. then
    7. echo "port $port is in use"
    8. return 1
    9. else
    10. echo "port is not established,please wait a moment......"
    11. return 0
    12. fi
    13. }
    14. PRG="$0"
    15. PRGDIR=`dirname "$PRG"`
    16. OAP_EXE=oapService.sh
    17. WEBAPP_EXE=webappService.sh
    18. elsearch_EXE=elasticsearchStart.sh
    19. "$PRGDIR"/"$elsearch_EXE"
    20. port=9200
    21. echo "check $port"
    22. for i in $(seq 1 20)
    23. do
    24. check_port $port
    25. if [ $? -eq 0 ]
    26. then
    27. sleep 2s
    28. else
    29. break
    30. fi
    31. done
    32. "$PRGDIR"/"$OAP_EXE"
    33. "$PRGDIR"/"$WEBAPP_EXE"

    Windows下的脚本就简单多了:

    1. @echo off
    2. setlocal
    3. set OAP_PROCESS_TITLE=Skywalking-Elasticsearch
    4. set OAP_HOME=%~dp0%..
    5. start "%OAP_PROCESS_TITLE%" %OAP_HOME%elasticsearchbinelasticsearch.bat
    6. endlocal

    而且windows下启动ES很快,没有端口启动的延时时间,所以整个skywalking启动脚本的改造量不大:

    1. @echo off
    2. setlocal
    3. call "%~dp0"elasticsearchUp.bat
    4. call "%~dp0"oapService.bat start
    5. call "%~dp0"webappService.bat start
    6. endlocal

    以上的准备,就是为Skywalking应用ES存储做好了准备,但是Elasticsearch本身也是存在写入瓶颈的,也就是说ES也会崩溃,一但崩溃,就可能oapService关闭,或是导致skywalking页面大盘空白。

    我们可以做些调优,skywalking写入ES的操作是使用了ES的批量写入接口。我们可以调整这些批量的维度。尽量降低ES索引的写入频率,如:

    1. bulkActions: ${SW_STORAGE_ES_BULK_ACTIONS:4000} # Execute the bulk every 2000 requests
    2. bulkSize: ${SW_STORAGE_ES_BULK_SIZE:40} # flush the bulk every 20mb
    3. flushInterval: ${SW_STORAGE_ES_FLUSH_INTERVAL:30} # flush the bulk every 10 seconds whatever the number of requests
    4. concurrentRequests: ${SW_STORAGE_ES_CONCURRENT_REQUESTS:4} # the number of concurrent requests
    5. metadataQueryMaxSize: ${SW_STORAGE_ES_QUERY_MAX_SIZE:8000}

    调整bulkActions默认2000次请求批量写入一次改到4000次;bulkSize批量刷新从20M一次到40M一次;flushInterval每10秒刷新一次堆改为每30秒刷新;concurrentRequests查询的最大数量由5000改为8000。这种配置调优确实生效了,重启服务后两三天了都没有出现过ES写入阻塞的问题。不过这种设置只是暂时的,你只能期望流量不突发,或者应用不增加。一旦遇到突发流量和应用的增加,ES写入瓶颈还是会凸显出来。而且参数设置过大带来了一个新的问题,就是数据写入延时会比较大,一次服务交互发生的trace隔好久才能在skywalking页面上查询到。所以最终解决方案是优化ES的写入性能,具体优化可以参考别人的文章:https://www.easyice.cn/archives/207

    另外作为开源化的平台,扩展性也是其中的优势,本身ES就是分布式全文检索框架,可以部署成高可用的集群,另外Skyawalking也是分布式链路跟踪系统,分布式既然是它应用的特性,那么怎么去构建集群化的监控平台,就完全靠你自己的想象和发挥了。

    最后放一张我的Skywalking监控平台的监控效果图(压测过程中的应用监控),我可是斗胆把人家的Logo都换了,但我可不会用在商用领域,只是部门内部使用,方便其他人一眼认出这是个APM监控平台:

    另外附上Skywalking各模块完整的配置说明(为看不明白英文注释的人准备):

    (1)Skywalking collector 配置 OAP(Collector)链路数据归集器,主要用于数据落地,大部分都会选择 Elasticsearch 6,OAP配置文件为 /opt/apache-skywalking-apm-6.2.0/config/application.yml,配置单点的 OAP(Collector)配置如下:

    1. cluster:
    2. # 单节点模式
    3. standalone:
    4. # zk用于管理collector集群协作.
    5. # zookeeper:
    6. # 多个zk连接地址用逗号分隔.
    7. # hostPort: localhost:2181
    8. # sessionTimeout: 100000
    9. # 分布式 kv 存储设施,类似于zk,但没有zk重型(除了etcd,consul、Nacos等都是类似功能)
    10. # etcd:
    11. # serviceName: ${SW_SERVICE_NAME:"SkyWalking_OAP_Cluster"}
    12. # 多个节点用逗号分隔, 如: 10.0.0.1:2379,10.0.0.2:2379,10.0.0.3:2379
    13. # hostPort: ${SW_CLUSTER_ETCD_HOST_PORT:localhost:2379}
    14. core:
    15. default:
    16. # 混合角色:接收代理数据,1级聚合、2级聚合
    17. # 接收者:接收代理数据,1级聚合点
    18. # 聚合器:2级聚合点
    19. role: ${SW_CORE_ROLE:Mixed} # Mixed/Receiver/Aggregator
    20. # rest 服务地址和端口
    21. restHost: ${SW_CORE_REST_HOST:localhost}
    22. restPort: ${SW_CORE_REST_PORT:12800}
    23. restContextPath: ${SW_CORE_REST_CONTEXT_PATH:/}
    24. # gRPC 服务地址和端口
    25. gRPCHost: ${SW_CORE_GRPC_HOST:localhost}
    26. gRPCPort: ${SW_CORE_GRPC_PORT:11800}
    27. downsampling:
    28. - Hour
    29. - Day
    30. - Month
    31. # 设置度量数据的超时。超时过期后,度量数据将自动删除.
    32. # 单位分钟
    33. recordDataTTL: ${SW_CORE_RECORD_DATA_TTL:90}
    34. # 单位分钟
    35. minuteMetricsDataTTL: ${SW_CORE_MINUTE_METRIC_DATA_TTL:90}
    36. # 单位小时
    37. hourMetricsDataTTL: ${SW_CORE_HOUR_METRIC_DATA_TTL:36}
    38. # 单位天
    39. dayMetricsDataTTL: ${SW_CORE_DAY_METRIC_DATA_TTL:45}
    40. # 单位月
    41. monthMetricsDataTTL: ${SW_CORE_MONTH_METRIC_DATA_TTL:18}
    42. storage:
    43. elasticsearch:
    44. # elasticsearch 的集群名称
    45. nameSpace: ${SW_NAMESPACE:"local-ES"}
    46. # elasticsearch 集群节点的地址及端口
    47. clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:192.168.2.10:9200}
    48. # elasticsearch 的用户名和密码
    49. user: ${SW_ES_USER:""}
    50. password: ${SW_ES_PASSWORD:""}
    51. # 设置 elasticsearch 索引分片数量
    52. indexShardsNumber: ${SW_STORAGE_ES_INDEX_SHARDS_NUMBER:2}
    53. # 设置 elasticsearch 索引副本数
    54. indexReplicasNumber: ${SW_STORAGE_ES_INDEX_REPLICAS_NUMBER:0}
    55. # 批量处理配置
    56. # 每2000个请求执行一次批量
    57. bulkActions: ${SW_STORAGE_ES_BULK_ACTIONS:2000}
    58. # 每 20mb 刷新一次内存块
    59. bulkSize: ${SW_STORAGE_ES_BULK_SIZE:20}
    60. # 无论请求的数量如何,每10秒刷新一次堆
    61. flushInterval: ${SW_STORAGE_ES_FLUSH_INTERVAL:10}
    62. # 并发请求的数量
    63. concurrentRequests: ${SW_STORAGE_ES_CONCURRENT_REQUESTS:2}
    64. # elasticsearch 查询的最大数量
    65. metadataQueryMaxSize: ${SW_STORAGE_ES_QUERY_MAX_SIZE:5000}
    66. # elasticsearch 查询段最大数量
    67. segmentQueryMaxSize: ${SW_STORAGE_ES_QUERY_SEGMENT_SIZE:200}

    (2)Skywalking webApp 配置 Skywalking 的 WebApp 主要是用来展示落地的数据,因此只需要配置 Web 的端口及获取数据的 OAP(Collector)的IP和端口,webApp 配置文件地址为 /opt/apache-skywalking-apm-6.2.0/webapp/webapp.yml 配置如下:

    1. server:
    2. port: 9000
    3. collector:
    4. path: /graphql
    5. ribbon:
    6. ReadTimeout: 10000
    7. # 指向所有后端collector 的 restHost:restPort 配置,多个使用, 分隔
    8. listOfServers: localhost:12800
    9. security:
    10. user:
    11. # username
    12. admin:
    13. # password
    14. password: admin

    (3)Skywalking Agent 配置 Skywalking 的 Agent 主要用于收集和发送数据到 OAP(Collector),因此需要进行配置 Skywalking OAP(Collector)的地址,Agent 的配置文件地址为 /opt/apache-skywalking-apm-6.2.0/agent/config/agent.config,配置如下:

    1. # 设置Agent命名空间,它用来隔离追踪和监控数据,当两个应用使用不同的名称空间时,跨进程传播链会中断。
    2. agent.namespace=${SW_AGENT_NAMESPACE:default-namespace}
    3. # 设置服务名称,会在 Skywalking UI 上显示的名称
    4. agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
    5. # 每 3秒采集的样本跟踪比例,如果是负数则表示 100%采集
    6. agent.sample_n_per_3_secs=${SW_AGENT_SAMPLE:-1}
    7. # 启用 Debug ,如果为 true 则将把所有检测到的类文件保存在"/debug"文件夹中
    8. # agent.is_open_debugging_class = ${SW_AGENT_OPEN_DEBUG:true}
    9. # 后端的 collector 端口及地址
    10. collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:192.168.2.215:11800}
    11. # 日志级别
    12. logging.level=${SW_LOGGING_LEVEL:DEBUG}

    欢迎光临smooth的博客:https://smooth.blog.csdn.net/

    原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

    如有侵权,请联系 yunjia_community@tencent.com 删除。