事情是这样的。
三年前我还是个满腔热血的年轻工程师,觉得Docker就是拯救世界的存在。什么都能容器化,什么都往docker-compose里塞,数据库?当然是跑容器里啊!多优雅!多现代化!
直到有一天,我的生产数据库在凌晨三点挂了。
事情是怎么发生的
那天晚上我的数据库容器突然OOM被kill了,MySQL在重启的时候卡在 InnoDB: recovery阶段,整整五分钟没有任何响应。运维的兄弟半夜爬起来看日志,发现是Docker的overlay2存储驱动在高并发写入时出现了文件锁竞争。
第二天早上开复盘会,leader看了我一眼,那眼神怎么说呢,就像看一个把炸弹当玩具的小孩。
他说了一句让我记到现在的话:「数据库跑在容器里,就像把金条放在纸盒子里——不是说不行,是你这个人不适合看孩子。」
容器化数据库到底有什么问题
先说性能。容器本质上是宿主机上的一个进程,数据库的IO路径每多一层抽象,就多一分损耗。有人会说「现代SSD很快,这点overhead不算什么」,但问题是数据库的写入不是一次性的,是每秒几千上万次的随机IO。
我用sysbench做过实测:同样的硬件,裸机MySQL的QPS比容器版本高大概15-20%。在中等规模业务里,这个差距意味着你需要多买20%的机器。
再说数据安全。容器里的数据最终还是要落到宿主机的文件系统上,但很多人配置volumes的时候会出现各种骚操作:
# 错误示范1:匿名volume,数据可能丢失
volumes:
- /var/lib/mysql
# 错误示范2:权限配置不当,MySQL启动不了
volumes:
- ./mysql-data:/var/lib/mysql
# 错误示范3:生产环境用bind mount还觉得自己很安全
volumes:
- /home/ubuntu/mysql-prod:/var/lib/mysql
我见过有人bind mount了一个nfs目录到MySQL的data dir,然后问为什么数据库慢——兄弟,NFS的延迟是本地SSD的10倍以上啊。
网络和存储才是真正的坑
Docker的网络模型是bridge/NAT,数据库客户端连接过来要经过一层NAT转发。大部分时候这没问题,但MySQL的连接协议是TCP长连接,高并发场景下NAT的连接跟踪表会成为瓶颈。
更坑的是存储。容器删了,volume不一定删干净;宿主机磁盘满了,容器不知道;不同容器共享同一个volume,权限问题能让你debug到天亮。
有个朋友的公司用K8s跑PostgreSQL,有一次误操作把PV删了,三个月的数据差点没了。最后从备份恢复,停机了整整两天。这事后来成了他们公司SRE领域最大的反面教材。
什么时候可以用容器跑数据库
等等,我不是说Docker跑数据库就是犯罪。场景对了,容器化数据库还是很香的。
适合容器化的场景:
- 本地开发环境——快速启动、随时重建,数据丢了不心疼
- CI/CD测试——每次跑完测试就销毁,环境干净
- 单节点测试服务——不需要高可用,就是个临时数据库
- 数据量小的边缘节点——10GB以下,高可用要求不高
不适合容器化的场景:
- 生产环境的中大型数据库——老老实实用独立实例
- 对IO延迟敏感的业务——金融、游戏、实时分析
- 需要高可用的数据库集群——用专业的数据库服务或运营商
那数据库应该怎么部署
如果你在云上,直接用托管数据库服务(RDS、Cloud SQL、Azure Database)。别觉得自己能比云厂商的DBA更懂数据库调优,大概率你不能。
如果你要自建:
# 用系统包管理安装,或者干脆二进制部署
wget https://dev.mysql.com/get/mysql-8.0-linux-glibc2.12-x86_64.tar.xz
tar xvf mysql-8.0.33-linux-glibc2.12-x86_64.tar.xz
# 用systemd管理,有完整的生命周期控制
systemctl enable mysql
systemctl restart mysql
# 监控用专业的mysql_exporter,不要自己写脚本
systemctl enable mysqld_exporter
数据目录放RAID10的SSD,备份用xtrabackup,主从复制用GTID模式。这些东西,容器都能实现,但你得花十倍的精力去配置和维护。
我的观点
容器化是伟大的技术,但它不是银弹。数据库作为有状态服务,和无状态的Web服务有本质区别。
很多人(包括三年前的我)喜欢说「Docker统一了开发生产环境」「容器化后运维更简单」——这话没错,但只对无状态服务成立。你把MySQL扔进容器,表面上运维简单了,实际上是把复杂度转移到了你看不见的地方,等出问题的时候就傻眼了。
技术选型这事,最忌讳的就是「大家都这么做」和「这很现代化」。问问自己:我的业务能承受数据库停机吗?数据丢了能恢复吗?如果答案是否定的,就别在数据库上省这点事。
当然,如果你说「我就跑着玩」「数据丢了无所谓」,那随便你怎么搞。反正出事了别来找我。
PS:如果你正在用Docker跑生产数据库,并且还没出过问题,那只能说明你的业务还不够大。继续保持,早晚会有惊喜的。