第 4 篇:性能治理不是只看 CPU

数据库一变慢,很多团队的第一反应是升配。CPU 高了,升。内存紧了,升。吞吐不稳,再升。这么做不是永远没用,但它经常把真正的问题盖住,而且特别烧钱。

云数据库里的性能问题,绝大多数都不是一句“机器不够大”能解释完的。更真实的情况往往是几种问题叠在一起:

  • SQL 写得差
  • 索引设计不对
  • 连接池开得太大
  • 热点键或热点分区集中打爆
  • 缓存命中率下降
  • 后台批处理和线上流量抢资源
  • 只读副本复制延迟,导致读流量也开始抖

最后在监控上统一表现为:延迟变高、吞吐变差、错误率上升。

先分清楚是吞吐问题还是延迟问题

性能问题最怕一上来就优化。第一步应该是分类,不是调参。

你得先搞清楚到底是哪种慢:

  • 是平均延迟上升,还是尾延迟恶化
  • 是全局变慢,还是某几个接口特别慢
  • 是读变慢,写变慢,还是连接建立变慢
  • 是稳定高负载,还是周期性抖动

这一步很关键。因为如果你的问题是少量慢查询把连接和工作线程卡住,那你就算升配,爆炸机制也还在,只是把爆炸时间往后推了一点。

SQL 和索引仍然是第一现场

无论数据库怎么演进,大部分线上性能事故最后都能追到 SQL 和索引上。这件事十几年没变过。

常见问题非常朴素:

  • 模糊查询和范围查询没有合适索引
  • 复合索引顺序不匹配过滤条件
  • 用函数处理索引列,导致索引失效
  • 大分页使用 offset 导致扫描成本飙升
  • 一次查询返回过多列和过多行

再往深一点说,你还要关注这些细节:

  • 查询条件的选择性够不够高
  • 排序字段和过滤字段能不能共用索引
  • 回表次数是不是过多
  • 扫描行数和返回行数的比值是不是离谱
  • 执行计划有没有随着数据量变化而漂移

这些问题在低流量时往往藏得很好,一到活动、批处理、月结或业务增长,就会被放大成事故。

连接数问题经常被低估

数据库不是 Web 服务,连接数不是越多越好。这个误区非常常见。

很多服务一部署就把连接池拉满,理由通常是“避免请求排队”。但数据库连接本身就是重资源,线程、内存、上下文切换都要成本。连接一多,数据库可能还没开始真正干活,就已经把资源浪费在连接管理上了。

云环境里这个问题更容易被放大。因为应用扩容通常很容易,一旦 HPA 或自动扩容触发,应用实例数翻倍,数据库看到的不是 QPS 先翻倍,而是连接数先翻倍。

所以你至少要建立下面几个基线:

  • 单实例允许的合理连接范围
  • 每个服务实例的连接池上限
  • 连接泄漏和空闲连接积压的报警阈值

热点比总量更危险

很多数据库整体 QPS 不高,平均资源也不高,但就是会抖。这种情况十有八九不是总量问题,而是热点问题。

热点之所以难搞,是因为总体资源看起来很健康,但局部竞争已经非常严重。常见场景包括:

  • 秒杀库存集中写某几行
  • 用户详情集中读某几个明星账号
  • 时间分区设计不合理,所有写入压在最新分区
  • 自增主键或单调递增索引导致写入页争用

热点问题通常不会靠数据库单边解决,往往要应用侧配合。比如:

  • 打散键设计,避免单一分区过热
  • 引入缓存和本地缓存,分散读压力
  • 用消息队列削峰,把同步写变成异步写
  • 对统计场景做预聚合,减少重复扫表
  • 对库存、配额这种高竞争数据引入更明确的并发控制策略

监控不要只盯 CPU

数据库监控如果只有 CPU、内存和磁盘占用,基本不够做性能治理。你真正应该长期盯的是这些指标:

  • 慢查询数量和分位延迟
  • 活跃连接数和等待事件
  • 锁等待和死锁趋势
  • 磁盘吞吐与 IOPS 峰值
  • Buffer 命中率和缓存抖动
  • 复制延迟和只读节点滞后

而且只看指标本身还不够,你得让指标和请求、SQL、应用版本、配置变更、活动时间点关联起来。只有这样,性能问题才能形成完整闭环。

先治理,再扩容

扩容不是错,但顺序不能错。更稳妥的做法通常是:

  1. 找出最差的那 1% SQL。
  2. 修正最明显的索引和查询路径问题。
  3. 控制连接池和批处理并发。
  4. 识别热点并做业务层分流。
  5. 最后再判断是否需要升级规格或增加只读节点。

这个顺序的价值在于,你拿到的不只是短期性能改善,还会得到更清楚的系统边界和更可预测的成本曲线。

小结

云数据库性能治理的关键,不是一直把机器买大,而是把访问路径管顺、把连接池管住、把热点识别出来、把坏 SQL 揪出来。

只看 CPU,最后很容易把结构性问题误诊成资源问题。真正成熟的性能治理,应该能回答这几个问题:慢在哪里,为什么慢,下一次怎么提前发现,是否真的需要花钱扩容。

下一篇我们就接着聊和性能高度相关的另一个问题:成本。