MySQL运维与设计五大致命陷阱(20年血泪总结)
|
去年8月,凌晨三点十七分,群里@全员那条消息弹出来的时候,我正用手机连着跳板机查binlog——不是查SQL,是查哪台slave的relay-log被truncate过三次。群里没人回,只有一串IP在日志里反复刷:10.23.41.198,眼熟,上个月在WAF规则里封过,但没加IPset自动同步,后来就漏了。这事儿跟MySQL五大陷阱没半毛钱关系,但我现在看见这个IP就想点开看两眼。 先扔结论:五个坑里,四个是人填的,一个是MySQL自己埋的,但最要命的永远是那个“我们一直这么干”的。比如主从延时报警阈值设成六十秒——你猜怎么着?上周五下午监控挂了四小时,运维说“没告警就是没问题”,直到业务侧发现订单丢了三十七单才翻出慢查询日志里那条select from user_log where create_time > '2023-08-12' order by id desc limit 1。查完才发现是从库没建create_time索引,主库有,但从库建表语句里少粘了一行,就少粘了那一行。我原以为是DBA漏执行,结果扒Git记录发现是开发提的DDL合并请求里自己删的——理由写的是“索引重复,冗余”。 第二个坑,连接池超时时间比wait_timeout短三秒。这事儿我敢打包票。不信你去翻任何一家用HikariCP配MySQL的K8s ConfigMap,八成写着maxLifetime: 1800000(三十分钟),而MySQL默认wait_timeout是28800(八小时)。等等,你先别急着翻配置——你先去看看你们那台跑定时任务的jump server上多出来的那个.gitignore文件,就在/home/jenkins/.cache/下面,大小一百二十六字节,md5我记不住,但开头肯定是# MySQL tmp dir。这事跟我当年在第三家厂子里写的那个备份脚本有关,脚本里rm -rf /tmp/mysql_ 没加判断,某次主库OOM后临时目录没清干净,脚本就把backup_lock文件当tmp删了。后面三年没人动那脚本,但每年七月都出一次间隙锁争用飙升。我不说是谁写的,反正不是我。 第三个坑……算了,不列了。列了你们也改不掉。比如把sys.schema_unused_indexes当真,真敢一键drop。我见人干过,干完五分钟内主键冲突暴涨四百倍。他还不信,非要说“官方工具肯定靠谱”,我说你看看那张表的comment字段写的是啥——“DO NOT USE IN PRODUCTION”,他当时回了个[OK],结果半小时后在群里问“为什么now()函数返回null”。这种事说多了累,就像昨天看见某个厂还在my.cnf里写skip-name-resolve,但DNS服务其实早换成了CoreDNS+自定义上游,结果有个边缘节点解析失败,所有连接卡在host_cache上,排队等十二秒,日志里全是“Host '172.16.22.33' is not allowed to connect”,其实根本不是权限问题,是DNS query timeout没调。我跟他们DBA吵过,他甩过来一张Percona的PDF截图,第三页倒数第二段,我没细看,就回了句“你把timeout改成三百七十二再试试”。他真改了,结果更糟,因为372毫秒正好卡在glibc resolver重试窗口里。 第四个坑,字符集。utf8mb4_collate_ci 这个排序规则,你查文档看到的是“大小写不敏感”,可你要是拿它建user表,再塞进一批带emoji的昵称和一堆‘admin’、‘Admin’、‘ADMIN’进去,某天业务要按用户名去重,你猜SELECT DISTINCT username FROM users GROUP BY LOWER(username)能跑出几个‘admin’?三个。这个我说不准。但我知道去年有个金融客户做审计溯源,查到一笔异常转账,追踪user_id时发现关联的login_log表里同一个uid对应四条不同host_ip记录,最后拆开看,两条是utf8mb4_bin存的,两条是latin1_swedish_ci存的,跨库JOIN时MySQL隐式转换,用的是连接字符集,不是字段字符集——中间那个proxy的character_set_client被一个Python脚本启动参数悄悄改过,那个脚本作者已经离职十八个月,代码库里搜不到调用痕迹,只在crontab里留了一句# keepalive_db。对,就这一句。 第五个坑,不是坑,是幻觉。叫“安全是成本不是收入”。这句话我十年前就说,现在还说,但每次说完都有人点头,转头就去搞SQL注入防护策略、WAF绕过测试、防拖库扫描,然后在测试环境开着general_log,生产环境开着performance_schema,最后发现slow_query_log里一条真实攻击记录都没有,反倒是凌晨四点有个IP用mysql -h xx -u root -p -e "show databases" 连了六十三次。我们花了三个月给这套链路加审计插件、打trace、补token,上线那天运维顺手把/tmp下的mysql.sock.lock文件挪到/data/tmp重命名了一下,忘了ln -sf,结果所有本地连接全部fallback到TCP,走了iptables里一条没开的DNAT规则。那天我没修,就看着监控曲线平得像刀切的,也没说话。后来我问他们,“如果明天root密码被爆破了,是WAF先拦还是audit_log先写?”没人答,群里静了十七秒。 再说个闲事:上个月去趟深圳,机场落地看见一个戴蓝帽子的,穿工装裤,蹲在行李转盘边调试一台扫码终端,旁边摆着三根网线,其中一根缠着另一根打了死结,标签纸上印着“MySQL-RW”,但接口是DB9。我就盯着看了四十秒,他抬头看了我一眼,没说话,把线解开了。这事儿跟陷阱没关系,纯属我最近有点神经过敏。
文章配图,仅供参考 站长个人见解,我现在只干三件事:每周三删一次备份目录下超过七天的.sql.gz;检查所有从库的Seconds_Behind_Master是不是稳定在零;以及,拒绝在任何新项目评审会上看到“支持横向扩展”这五个字。至于别的——你先把10.23.41.198那个IP从所有白名单里摘了,然后再看。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


鸿蒙开发者必学:MySQL运维设计实战