努力
加油

如何在同一台服务器上管理多个不同类型的数据库实例?

在同一台物理机或虚拟机上部署和管理多个不同类型的数据库实例,是中小企业、开发测试环境甚至部分生产架构中非常常见的场景。虽然“资源隔离”和“高可用”通常建议物理分离,但在预算有限或资源利用率优先的场景下,混合部署是完全可行的。

核心挑战在于:端口冲突、资源争抢(CPU/内存/IO)、安全隔离以及运维复杂度。

下面我从实操层面、资源隔离策略和最佳实践三个维度,拆解如何优雅地搞定这件事。

一、 基础前提:端口与路径规划

这是最容易踩坑的地方。不同数据库默认端口可能相同(如 MySQL 和 PostgreSQL 都习惯用 5432 或 3306 的变体,或者 Redis 默认 6379),同类型多实例必须区分端口。

  1. 端口分配表:

    • MySQL: 3306 (主), 3307 (从/其他)
    • PostgreSQL: 5432 (主), 5433 (其他)
    • Redis: 6379 (主), 6380 (缓存集群节点)
    • MongoDB: 27017, 27018
    • Elasticsearch: 9200, 9300
    • 原则:所有服务端口必须在防火墙(iptables/firewalld)和安全组中明确开放,且互不重叠。
  2. 数据目录隔离:

    • 绝对不要把所有数据放在 /var/lib/mysql 这种默认路径混在一起。
    • 推荐结构:
      /data/db/
      ├── mysql_3306/
      │   ├── data/
      │   └── logs/
      ├── postgresql_5432/
      │   ├── data/
      │   └── logs/
      ├── redis_6379/
      │   └── dump.rdb
      └── mongo_27017/
          └── data/
    • 每个实例拥有独立的 PID 文件、Socket 文件和日志文件。

二、 操作系统层面的资源隔离(关键步骤)

如果所有数据库都跑在同一个 Linux 用户下,一个数据库吃光内存,其他数据库就会 OOM(Out of Memory)。必须利用 Linux 内核特性进行限制。

1. 使用 systemd 管理进程(现代 Linux 发行版标配)

不要手动写 shell 脚本启动数据库,要用 systemd。它不仅能开机自启,还能做资源控制。

以 MySQL 为例,创建一个 service 文件 /etc/systemd/system/mysql-custom.service:

[Unit]
Description=MySQL Custom Instance on Port 3307
After=network.target

[Service]
Type=simple
User=mysql
Group=mysql
# 指定配置文件和数据目录
ExecStart=/usr/sbin/mysqld --defaults-file=/data/db/mysql_3306/my.cnf
Restart=on-failure
LimitNOFILE=65535

# 【核心】资源限制
MemoryMax=2G          # 限制最大内存为 2GB
MemoryHigh=1.5G       # 超过 1.5GB 时开始压缩回收
CPUQuota=50%          # 限制 CPU 使用率不超过 50%
IOWeight=100          # 限制 IO 权重(需启用 iocontroller)

对 PostgreSQL、Redis 等也做类似配置。注意:Redis 本身支持单线程,但如果配置了 AOF/RDB 持久化或 Cluster 模式,也需要关注其内存峰值。

2. cgroups v2 进阶(可选但推荐)

如果你使用的是较新的 CentOS 8 / Ubuntu 20.04+ / Debian 11+,系统默认使用 cgroups v2。你可以更精细地划分 IO 带宽。

例如,防止 MySQL 的大查询把磁盘 IO 打满,导致 Redis 响应变慢:

# 创建 cgroup 层级
mkdir /sys/fs/cgroup/io/mysql_high_priority
echo "1000" > /sys/fs/cgroup/io/mysql_high_priority/io.weight
echo "100" > /sys/fs/cgroup/io/redis_low_priority/io.weight

注:具体命令因发行版而异,建议使用 cgcreate 工具或 systemd 自动处理。

三、 各类型数据库的特殊注意事项

1. MySQL/MariaDB

  • 多实例方案:推荐使用 MySQL Enterprise Monitor 的多实例模板,或者使用 mysqld_multi 工具。
  • 配置要点:每个实例必须有独立的 my.cnf,重点调整 innodb_buffer_pool_size。假设总内存 16G,两个 MySQL 实例各分 6G,留 4G 给 OS 和其他数据库。
  • 权限隔离:不同实例之间没有直接关系,但建议为每个实例创建独立的管理员账号,避免密码泄露导致横向渗透。

2. PostgreSQL

  • 优势:PostgreSQL 天生擅长多实例共存,因为它的每个实例是一个独立的 Postmaster 进程。
  • 操作:只需初始化不同的 PGDATA 目录,并在 postgresql.conf 中修改 port、unix_socket_directories 和 shared_buffers。
  • 提示:shared_buffers 不要设得太大,否则多个 PG 实例加起来会撑爆内存。

3. Redis

  • 风险最高:Redis 是单线程模型,且全内存操作。一个实例的 KEYS * 或大 Key 删除可能导致整个服务器卡顿。
  • 隔离建议:
    • 如果使用 Redis Sentinel 或 Cluster,尽量将不同角色的节点分散到不同 IP(即使在同一台机器,也要通过不同网卡接口或隧道隔离,如果做不到,至少用不同的 TCP 端口)。
    • 强烈建议:在同一台服务器上运行多个 Redis 实例时,务必设置 maxmemory-policy 为 allkeys-lru 或 volatile-lru,并严格限制 maxmemory。
    • 考虑使用 Redis Modules 或 Namespace 逻辑隔离,但物理进程隔离更安全。

4. MongoDB

  • 副本集 vs 分片:MongoDB 可以运行多个 mongod 实例组成副本集。它们共享文件系统锁吗?不,MongoDB 3.6+ 默认使用 WiredTiger 引擎,支持多文档事务,但对同一集合有锁竞争。
  • 建议:如果是生产环境,尽量避免在同一台小规格机器上跑 MongoDB 副本集的所有成员。如果是开发环境,确保每个实例使用不同的 --dbpath 和 --port,并监控 WiredTiger cache 大小。

5. Elasticsearch / Kibana

  • JVM 堆内存陷阱:ES 极度依赖 JVM 堆内存。默认堆内存是 1G,但在多实例环境下,你必须手动计算:Heap Size = 总内存 * 50% / 实例数。
  • 警告:如果堆内存设置过大,会导致频繁的 Full GC,进而引发集群脑裂或写入超时。同时,ES 需要大量文件句柄,记得调整 fs.file-max 和 vm.max_map_count。

四、 运维与监控:别等到崩了才知道

当多个数据库挤在一台服务器上,监控粒度必须细化。

  1. Prometheus + Node Exporter + 各数据库 Exporter

    • 安装 node_exporter 监控整机 CPU、内存、IO。
    • 安装 mysqld_exporter、postgres_exporter、redis_exporter 等。
    • 关键点:在 Prometheus 的 scrape 配置中,通过 job_name 和 instance 标签区分不同实例。例如:
      - job_name: 'mysql'
        static_configs:
          - targets: ['localhost:9104'] # MySQL 3306
            labels: { instance: 'mysql_primary' }
          - targets: ['localhost:9105'] # MySQL 3307
            labels: { instance: 'mysql_secondary' }
  2. 日志集中收集

    • 不要 SSH 上去看日志。使用 Filebeat 或 Fluentd 将所有数据库日志发送到 Elasticsearch 或 Loki。
    • 配置 Logrotate,防止日志文件撑爆磁盘。每个数据库实例单独配置 logrotate 策略。
  3. 备份策略

    • 串行执行:备份任务绝对不能并行!两台数据库同时做全量备份,IO 会直接堵死。
    • 错峰调度:
      • MySQL 备份:凌晨 2:00
      • PostgreSQL 备份:凌晨 3:00
      • Redis RDB:每 6 小时一次,但设置 save 间隔较长,或在低峰期触发。
    • 工具选择:
      • MySQL: Percona XtraBackup
      • PostgreSQL: pgBackRest 或 WAL-G
      • Redis: 官方 BGSAVE 配合脚本自动化拷贝 RDB 文件。

五、 总结与避坑指南

  1. 不要迷信“够用”:评估业务峰值。如果 MySQL 峰值占 80% 内存,再放一个 Redis 进去,必挂。预留 30%-40% 的资源给 OS 和其他数据库。
  2. 网络隔离:如果可能,使用 Docker 或 LXC 容器来封装每个数据库实例。Docker 天然提供了 cgroups 和 namespace 隔离,比裸奔在宿主机上安全得多。
    • 示例:docker run -p 3306:3306 -m 2g --cpus 1.5 mysql:8
  3. 安全第一:
    • 关闭不必要的远程访问(绑定 127.0.0.1 除非必要)。
    • 防火墙只开放业务所需端口。
    • 定期更新补丁,特别是 OpenSSL 和数据库内核漏洞。
  4. 最终建议:
    • 开发/测试环境:完全可以混合部署,节省成本。
    • 生产环境:除非是极小规模(如日均 PV < 1万)或边缘节点,否则强烈建议按功能拆分服务器。数据库是 IO 密集型应用,混合部署带来的调试成本和故障排查难度,远高于几台云服务器的费用。

如果你正在搭建这套环境,先从 Docker Compose 或 systemd + cgroups 入手,做好资源限额,这是性价比最高的隔离方式。