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
1
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
1
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"]

1
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
1
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
1
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]
1
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)"

1
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
1
上次更新: 2024/11/27, 13:48:55
最近更新
01
docker-compose笔记
01-12
02
MySQL数据迁移
11-27
03
Docker部署服务,避免PID=1
11-27
更多文章>