MySQL运维设计五大经典陷阱避坑指南
|
去年九月,凌晨三点十七分,我盯着主从延迟那条红杠在 Grafana 里一抖一抖,像心电图快停跳前的最后几次颤动。老何坐我斜后方,正用指关节敲键盘敲出一串“select count() from event_log where dt=’20230904’ and status=1”,他没看屏幕,盯着自己左手无名指上那圈浅浅的戒指印——人结婚十年,戒痕还在,数据库没主键,连印子都留不住。 我说MySQL运维设计五大经典陷阱避坑指南?别信标题党,它站得住的地方就一个:优胜劣汰。不是你写了规范别人就照做,是你线上崩三次、报表错两天、AB组数据对不上三回,活下来的方案才叫“经典”。上个月复盘那个裂变活动漏埋事件,运维小李一边调 binlog 格式一边啃冷掉的韭菜盒子,饼皮碎渣掉进键盘缝隙,我数了十八秒才听见他咳出来第一声。 第一个坑?主键当装饰品。我们有个订单日志表,设计稿写着“id bigint auto_increment primary key”,上线三个月没人动过主键约束。结果去年九月,增长团队要补算裂变路径,发现十万条记录 id 全是 0。不是 NULL,是零。我翻 schema 时发现建表语句里写了 ENGINE=InnoDB,但没写 ROW_FORMAT=COMPACT,也没显式设 AUTO_INCREMENT=1——这事儿查到一半,机房空调突然轰一声停了,三十七度的热风裹着铁锈味灌进来。我原以为是字段默认值设错了,结果是 init_file 里那段 SQL 被同事手动改过,删了 AUTO_INCREMENT,加了 comment ‘兼容旧系统’。兼容个屁。那同事上周转岗去BI支持组了,现在天天帮业务核对漏斗分母是不是空的。
文章配图,仅供参考 第二个坑?时间字段不统一时区。我们有个 user_behavior 表,created_at 用的是 timestamp,update_time 用的是 datetime,update_by 用的是 varchar 存毫秒时间戳。不是故意恶心人,是三个不同组在不同时期写的。最绝的是某次跨周导数,ETL 脚本跑在 CEST(夏令时),而 MySQL server_time_zone 是 SYSTEM,系统又配了 systemd-timesyncd 自动校时……那天下午四点十二分,老何在会议室投影仪前切到一张趋势图,突然指着Y轴问:“这个‘昨日’为什么比‘今日’高四十七倍?”没人答得上来。后来查出来,其中一列数据是用 UNIX_TIMESTAMP(NOW()) 算的,另一列是用 FROM_UNIXTIME() 回填的,中间穿插了一次NTP强制同步,差了两分十七秒——两分十七秒足够让五万用户行为落在错误的分区里。 第三个坑?大字段默认不压缩还上索引。text 字段加 fulltext?行。json 字段加 generated column 再加函数索引?也行。可有人把 remark varchar(2000) 加了普通 B+tree 索引,还是联合索引的第一位。我第一次看见执行计划里 Extra 列写着 “Using where; Using index condition; Using filesort”,心里咯噔一下。不是慢,是每次 insert 都卡顿半秒。上周排查,发现这个索引占了单表空间的六成三——六成三啊,还是个被业务代码根本没读过的字段。当时我坐在工位上,听见隔壁工位小王接了个电话,声音不大:“……嗯,对,就是那个备注字段,他们说要搜关键字,我没细问……哎您稍等,我看看监控……”他低头看屏幕,耳机线缠在手指上绕了三圈。 第四个坑?备份不验。全量备份每周日凌晨两点跑,xtrabackup —prepare 每次只验证到“completed OK”。去年九月十六号凌晨,备库拉起来发现 ibdata1 校验和对不上——不是损坏,是备份过程中 OS 层做了 LVM 快照,而 xtrabackup —backup 时用了 —no-lock,快照瞬间冻结了 redo buffer,但没冻住 undo log 写入。修复花了十九小时。期间增长组每天催数据口径,我们拿临时 SQL 硬凑,直到第四天老何发来一条钉钉:“上次A/B实验效果归零,可能因为分流ID取模用了 crc32(‘user_id’),但某些ID含中文,crc32返回负数,取模后直接进了B组。”他发完就撤回了,后面补了句:“…刚发现,我们那个分流表也是用的 remark 字段索引。” 第五个坑?权限按“能跑就行”给。DBA 给 BI 工具开的账号,host 是 %,密码三年没换,SELECT 权限给了整个 billing 库。去年双十一前夜压测,BI 前端误操作触发了 “SELECT FROM order_detail ORDER BY created_at DESC LIMIT 100000”,扫了三十分钟全表。我蹲在备份服务器上 grep error log 的时候,听见楼下便利店关卷帘门的金属哗啦声。当时就想,这哪是坑?这是自己刨的坟包,还主动帮别人把棺材板撬松了。 所以现在我们改了流程:每个新表上线前,必须提交三份东西——DDL、预期 QPS 分布图、以及至少一次模拟宕机后的恢复耗时实测。上上周小李提了个 new_user_profile 表申请,我让他先用本地 Docker 启两个 MySQL 实例,一个配主从,一个只启 standalone,把同一批插入语句跑三遍。他跑完发我截图,最后一行是 “restore finished at 2023-09-18T15:22:07.832Z”。我回他:“行,明天十点前把 binlog_gtid_simple_recovery 改成 ON。” 他秒回:“收到。” 又补一句:“我刚买了杯冰美式,糖浆没搅匀。” 说到底,所谓“经典陷阱”,就是那些你踩完之后不好意思写进文档、但每次交接都悄悄耳语的脏话。真要避坑?不如把“show create table” 当晨会打卡项目。我现在手机备忘录里记着二十三张表的名字,每张都标了“⚠️下次迁移必砍remark索引”。但其实我早忘了第三张是什么——上周五下午五点,运营说要临时查个漏斗,我顺手 drop 了那个索引,还没来得及告诉谁。电脑右下角时间跳成 17:04,窗外开始下雨,雨点打在机房通风口百叶窗上,啪嗒、啪嗒、啪嗒。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


MySQL运维设计实战:36小时崩溃到稳如磐石
大数据架构师避而不谈的3个致命代码陷阱
MySQL事务控制无障碍设计实战指南