Skywalking笔记
Skywalking是一个开源的应用性能监控系统,提供分布式追踪、性能指标分析、应用拓扑分析等功能。
架构分为三部分: - OAP:数据处理、存储 - UI:数据展示 - Agent:数据采集
# 服务端部署
通过docker-compose
部署Skywalking,编写docker-compose.yml
文件:
version: '3.8'
services:
skywalking-oap-server:
image: apache/skywalking-oap-server:10.1.0
container_name: skywalking-oap-server
restart: always
# 端口映射
ports:
- "11800:11800"
- "12800:12800"
volumes:
- ./config/oap/alarm-settings.yml:/skywalking/config/alarm-settings.yml
environment:
SW_HEALTH_CHECKER: default
SW_STORAGE: elasticsearch
SW_ENABLE_UPDATE_UI_TEMPLATE: "true"
SW_STORAGE_ES_CLUSTER_NODES: ${ES_IP}:${ES_PORT}
JAVA_OPTS: "-Xms512m -Xmx512m"
TZ: Asia/Shanghai
SW_TELEMETRY: prometheus
skywalking-ui:
image: apache/skywalking-ui:10.1.0
container_name: skywalking-ui
restart: always
depends_on:
- skywalking-oap-server
links:
- skywalking-oap-server
ports:
- "8051:8080"
environment:
SW_OAP_ADDRESS: http://skywalking-oap-server:12800
TZ: Asia/Shanghai
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
skywalking默认使用H2数据库,可以通过SW_STORAGE
环境变量指定使用的存储,可以作为验证功能临时使用。
skywalking支持配置MySQL存储,但是由于开源协议不同,需要自己引入MySQL驱动。
实际测试发现,直接将驱动jar包放入/skywalking/oap-libs
目录下,运行时可以被程序加载,但是依旧会报错没有合适的驱动。
在原镜像的基础上,自己构建镜像,将MySQL驱动jar包放入/skywalking/oap-libs
目录下,通过自己构建的镜像运行,不再报错找不到驱动,但是无法连接到指定的MySQL数据库。配置的MySQL 用户名、链接地址失效,总是连接root@机器公网IP。 未找到解决办法,放弃使用MySQL存储。
况且使用MySQL存储,会影响后续数据处理性能,也不利于存储扩展。所以选择使用ElasticSearch存储。
# Java Agent
由于通过Docker部署java应用,为了方便使用,将agent打包到应用镜像中。
编写Dockerfile:
FROM openjdk:8-jdk
ENV TZ=Asia/Shanghai
# SkyWalking Agent
COPY skywalking-agent-9.0.0 ./skywalking-agent
2
3
4
部署java应用的Dockerfile:
FROM jdk8:baseImage
ARG appName
ENV APP_NAME=${appName}
ENV SW_AGENT_NAME=${appName}
ENV SW_AGENT_COLLECTOR_BACKEND_SERVICES=${oapIp}:11800
COPY *.jar /app.jar
ENTRYPOINT ["tini", "--", "sh", "-c", " exec java -jar -javaagent:/skywalking-agent/skywalking-agent.jar -Dskywalking.trace.ignore_path=/resources/**,Redisson/**,Lettuce/**,Mysql/JDBI/**,/nacos/**,Mysql/JDBC/**,HikariCP/** /app.jar"]
2
3
4
5
6
7
8
9
10
11
12
13
14
# 服务器监控
通过node-exporter采集服务器监控数据,通过opentelemetry-collector抓取数据,上报到skywalking。
# node-exporter
services:
node-exporter:
image: prom/node-exporter:v1
container_name: node-exporter
hostname: node-exporter
ports:
- "9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
restart: always
2
3
4
5
6
7
8
9
10
11
12
部署到服务器上,通过9100
端口访问。
# opentelemetry-collector
services:
otel-collector:
image: otel/opentelemetry-collector:0.113.0
container_name: otel-collector
command: [ "--config=/etc/otel-collector-config.yaml" ]
depends_on:
- skywalking-oap-server
links:
- skywalking-oap-server
volumes:
- ./config/opentelemetry/otel-collector-config.yaml:/etc/otel-collector-config.yaml
expose:
- 55678
2
3
4
5
6
7
8
9
10
11
12
13
otel-collector-config.yaml
配置文件:
receivers:
prometheus:
config:
scrape_configs:
- job_name: "vm-monitoring" # make sure to use this in the vm.yaml to filter only VM metrics
scrape_interval: 10s
static_configs:
- targets: ["192.168.1.1:9100"]
processors:
batch:
exporters:
otlp:
endpoint: "skywalking-oap-server:11800" # The OAP Server address
# The config format of OTEL version prior to 0.34.0, eg. 0.29.0, should be:
# insecure: true
tls:
insecure: true
#insecure: true
service:
pipelines:
metrics:
receivers: [prometheus]
processors: [batch]
exporters: [otlp]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
可以写到oap和UI的docker-compose.yml文件中,一起部署。
# 监控日志清理
日志写入Elasticsearch
,上报日志数据量大,需要定期清理
起初尝试使用elasticsearch-curator工具清理,但是该工具在判断数据量条件时采用的是多个索引累加,然后删除超过数量之后的索引,累加的顺序逻辑复杂,无法批量处理针对单个系列的索引,例如 sw_segment-*
,sw_log-*
,遂放弃。
转而使用Elasticsearch提供的ILM(索引生命周期管理)工具。通过索引的年龄、文档数、数据量触发条件,滚动到新索引,将原索引删除。但是由于Skywalking写入索引不支持自定义,滚动生成的新索引无法被Skywalking识别,会导致skywalking写入失败,也放弃。
最终通过shell脚本灵活删除日志:
#!/bin/bash
# 参数
# $1: 删除索引的大小阈值,单位为GB
# $2: 删除索引的年龄阈值,单位为天
set -e
# Elasticsearch 主机和端口
ES_HOST=
del_by_size() {
del_size=$1
# 获取所有 sw_* 开头的索引及其大小
indices=$(curl -s "$ES_HOST/_cat/indices/sw_*?h=index,store.size&format=json")
# 遍历每个索引
echo "$indices" | jq -c '.[]' | while read -r index; do
index_name=$(echo "$index" | jq -r '.index')
# 排除 sw_management
if [ "$index_name" == "sw_management" ]; then
continue
fi
index_size=$(echo "$index" | jq -r '.["store.size"]')
# 将大小转换为字节
size_in_bytes=$(echo "$index_size" | sed 's/[bB]//g' | sed 's/k/K/g; s/m/M/g; s/g/G/g; s/t/T/g' | numfmt --from=iec)
# 如果大小超过 nGB,则删除索引
if [ "$size_in_bytes" -gt "$del_size" ]; then
echo "Deleting index $index_name with size $index_size"
curl -X DELETE "$ES_HOST/$index_name"
#换行
echo
fi
done
}
# 删除超过n天的索引
del_by_age() {
del_age=$1
# 获取所有 sw_* 开头的索引及其创建时间
indices=$(curl -s "$ES_HOST/_cat/indices/sw_*?h=index,creation.date.string&format=json")
# 当前日期的时间戳
current_date=$(date +%s)
# 遍历每个索引
echo "$indices" | jq -c '.[]' | while read -r index; do
index_name=$(echo "$index" | jq -r '.index')
## 排除 sw_management
if [ "$index_name" == "sw_management" ]; then
continue
fi
creation_date=$(echo "$index" | jq -r '.["creation.date.string"]')
# 将创建日期转换为时间戳
creation_timestamp=$(date -d "$creation_date" +%s)
# 计算索引的年龄(天)
age=$(((current_date - creation_timestamp) / 86400))
# 如果年龄超过n天,则删除索引
if [ "$age" -gt "$del_age" ]; then
echo "Deleting index $index_name created on $creation_date"
curl -X DELETE "$ES_HOST/$index_name"
#换行
echo
fi
done
}
DEL_SIZE_G=$1
DEL_AGE_DAY=$2
DEL_SIZE_B=$(($DEL_SIZE_G * 1024 * 1024 * 1024))
# 打印执行时间
echo "Start time: $(date) 参数:删除大小阈值 $DEL_SIZE_G GB,删除年龄阈值 $DEL_AGE_DAY 天"
# 调用函数
del_by_size $DEL_SIZE_B
del_by_age $DEL_AGE_DAY
# 打印执行时间
echo "End time: $(date)"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
命令行执行 crontab -e
,将脚本加入到定时任务中:
0 0 * * * /bin/bash /path/to/delete_index.sh 20 90 >> /path/to/delete_index.log 2>&1