执行摘要
MariaDB 停止运行不是因为损坏、Galera 问题或 SQL 缺陷。Linux 内核因为超出内存限制而杀死了 mariadbd 进程。
证据在 systemd 和内核日志中非常明确:
mariadb.service: Failed with result 'oom-kill'
Out of memory: Killed process 1177 (mariadbd) total-vm:22267612kB, anon-rss:16649820kB
Memory cgroup out of memory: Killed process 1146610 (mariadbd)
环境
| 组件 | 值 |
|---|---|
| 总内存 | 19.5 GB |
| 交换空间 | ~1 GB |
| systemd MemoryMax | 16 GB |
| innodb_buffer_pool_size | 2 GB(自动缩减 → 1 GB) |
| rocksdb_block_cache_size | 4 GB |
| tmp_table_size(Releem 覆盖) | 768 MB |
| max_heap_table_size(Releem 覆盖) | 768 MB |
| sort_buffer_size | 32 MB |
| max_connections | 100 |
被杀之前发生了什么
MariaDB 检测到内存压力并尝试通过缩减 InnoDB 缓冲池来自我保护:
Memory pressure event shrunk innodb_buffer_pool_size=1536m from 2048m
→ 1280m → 1152m → 1088m → 1056m → 1040m → 1032m → 1024m
Memory pressure event disregarded; innodb_buffer_pool_size=1024m,
innodb_buffer_pool_size_auto_min=1024m
InnoDB 已经将缓冲池缩减到最小值(1 GB)。但这不够。其他内存消费者不会退让。
最坏情况计算
在 100 个同时连接下,每个会话的最坏情况内存消耗:
100 × (768 MB tmp_table + 768 MB heap + 32 MB sort) = ~153 GB
显然,不是所有会话都会创建 768 MB 的临时表。但仅仅 20 个会话 运行带有 GROUP BY 或 ORDER BY 的大数据集查询就足以突破 16 GB 上限:
InnoDB 缓冲池: 1 GB (已缩减)
RocksDB 缓存: 4 GB (固定,不会缩减)
20 个会话 × 768 MB: 15 GB
总计: 20 GB → 被杀
加重因素:ProxySQL 连接风暴
在 OOM 之前,MariaDB 日志显示来自 10.68.68.103(ProxySQL)的大量中断连接:
Aborted connection ... user: 'unauthenticated' host: '10.68.68.103'
Too many connections
更多连接 = 更多会话内存 = 更大压力。
修复方案
立即行动
- 减少会话内存:
tmp_table_size = 128M
max_heap_table_size = 128M
sort_buffer_size = 8M
- 提高 systemd 上限:
MemoryMax=18G
- 审计 RocksDB 缓存 —— 4 GB 可能过大:
rocksdb_block_cache_size = 2G
中期行动
- 移除 Releem 覆盖文件(
/etc/mysql/releem.conf.d/z_aiops_mysql.cnf) - 通过 PmaControl 监控
memory_mysqld以在被杀之前发出告警 - 配置 ProxySQL 的后端
max_connections低于 MariaDB 的max_connections
这不是什么
这不是:
- 启动失败
- Galera 恢复损坏
- 数据目录损坏
- 文件描述符问题
MariaDB 干净地重启并立即恢复为 active (running) 状态。
结论
一个自动调优工具(Releem)将 tmp_table_size 推到了 768 MB ——这个值单独看似乎合理。但与 16 GB 的 systemd 上限、4 GB 的 RocksDB 缓存以及 ProxySQL 连接风暴结合在一起,它就变成了一颗定时炸弹。
MariaDB 服务器的内存必须按最坏情况计算,而不是平均情况。
评论 (0)
暂无评论。
发表评论