1.概念
SkyWalking 是什么?
分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。提供分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案。目前Skywalking已迭代到9.3.0,支持Mysql/Postgresql Database监控,还支持慢日志查询,快快尝试一下新功能吧。
SkyWalking有哪些功能?
- 多种监控手段。可以通过语言探针和service mesh获得监控数据。
- 多个语言自动探针。包括 Java,.NET Core和Node.JS。
- 轻量高效。无需大数据平台,和大量的服务器资源。
- 模块化。UI、存储、集群管理都有多种机制可选。
- 支持告警。
- 优秀的可视化解决方案。
整体架构设计
整个架构,分成上、下、左、右四部分:
考虑到让描述更简单,我们舍弃掉 Metric 指标相关,而着重在Tracing链路相关功能。
- 上部分 Agent :负责从应用中,收集链路信息,发送给 SkyWalking OAP 服务器。目前支持 SkyWalking、Zikpin、Jaeger 等提供的 Tracing 数据信息。而我们目前采用的是,SkyWalking Agent 收集 SkyWalking Tracing 数据,传递给服务器。
- 下部分 SkyWalking OAP :负责接收 Agent 发送的 Tracing 数据信息,然后进行分析(Analysis Core) ,存储到外部存储器( Storage ),最终提供查询( Query )功能。
- 右部分 Storage :Tracing 数据存储。目前支持 ES、MySQL、Sharding Sphere、TiDB、H2 多种存储器。而我们目前采用的是 ES ,主要考虑是 SkyWalking 开发团队自己的生产环境采用 ES 为主。
- 左部分 SkyWalking UI :负责提供控台,查看链路等等。
2.搭建SkyWalking
Docker中搭建一个SkyWalking单机环境,步骤如下:
- 第一步,搭建一个Elasticsearch服务(8.2.0版本为例)。
- 第二步,搭建一个SkyWalking OAP服务(以最新的9.3.0为例)。
- 第三步,搭建一个SkyWalking UI服务。
- 第四步,启动一个SpringBoot应用,并配置SkyWalking Agent。
- 第五步,监听Database(Mysql/Postgresql)
Elasticsearch搭建
搭建命令:
#创建数据挂载文件
mkdir -p /Users/advance/docker/elasticsearch/config/
mkdir -p /Users/advance/docker/elasticsearch/data/
chmod -R 777 /mydata/elasticsearch
#拉取镜像
docker pull elasticsearch:8.2.0
#启动容器
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e discovery.type=single-node -e ES_JAVA_OPS="-Xms256m -Xmx256m" -e TZ=Asia/Shanghai -v /Users/advance/docker/elasticsearch/config:/usr/share/elasticsearch/config -v /Users/advance/docker/elasticsearch/data:/usr/share/elasticsearch/data -v /Users/advance/docker/elasticsearch/plugins:/usr/share/elasticsearch/plugins elasticsearch:8.2.0
注:
elasticsearch8.2.0默认开启ssl,如果不需要ssl则可以在/config/application.yaml中关闭
如果是单节点,需要discovery.type=single-node
9200:是ES节点与外部通讯使用的端口。是http协议的RESTful接口(各种CRUD操作都是走的该端口)。
9300:是ES节点之间通讯使用的端口。它是tcp通讯端口,集群间和TCPclient都走的它。)
访问端口9200,如下所示,表明elasticsearch容器已启动
Skywalking OAP
#拉取镜像
docker pull apache/skywalking-oap-server:9.3.0
#启动容器
docker run -d --name skywalking-oap --restart always -p 11800:11800 -p 12800:12800 -e SW_STORAGE=elasticsearch -e SW_STORAGE_ES_CLUSTER_NODES=xxx.xxx.xxx.xxx:9200 apache/skywalking-oap-server:9.3.0
SW_STORAGE:=elasticsearch:选择es存储监控数据。
SW_STORAGE_ES_CLUSTER_NODES=xxx.xxx.xxx.xxx:9200:ES host地址
11800:用于数据采集后上报的gRPC协议端口
12800:用于skywalking-ui进行监控数据查询的HTTP协议端口
访问12800端口,如下所示,表明skywalking-oap容器已启动
Skywalking UI
#拉取镜像
docker pull apache/skywalking-ui:9.3.0
#启动容器
docker run -d --name skywalking-ui --restart always -p 8088:8080 --link skywalking-oap:skywalking-oap -e TZ=Asia/Shanghai -e SW_OAP_ADDRESS=http://xxx.xxx.xxx.xxx:12800 -v /etc/localtime:/etc/localtime:ro apache/skywalking-ui:9.3.0
访问12800端口,如下所示,表明skywalking-ui容器已启动
SkyWalking Agent
下载Skywalkling-agent(通过如下链接进行下载,下载8.14.0版本)
wget https://dlcdn.apache.org/skywalking/java-agent/8.14.0/apache-skywalking-java-agent-8.14.0.tgz
#解压tar到/opt/skywalking
tar -zxvf apache-skywalking-java-agent-8.14.0.tgz -C /opt/skywalking
配置Skywalkling-agent
接下来要配置的是Skywalking的agent和web的配置,如下:
#探针的配置 修改agent.config配置如下:
vim /opt/skywalking/agent/config/agent.config
agent.service_name=Your_ApplicationName #改为你的项目名字
collector.backend_service=xxx.xxx.xxx.xxx:11800,xxx.xxx.xxx.xxx:11800,xxx.xxx.xxx.xxx:11800 #collector的端口服务地址;
注:
端口11800是agent与Skywalking-OAP collect进行grpc协议通信的端口地址,端口12800是ui与Skywalking-OAP collect进行http协议通信的端口地址
启动服务
接下来就可以启动agent
#在启动你的应用程序的命令行中添加 -javaagent 参数. 并确保在-jar参数之前添加它. 例如:
java -javaagent:/opt/skywalking/agent/skywalking-agent.jar -jar yourApp.jar
注:
java -javaagent:后面一定要写skywalking-agent.jar的绝对目录,并且要保证skywalking-agent.jar能够读取到config目录下的agent.config配置文件。
启动成功后有如下服务被监听:
监听Postgresql
Skywalking9.3.0支持监听Postgresql,它没有自己的监听插件,而是通过postgresql-exporter、opentelemetry-collector实现对Postgresql监控
Postgres-exporter配置
#DATA_SOURCE_NAME formats: postgresql://UserName:Password@IpAddr:PortNumber/core?sslmode=disable
docker run -d --name postgres-exporter -p 9187:9187 -e DATA_SOURCE_NAME="postgresql://postgres:XXXXX@XXX.XXX.XXX.XXX:5432/core?sslmode=disable" -e TZ="Asia/Shanghai" prometheuscommunity/postgres-exporter
opentelemetry-collector配置
docker-compose.yaml
version: '3.8'
services:
otel-collector:
image: otel/opentelemetry-collector
container_name: opentelemetry-collector
command: [ "--config=/etc/otel-collector-config.yaml" ]
volumes:
- /Users/advance/docker/opentelemetry-collector/otel-collector-config.yaml:/etc/otel-collector-config.yaml
expose:
- 55678
otel-collector-config.yaml
receivers:
prometheus:
config:
scrape_configs:
- job_name: 'postgresql-monitoring'
scrape_interval: 5s
static_configs:
- targets: ['xxx.xxx.xxx.xxx:9187']
labels:
host_name: postgres:5432
processors:
batch:
exporters:
otlp:
# push skywalking url
endpoint: http://xxx.xxx.xxx.xxx:11800
tls:
insecure: true
service:
pipelines:
metrics:
receivers:
- prometheus
processors:
- batch
exporters:
- otlp
job_name: postgresql-monitoring
targets: Postgresql-export服务地址
endpoint:Skywalking OAP服务地址
host_name: 被监控服务名称
Postgresql慢查询配置
Skywalking通过flunt-bit完成对Postgresql慢查询的监控
开启Postgresql慢查询
更改 ../pddata/postgresql.conf
logging_collector = on
log_directory = 'log' // 慢日志存储目录
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_rotation_size = 1024MB
log_min_messages = info
log_min_duration_statement = 20 // unit:ms 慢日志最小执行时间
log_line_prefix = '%m'
log_timezone = 'Asia/Shanghai'
datestyle = 'iso, mdy'
timezone = 'Asia/Shanghai'
Skywalking监控Postgresql慢查询需要三个配置文件,分别是:
flunt-bit.conf/flunt-bit-script.lua/flunt-bit-parser.conf
flunt-bit.conf如下:
[SERVICE]
flush 1
log_level info
parsers_File fluent-bit-parser.conf
[INPUT]
name tail
path /tmp/skywalking-logs/postgresql-*.log
parser my-log-format
[FILTER]
name grep
match *
regex log \w*-\w*-\w* \w*:\w*:\w*.\w* WIBLOG: duration: \w*.\w* statement.*
[FILTER]
name lua
match *
script fluent-bit-script.lua
call rewrite_body
[OUTPUT]
name stdout
match *
format json
[OUTPUT]
name http
match *
# Skywalking OAP address
host xxx.xxx.xxx.xxx
port 12800
uri /v3/logs
format json
flunt-bit-script.lua如下:
function rewrite_body(tag, timestamp, record)
log = record["log"]
record["log"] = nil
record["date"] = nil
record["tags"] = {data={{key="LOG_KIND", value="SLOW_SQL"}}}
arr = split(log,"\n")
re1 = {}
re1["time"] = os.time() * 1000
re1["layer"] = "POSTGRESQL"
record["layer"] = "POSTGRESQL"
_,durationIndex = string.find(log,"duration: ")
msIndex,_ = string.find(log," ms")
duration = string.sub(log,durationIndex+1,msIndex)
_,statementAf = string.find(log,"statement: ")
re1["statement"] = string.sub(log,statementAf+1)
duration = string.sub(log,durationIndex+1,msIndex-1)
d1 = math.floor(tonumber(duration))
re1["query_time"] = d1
record["service"]="postgresql::postgres:5432"
re1["service"]= "postgresql::postgres:5432"
re1["id"] = uuid()
jsonstr = table2json(re1)
record["body"]={json={}}
record["body"]["json"]["json"] = jsonstr
return 1, timestamp, record
end
function split(input, delimiter)
input = tostring(input)
delimiter = tostring(delimiter)
if (delimiter == "") then return false end
local pos, arr = 0, {}
for st, sp in function() return string.find(input, delimiter, pos, true) end do
table.insert(arr, string.sub(input, pos, st - 1))
pos = sp + 1
end
table.insert(arr, string.sub(input, pos))
return arr
end
function uuid()
local seed={'e','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}
local tb={}
for i=1,32 do
table.insert(tb,seed[math.random(1,16)])
end
local sid=table.concat(tb)
return string.format('%s-%s-%s-%s-%s',
string.sub(sid,1,8),
string.sub(sid,9,12),
string.sub(sid,13,16),
string.sub(sid,17,20),
string.sub(sid,21,32)
)
end
function table2json(t)
local function serialize(tbl)
local tmp = {}
for k, v in pairs(tbl) do
local k_type = type(k)
local v_type = type(v)
local key = (k_type == "string" and '"' .. k .. '":') or (k_type == "number" and "")
local value =
(v_type == "table" and serialize(v)) or (v_type == "boolean" and tostring(v)) or
(v_type == "string" and '"' .. v .. '"') or
(v_type == "number" and v)
tmp[#tmp + 1] = key and value and tostring(key) .. tostring(value) or nil
end
if table.maxn(tbl) == 0 then
return "{" .. table.concat(tmp, ",") .. "}"
else
return "[" .. table.concat(tmp, ",") .. "]"
end
end
assert(type(t) == "table")
return serialize(t)
end
flunt-bit-parser.conf如下:
[PARSER]
name my-log-format
format regex
regex \w*-\w*-\w* \w*:\w*:\w*.\w* WIBLOG: duration: \w*.\w* ms statement.**
启动flunt-bit命令:
docker run -d --name fluent-bit -p 24224:24224 -e TZ=Asia/Shanghai -v /docker/postgresql/pgdata/log:/tmp/skywalking-logs -v /docker/fluent-bit/fluent-bit/etc/fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf -v /docker/fluent-bit/fluent-bit/etc/fluent-bit-parser.conf:/fluent-bit/etc/fluent-bit-parser.conf -v /docker/fluent-bit/fluent-bit/etc/fluent-bit-script.lua:/fluent-bit/etc/fluent-bit-script.lua fluent/fluent-bit:2.0.9
启动成功后进入Skywalking-ui如下,可以看到被监控的Postgresql服务:
同时也可以看到慢sql:
Skywalking官方文档:
https://skywalking.apache.org/docs/main/v9.3.0/readme/
Skywalking监控Postgresql Example:
https://github.com/apache/skywalking/tree/7ad04062b20ecf2bdb0afc4ba8c6ce353e5ae4d8/test/e2e-v2/cases/postgresql/postgres-exporter