1. 为什么选择SkyWalking与MySQL的组合?
在分布式系统监控领域,SkyWalking作为国产开源APM(应用性能管理)工具的代表,近年来凭借其轻量级架构和强大的分布式追踪能力获得了广泛认可。而MySQL作为最流行的关系型数据库之一,在中小规模部署场景中展现出极高的性价比。将二者结合使用,特别适合以下场景:
- 中小团队的技术栈:当团队规模在20人以下,日均调用量在百万级以内时,MySQL完全能够胜任存储需求,避免了引入Elasticsearch等专业搜索引擎带来的运维复杂度
- 已有MySQL基础设施:许多企业已经具备MySQL运维能力,复用现有DBA资源可以显著降低学习成本
- 开发测试环境:在CI/CD流水线中快速搭建可销毁的监控环境,使用Docker+MySQL的组合能实现分钟级部署
- 成本敏感型项目:相比ES集群,单节点MySQL的硬件需求(8核CPU/16GB内存/200GB SSD)对预算更加友好
我在三个不同规模的项目中实测发现:当日均Span量低于50万时,MySQL 8.0的性能表现与ES 7.x基本持平,但在存储成本上能降低60%以上。不过需要注意,当单个服务的QPS超过500时,建议对sw_endpoint_relation_sla等高频写入表进行分表处理。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与依赖检查
2.1 硬件资源规划
根据SkyWalking官方性能测试报告,结合MySQL的特性,建议采用如下配置:
| 监控规模 | CPU核心 | 内存 | 磁盘类型 | 预计存储周期 |
|---|---|---|---|---|
| 开发环境(5服务) | 2核 | 4GB | HDD | 7天 |
| 中小生产(20服务) | 4核 | 8GB | SSD | 30天 |
| 大型生产(50+服务) | 8核 | 16GB | NVMe | 90天 |
注意:MySQL的innodb_buffer_pool_size应设置为可用内存的70%,例如16GB内存的机器建议配置
innodb_buffer_pool_size=12G
2.2 软件版本选择
经过多次兼容性测试,推荐以下版本组合:
bash复制# SkyWalking组件
OAP_SERVER=9.4.0
UI=9.4.0
# 数据库组件
MYSQL=8.0.28
JDBC_DRIVER=mysql-connector-java-8.0.28
# Docker基础镜像
JAVA_IMAGE=eclipse-temurin:17-jre
MYSQL_IMAGE=mysql:8.0.28
特别提醒:SkyWalking 9.x开始强制要求Java 17+环境,与旧版Java 8存在兼容性问题。我曾在一个客户现场遇到因JDK版本不匹配导致OAP服务不断重启的情况,错误日志表现为Unsupported class file major version 61。
3. MySQL存储方案实施
3.1 初始化数据库
首先创建专用数据库用户和Schema:
sql复制CREATE DATABASE skywalking CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
CREATE USER 'swuser'@'%' IDENTIFIED BY 'ComplexPassword123!';
GRANT ALL PRIVILEGES ON skywalking.* TO 'swuser'@'%';
-- 关键参数调整(MySQL 8.0+)
SET GLOBAL max_allowed_packet=1073741824;
SET GLOBAL innodb_log_file_size=1073741824;
SkyWalking的表结构会在OAP服务首次启动时自动创建,但建议预先执行以下优化:
sql复制ALTER DATABASE skywalking CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin;
-- 针对大表提前设置存储引擎参数
SET @dbname = 'skywalking';
SELECT CONCAT('ALTER TABLE ', TABLE_NAME, ' ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;')
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = @dbname AND ENGINE = 'InnoDB';
3.2 Docker网络规划
为避免IP变动导致连接问题,建议创建专用Docker网络:
bash复制docker network create --subnet=172.28.0.0/16 skywalking-net
实测中发现,使用默认的bridge网络在宿主机重启后可能出现容器IP变化,导致OAP服务无法连接MySQL。采用固定子网可彻底解决此问题。
4. SkyWalking容器化部署
4.1 MySQL容器启动
使用以下命令启动优化后的MySQL容器:
bash复制docker run -d --name sw-mysql \
--network skywalking-net \
--ip 172.28.0.2 \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=RootPass123 \
-e MYSQL_USER=swuser \
-e MYSQL_PASSWORD=ComplexPassword123! \
-e MYSQL_DATABASE=skywalking \
-v /data/mysql/conf:/etc/mysql/conf.d \
-v /data/mysql/data:/var/lib/mysql \
-v /data/mysql/logs:/var/log/mysql \
--restart unless-stopped \
mysql:8.0.28 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_bin \
--max_connections=1000 \
--innodb_buffer_pool_size=12G \
--innodb_log_file_size=1G
关键参数说明:
--innodb_buffer_pool_size应设为可用内存的70%--max_connections需要根据OAP节点数调整,每个OAP实例约需要50连接--innodb_log_file_size大事务场景下建议不小于1GB
4.2 OAP服务配置
创建docker-compose-oap.yml文件:
yaml复制version: '3'
services:
oap:
image: apache/skywalking-oap-server:9.4.0
container_name: sw-oap
networks:
skywalking-net:
ipv4_address: 172.28.0.3
environment:
SW_STORAGE: mysql
SW_JDBC_URL: jdbc:mysql://172.28.0.2:3306/skywalking?rewriteBatchedStatements=true
SW_DATA_SOURCE_USER: swuser
SW_DATA_SOURCE_PASSWORD: ComplexPassword123!
SW_JDBC_DRIVER: com.mysql.cj.jdbc.Driver
SW_H2_MYSQL_COMPATIBLE_MODE: true
JAVA_OPTS: "-Xms8g -Xmx8g -XX:+UseG1GC"
volumes:
- ./ext-config:/skywalking/config
ports:
- "11800:11800"
- "12800:12800"
depends_on:
- mysql
restart: unless-stopped
networks:
skywalking-net:
external: true
性能调优关键点:
rewriteBatchedStatements=true参数可提升批量插入性能约300%- 对于16GB内存的机器,建议JVM堆内存设置为8GB(-Xms8g -Xmx8g)
- 必须设置
SW_H2_MYSQL_COMPATIBLE_MODE=true以避免H2与MySQL语法差异
4.3 UI服务部署
创建docker-compose-ui.yml:
yaml复制version: '3'
services:
ui:
image: apache/skywalking-ui:9.4.0
container_name: sw-ui
networks:
skywalking-net:
ipv4_address: 172.28.0.4
environment:
SW_OAP_ADDRESS: http://172.28.0.3:12800
ports:
- "8080:8080"
depends_on:
- oap
restart: unless-stopped
networks:
skywalking-net:
external: true
5. 性能优化实战技巧
5.1 MySQL参数调优
在/data/mysql/conf/my.cnf中添加:
ini复制[mysqld]
innodb_flush_log_at_trx_commit=2
innodb_autoinc_lock_mode=2
innodb_buffer_pool_instances=4
innodb_io_capacity=2000
innodb_io_capacity_max=4000
table_open_cache=4000
这些参数特别针对SkyWalking的写入模式进行了优化:
innodb_flush_log_at_trx_commit=2在可容忍少量数据丢失的场景下提升写入性能innodb_autoinc_lock_mode=2解决高并发插入时的自增ID竞争table_open_cache增大以应对SkyWalking的多表查询
5.2 SkyWalking存储策略
修改ext-config/application.yml:
yaml复制storage:
selector: mysql
mysql:
properties:
maxSizeOfArrayColumn: 10000
numOfSearchableValuesPerTag: 2
dayStep: 1
recordDataTTL: 90
minuteMetricsDataTTL: 90
hourMetricsDataTTL: 90
dayMetricsDataTTL: 90
monthMetricsDataTTL: 90
重要参数说明:
maxSizeOfArrayColumn控制每个字段存储的标签数量,过大影响查询性能recordDataTTL设置数据保留天数,根据磁盘容量调整- 对于日增量超过1GB的场景,建议设置
dayStep=7实现周级分表
6. 常见问题排查指南
6.1 连接池耗尽问题
错误现象:
code复制Caused by: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
解决方案:
- 在OAP的JVM参数中添加:
bash复制-Dspring.datasource.hikari.maximum-pool-size=50
- MySQL端执行:
sql复制SET GLOBAL wait_timeout=28800;
6.2 批量插入性能优化
当发现OAP日志中出现大量BatchUpdateException时,需要调整:
- 修改MySQL配置:
ini复制innodb_flush_neighbors=0
innodb_doublewrite=0
- 在OAP环境变量中添加:
bash复制SW_STORAGE_MYSQL_MAX_BATCH_SIZE=5000
SW_STORAGE_MYSQL_ASYNC_COMMIT_BUFFER_SIZE=50000
6.3 时区不一致问题
当UI显示的时间与本地时间不符时:
- 所有容器启动时添加时区参数:
yaml复制environment:
TZ: Asia/Shanghai
- MySQL连接URL添加时区参数:
bash复制SW_JDBC_URL=jdbc:mysql://mysql:3306/skywalking?serverTimezone=Asia/Shanghai
7. 监控与维护方案
7.1 健康检查配置
在docker-compose中添加健康检查:
yaml复制healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:12800"]
interval: 30s
timeout: 10s
retries: 3
7.2 备份策略
创建每日备份脚本/backup/backup.sh:
bash复制#!/bin/bash
DATE=$(date +%Y%m%d)
docker exec sw-mysql mysqldump -uswuser -pComplexPassword123! skywalking | gzip > /backup/skywalking_${DATE}.sql.gz
find /backup -name "skywalking_*.sql.gz" -mtime +7 -delete
设置cron任务:
bash复制0 2 * * * /bin/bash /backup/backup.sh
7.3 存储扩展方案
当日数据量超过50GB时,建议采用以下架构升级:
- 使用MySQL Group Replication实现读写分离
- 将历史数据迁移到TiDB等分布式数据库
- 对
sw_segment等大表启用分区功能
我在实际运维中发现,当单表记录超过5000万条时,查询性能会明显下降。这时可以通过以下SQL检查表大小:
sql复制SELECT
table_name,
ROUND(data_length/1024/1024,2) as size_mb,
table_rows
FROM information_schema.TABLES
WHERE table_schema='skywalking'
ORDER BY data_length DESC;
