MySQL、PostgreSQL、Redis 多实例的内存参数(innodb_buffer_pool_size、shared_buffers、maxmemory)均按进程独立生效,依赖OS级隔离与cgroups围栏防越界。
MySQL 多实例用 mysqld 启动时,innodb_buffer_pool_size 是按实例独立分配的
每个 mysqld 进程启动时加载自己的配置文件(如 my.cnf),innodb_buffer_pool_size 只作用于当前实例的 innodb 缓冲池,不会跨进程共享或泄漏。只要端口、socket、数据目录、配置文件完全隔离,内存空间天然隔离。
常见错误现象:SHOW ENGINE INNODB STATUS 里看到缓冲池大小和配置不一致;多个实例共用同一份 my.cnf 导致参数被覆盖;启动脚本硬编码了全局配置路径。
- 每个实例必须指定独立的
--defaults-file=/path/to/my_instance1.cnf,不能依赖默认搜索路径 -
datadir、socket、port、pid-file四者必须全部不同,缺一不可 - 避免在配置中使用
!include或环境变量拼接,容易意外复用同一份 buffer pool 配置
PostgreSQL 多实例需用 pg_ctl 分别初始化 + 启动,shared_buffers 不会越界
PostgreSQL 没有“多实例”原生概念,靠多个独立的 PGDATA 目录 + 不同端口实现。每个 postgres 进程只读取自己 postgresql.conf 中的 shared_buffers,操作系统级进程隔离保证内存不互通。
使用场景:容器化部署、开发机本地跑测试库、生产中按业务线拆分集群。
- 初始化必须用
pg_ctl -D /data/pg_instance_a initdb,不能 cp 整个PGDATA目录后改配置——wal 目录和 pg_control 会冲突 - 启动命令必须显式指定
-D /data/pg_instance_a -c port=5433,不能只改 conf 文件后 reload -
shared_buffers值超过系统shmmax会导致启动失败,错误信息是could not create shared memory segment,需同步调大内核参数
Redis 多实例靠 redis-server 加载不同配置文件,maxmemory 是硬隔离边界
Redis 实例间完全无共享内存,maxmemory 是 per-process 的 RSS 上限,由 malloc 分配,不受其他 Redis 进程影响。越权读取只可能发生在客户端连错端口,而非内存泄漏。
性能影响:若多个实例部署在同一台机器且总内存超物理限制,Linux OOM Killer 可能杀掉任意一个 redis-server 进程,错误日志里会出现 Killed process [pid] (redis-server)。
- 必须为每个实例写独立的
redis.conf,禁用include引入公共配置(防止maxmemory被覆盖) - 启动命令必须带绝对路径:
redis-server /etc/redis/instance_a.conf,不能 cd 进目录后执行redis-server - 用
redis-cli -p 6380 CONFIG GET maxmemory实时验证,避免配置热加载未生效
所有数据库都绕不开 Linux cgroups v2 —— 真正防越权得靠进程级资源围栏
配置文件里的内存参数只是应用层建议值,真正阻止越界的是 OS 层的 cgroups。比如 MySQL 实例即使配了 innodb_buffer_pool_size = 4G,若没用 cgroups 限制,它仍可能因临时排序、连接缓冲等吃满 16G 内存,挤占其他实例。
容易被忽略的地方:Docker 默认用 cgroups v2,但 systemd service 启动的 mysqld 默认不在任何 slice 下,等于裸跑。
- 用
systemctl --scope -p MemoryMax=4G /usr/bin/mysqld --defaults-file=/etc/mysql/inst_a.cnf启动可即时生效 - 检查是否生效:
cat /proc/<pid>/cgroup | grep memory</pid>,看到memory.max才算落进围栏 - Redis 和 PostgreSQL 同理,但注意
fork()子进程(如 PG 的 backend、Redis 的 RDB fork)也会继承 memory.max 限制










