第3章:数据库监控与优化

数据库,说白了就是量化系统的「账本」。

行情数据、订单记录、账户资金、策略参数……全得靠它存着。我见过不少团队,策略写得漂亮,但一到盘中数据库就崩了,结果单子没发出去,亏得那叫一个惨。所以今天咱们聊聊数据库监控,重点放在关系型和非关系型这两大类上。

3.1 关系型数据库监控指标

关系型数据库,MySQL 和 PostgreSQL 是主流。我个人习惯把监控指标分成三层:系统层、引擎层、查询层

3.1.1 系统层指标

  • 连接数:当前活跃连接 vs 最大连接数。我建议设置告警阈值在 80%。
  • QPS/TPS:每秒查询数、每秒事务数。突然飙升往往意味着有慢查询或死锁。
  • 缓存命中率:InnoDB buffer pool 命中率低于 95% 就该加内存了。
  • 磁盘 IO:尤其是 iowait 和每秒读写量。量化系统高频写入时,磁盘很容易成为瓶颈。

核心指标速查表

指标MySQLPostgreSQL
连接数Threads_connectednumbackends
缓存命中Innodb_buffer_pool_read_requests / Innodb_buffer_pool_readsblks_hit / (blks_hit + blks_read)
事务数Com_commit + Com_rollbackxact_commit + xact_rollback
死锁Innodb_deadlocksdeadlocks

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 数据库监控体系总览

说了这么多,咱们用一张图把关系型和非关系型的监控要点串起来。

数据库监控体系总览 关系型数据库 MySQL / PostgreSQL 系统层指标 连接数 · QPS/TPS · 缓存命中率 · 磁盘IO 查询层分析 慢查询日志 · EXPLAIN · 索引优化 连接池监控 活跃连接 · 空闲连接 · 等待队列 · 超时 NoSQL数据库 Redis / MongoDB Redis 监控要点 内存使用率 · 键淘汰 · 持久化延迟 慢查询 · 避免 KEYS * MongoDB 监控要点 opcounters · 连接数 · 慢查询 索引命中率 · 缓存池配置 共同关注 核心原则:先监控,后优化;先告警,后排查

说白了,数据库监控不是一锤子买卖。你想想看,量化系统跑着跑着,数据量越来越大,查询越来越慢,连接数越来越多——这些都是渐进的过程。所以我的习惯是:每天看一次核心指标,每周分析一次慢查询,每月做一次容量规划

嗯,今天就聊到这儿。数据库这块儿,监控做好了,能省下不少半夜爬起来排查问题的精力。


公众号:蓝海资料掘金营,微信deep3321