第3章:数据库监控与优化
数据库,说白了就是量化系统的「账本」。
行情数据、订单记录、账户资金、策略参数……全得靠它存着。我见过不少团队,策略写得漂亮,但一到盘中数据库就崩了,结果单子没发出去,亏得那叫一个惨。所以今天咱们聊聊数据库监控,重点放在关系型和非关系型这两大类上。
3.1 关系型数据库监控指标
关系型数据库,MySQL 和 PostgreSQL 是主流。我个人习惯把监控指标分成三层:系统层、引擎层、查询层。
3.1.1 系统层指标
- 连接数:当前活跃连接 vs 最大连接数。我建议设置告警阈值在 80%。
- QPS/TPS:每秒查询数、每秒事务数。突然飙升往往意味着有慢查询或死锁。
- 缓存命中率:InnoDB buffer pool 命中率低于 95% 就该加内存了。
- 磁盘 IO:尤其是 iowait 和每秒读写量。量化系统高频写入时,磁盘很容易成为瓶颈。
核心指标速查表
| 指标 | MySQL | PostgreSQL |
|---|---|---|
| 连接数 | Threads_connected | numbackends |
| 缓存命中 | Innodb_buffer_pool_read_requests / Innodb_buffer_pool_reads | blks_hit / (blks_hit + blks_read) |
| 事务数 | Com_commit + Com_rollback | xact_commit + xact_rollback |
| 死锁 | Innodb_deadlocks | deadlocks |
3.1.2 慢查询分析
慢查询是数据库性能的「照妖镜」。我曾经接手过一个回测系统,每天跑完回测要等半小时才能出结果。一查慢查询日志,发现有个 SQL 没走索引,全表扫描了上千万条记录。
怎么查?
- MySQL:开启 slow_query_log,设置 long_query_time = 1(秒)。
- PostgreSQL:设置 log_min_duration_statement = 1000(毫秒)。
拿到慢查询后,用 EXPLAIN 分析执行计划。重点关注:
- type:ALL 或 index 说明没走索引,得优化。
- rows:扫描行数远大于返回行数,说明过滤条件不够好。
- Extra:出现 Using filesort 或 Using temporary 要警惕。
我的小技巧:慢查询日志别一直开着,生产环境开 10 分钟采样就够了。否则日志文件能撑爆磁盘。
3.1.3 连接池监控
连接池是数据库的「门卫」。量化系统里,策略进程和数据库之间频繁交互,如果连接池配置不当,很容易出现「连接泄露」或「连接耗尽」。
我建议监控这几个指标:
- 活跃连接数:当前正在执行 SQL 的连接。
- 空闲连接数:等待被复用的连接。太少说明池子太小。
- 等待队列长度:连接不够用时,请求会排队。队列一长,延迟就上去了。
- 连接超时次数:超过最大等待时间还没拿到连接,直接报错。
常用的连接池中间件有 HikariCP(Java)、psycopg2.pool(Python)、DBUtils。我个人偏好 HikariCP,性能确实好。
避坑指南:我曾经在生产环境遇到过连接池「假死」——连接池显示有连接,但实际已经断开了。后来加了连接有效性检测(validationQuery),每 30 秒 ping 一次数据库,问题就解决了。
3.2 NoSQL 数据库监控要点
量化系统里,Redis 和 MongoDB 用得最多。Redis 做缓存和消息队列,MongoDB 存非结构化的日志和回测结果。
3.2.1 Redis 监控
Redis 是纯内存操作,所以监控重点在内存和持久化。
- 内存使用率:used_memory / maxmemory。超过 80% 就要考虑扩容或淘汰策略。
- 键过期淘汰:evicted_keys 突然增加,说明内存不够了,大量 key 被强制淘汰。
- 持久化延迟:RDB 或 AOF 写入磁盘时,会 fork 子进程。如果 fork 时间超过 1 秒,主线程会卡住。
- 慢查询:Redis 也有 slowlog,默认超过 10000 微秒(10ms)就记录。
Redis 监控命令速查
# 查看内存
INFO memory
# 查看慢查询
SLOWLOG GET 10
# 查看连接数
INFO clients
# 查看持久化状态
INFO persistence
嗯,这里要注意:Redis 的 KEYS * 命令千万别在生产环境用。我见过有人用这个命令查数据,结果 Redis 直接卡死 5 秒,所有请求都超时了。用 SCAN 代替。
3.2.2 MongoDB 监控
MongoDB 的监控,我重点关注操作延迟和连接数。
- opcounters:每秒的 insert、query、update、delete 次数。突然下降可能意味着客户端连不上了。
- 连接数:current 连接数 vs 最大连接数。MongoDB 默认最大连接数是 65536,但实际受限于文件描述符。
- 慢查询:通过 db.setProfilingLevel(1, 100) 开启慢查询日志,超过 100ms 的查询会被记录。
- 索引命中率:totalKeysExamined / totalDocsExamined。如果这个比值接近 1,说明索引用得好;如果远大于 1,说明索引效率低。
我的经验:MongoDB 的 WiredTiger 存储引擎有缓存池,默认是 50% 的物理内存。如果内存不够,缓存命中率会下降,查询变慢。我一般会把这个比例调到 60%-70%,但别超过 80%,要给操作系统留点余量。
3.3 数据库监控体系总览
说了这么多,咱们用一张图把关系型和非关系型的监控要点串起来。
说白了,数据库监控不是一锤子买卖。你想想看,量化系统跑着跑着,数据量越来越大,查询越来越慢,连接数越来越多——这些都是渐进的过程。所以我的习惯是:每天看一次核心指标,每周分析一次慢查询,每月做一次容量规划。
嗯,今天就聊到这儿。数据库这块儿,监控做好了,能省下不少半夜爬起来排查问题的精力。
公众号:蓝海资料掘金营,微信deep3321