数据库常见问题:我线上踩过的几个坑

数据库常见问题:我线上踩过的几个坑-z35资讯网

热点 阅读

这些年做后端,半夜被电话叫醒的次数不少,十次里有七次跟数据库有关。应用层的 bug 一般不会烧到整个系统,数据库一出问题,基本就是全站挂。我把遇到频率最高的几个问题整理一下,都是真事儿,不是从文档里抄的。

连接数打满,报警总比故障来得晚

最常见的一个。MySQL 默认 max_connections 是 151,很多团队上线前压根没改过。业务量一涨,应用连接池配得又大,两边一叠加就顶到天花板,报错 Too many connections,新请求全进不来。我见过一次是连接池最大连接数配了 200,三个服务实例一跑就是 600,数据库直接懵了。解决办法不复杂:先 show processlist 看看谁在占连接,多半是某个慢 SQL 卡着不释放,或者连接池的回收策略没配对。连接数不是越大越好,每个连接都吃内存,撑到几千反而更慢。

数据库常见问题:我线上踩过的几个坑

另一个坑是慢查询。有张订单表涨到 800 多万行,列表页查询从 200 毫秒慢慢爬到了 4 秒多。开发一开始以为是数据库不行了,嚷嚷着要分库分表。我拉了一下慢日志,发现是一条 where 条件里对时间字段做了函数运算的 SQL,索引直接失效,走全表扫描。把条件改成范围比较,再加一个 (user_id, created_at) 的联合索引,耗时掉到 30 毫秒左右。分库分表这种事,很多时候是被误判出来的。

数据库常见问题:我线上踩过的几个坑

隐式类型转换也算高频。字段是 varchar,代码里传了个数字进去,MySQL 会把列转成数字比较,索引白建。这种问题在测试环境数据量小的时候完全看不出来,一上生产就露馅。还有 N+1 查询,ORM 用着顺手,一个列表页偷偷发了 300 条 SQL,单看每条都很快,加起来就把连接池占满了。

数据库常见问题:我线上踩过的几个坑

主从延迟和备份,出事了才知道疼

主从延迟我吃过一次大亏。写库压力大,从库延迟冲到 30 多秒,用户下单后立刻跳详情页,读的是从库,数据还没同步过去,页面显示订单不存在。客诉电话直接打爆。后来把这类写完立刻读的场景强制走主库,延迟才没再惹事。监控上就看 seconds_behind_master,超过阈值就告警,别等用户反馈。

备份这事更简单,也更容易偷懒。我见过有团队每天备份,真出事的时候发现备份文件是 0 字节,脚本早就静默失败了。备份不演练等于没备份,我现在要求每个月至少做一次真实的恢复测试,把库恢复到另一台机器上,跑一遍核心查询。

  • 连接池最大连接数乘上实例数,一定留 30% 余量给运维和监控
  • 慢查询阈值设成 200 毫秒,别用默认的 10 秒,那时候已经晚了
  • where 条件里不要对索引列做函数运算或隐式类型转换
  • 备份脚本要有校验,恢复演练每月一次
  • 主从延迟超过 5 秒就告警,写后立刻读的请求走主库

说白了,数据库这些问题大多不新鲜,难的是提前发现。我的习惯是上线前把慢日志、连接数、主从延迟这三个指标都配上告警,出事的时候至少知道往哪看。剩下的就是别嫌麻烦,该加的索引加,该演练的备份演练。

继续阅读