MySQL和Redis共用同一台Linux服务器时,磁盘IO和内存如何优化配置?

当 MySQL 和 Redis 共存于同一台 Linux 服务器时,二者对资源(尤其是内存和磁盘 I/O)存在显著竞争,若配置不当,极易引发性能抖动、OOM Killer 干预、慢查询激增或 Redis 频繁 swap。以下是生产环境推荐的系统级 + 应用级协同优化策略,兼顾稳定性、性能与可维护性:


🔑 一、核心原则(先决条件)

  1. 明确角色边界

    • ✅ MySQL:持久化、事务、复杂查询 → 依赖磁盘 I/O + 内存缓冲(InnoDB Buffer Pool)
    • ✅ Redis:高速缓存/会话存储 → 纯内存操作,拒绝 swap,容忍有限持久化开销
      禁止让 Redis 与 MySQL 争抢关键资源
  2. 资源总量评估(必须做!)

    free -h    # 总内存 & 可用内存(注意 buff/cache)
    iostat -x 1 3  # 磁盘 %util, await, r/s w/s, avgqu-sz(识别瓶颈)
    df -h      # 磁盘空间 & Inode 使用率(尤其 /var/lib/mysql 和 /var/lib/redis)

🧠 二、内存优化(最关键!防 OOM 和 Swap)

组件 关键配置 推荐值(示例:64GB 总内存) 原因与说明
Linux Kernel vm.swappiness=1 echo 'vm.swappiness=1' >> /etc/sysctl.conf && sysctl -p ⚠️ 严禁设为 0(会导致 OOM Killer 更激进),设为 1 表示仅在内存极度紧张时才 swap,保护 Redis
Redis maxmemory + maxmemory-policy maxmemory 24gb(占总内存 ≤35%)
maxmemory-policy allkeys-lru(避免 volatile-* 在无过期键时失效)
✅ 强制内存上限,防止吃光内存
❌ 禁用 noeviction(除非你确定绝不超限)
MySQL (InnoDB) innodb_buffer_pool_size innodb_buffer_pool_size = 28g(≤45% 总内存,留足 OS 缓存 + Redis) 💡 Buffer Pool 是 MySQL 最耗内存的部分,需预留至少 8~12GB 给 OS(文件缓存)、Redis、其他进程
OS 层 vm.vfs_cache_pressure=50 echo 'vm.vfs_cache_pressure=50' >> /etc/sysctl.conf 降低内核回收 dentry/inode 缓存的倾向,提升文件系统性能(利好 MySQL 大量小文件场景)

验证内存分配合理性

# 检查实际使用(避免 buffer pool + redis + os cache 超过物理内存)
ps -eo pid,ppid,cmd,%mem --sort=-%mem | head -10
cat /proc/meminfo | grep -E "MemTotal|MemFree|Buffers|Cached|SReclaimable"

⚠️ 严重警告

  • 若 Redis 启用了 savebgsave(RDB),fork 子进程时会复制页表(COW),瞬时内存需求 ≈ 当前 Redis 数据集大小!确保 free -h 显示的 "available" ≥ Redis maxmemory,否则 fork 失败导致 RDB 持久化中断。
  • MySQL 的 innodb_buffer_pool_size 必须小于 MemAvailable(非 MemFree),否则启动失败。

💾 三、磁盘 I/O 优化(减少争抢,提升吞吐)

场景 优化措施 操作命令/配置
磁盘分离(强烈推荐) 将 MySQL 数据目录(/var/lib/mysql)与 Redis 持久化目录(/var/lib/redis)放在不同物理磁盘/分区(如 SSD vs NVMe) bash<br>mkdir -p /mnt/ssd/mysql /mnt/nvme/redis<br>chown mysql:mysql /mnt/ssd/mysql<br>chown redis:redis /mnt/nvme/redis<br># 修改 my.cnf: datadir = /mnt/ssd/mysql<br># 修改 redis.conf: dir /mnt/nvme/redis
I/O 调度器优化 对 SSD/NVMe:none(禁用调度器);对 SATA HDD:deadline bash<br>echo 'none' > /sys/block/nvme0n1/queue/scheduler<br># 加入 /etc/rc.local 或 udev rule 持久化
MySQL 日志优化 减少刷盘频率,但保证崩溃恢复能力 ini<br># my.cnf<br>innodb_flush_log_at_trx_commit = 2 # 折中:每秒刷日志,非每次事务(牺牲极小安全性)<br>sync_binlog = 1000 # 每1000次事务同步 binlog(非 1)<br>innodb_io_capacity = 2000 # 根据 SSD 实测 IOPS 设置(如 NVMe 可设 5000+)
Redis 持久化策略 禁用 RDB + AOF 混合;优先选 appendonly yes + aof-use-rdb-preamble yes(Redis 7.0+),或仅用 AOF(appendfsync everysec conf<br>save "" # 彻底禁用 RDB 触发式保存<br>appendonly yes<br>appendfsync everysec # 平衡性能与数据丢失风险<br>no-appendfsync-on-rewrite yes # BGREWRITEAOF 时不触发 fsync
文件系统挂载选项 对 MySQL/Redis 数据盘启用 noatime,nobarrier(SSD)或 barrier=1(HDD) bash<br># /etc/fstab 示例(SSD)<br>/dev/nvme0n1p1 /mnt/nvme ext4 defaults,noatime,nobarrier 0 0

🔍 I/O 监控必备命令

# 实时观察各进程 I/O(安装 iotop)
iotop -o -P  # 只显示实际 I/O 进程
# 查看磁盘队列深度(长期 >2 表示饱和)
iostat -x 1 | grep -E "(nvme|sda).*await|avgqu-sz"

🛡 四、进阶防护与监控

  1. cgroups v2 隔离(Linux 5.0+,强烈推荐)
    限制 MySQL 和 Redis 的内存/CPU 上限,彻底避免互相影响:

    # 创建 memory cgroup
    sudo mkdir -p /sys/fs/cgroup/mysql /sys/fs/cgroup/redis
    echo "28G" | sudo tee /sys/fs/cgroup/mysql/memory.max
    echo "24G" | sudo tee /sys/fs/cgroup/redis/memory.max
    # 启动时绑定进程(systemd service 中添加)
    MemoryMax=24G  # in redis.service [Service] section
  2. 关键监控指标(接入 Prometheus + Grafana)

    • MySQL:Innodb_buffer_pool_wait_free, Threads_connected, Innodb_data_pending_reads/writes
    • Redis:used_memory_rss, mem_fragmentation_ratio, evicted_keys, expired_keys, aof_last_rewrite_time_sec
    • 系统:node_memory_MemAvailable_bytes, node_disk_io_time_seconds_total, node_vmstat_pgmajfault(大页缺页,预示 swap 风险)
  3. 备份与维护错峰

    • MySQL mysqldump / xtrabackup 安排在业务低谷,并设置 ionice -c2 -n7 降低 I/O 优先级
    • Redis BGSAVE / BGREWRITEAOF 避免与 MySQL 备份同时运行

🚫 五、绝对禁止的配置

风险项 为什么危险 替代方案
vm.swappiness=0 内核无法 swap,OOM Killer 直接杀进程(常杀 Redis 或 MySQL) 设为 1
Redis maxmemory 未设置 内存无限增长,挤占 MySQL 和 OS 必须显式配置
MySQL innodb_buffer_pool_size > 50% 总内存 OS 缓存不足,MySQL 文件 I/O 性能暴跌 ≤45%,留足给 OS + Redis
Redis AOF appendfsync always 每次写都刷盘,I/O 压力爆炸 改用 everysec
MySQL 和 Redis 共用同一块机械硬盘 随机读写(Redis)与顺序写(MySQL binlog)严重干扰 物理磁盘分离

✅ 总结:检查清单(部署前必做)

  1. [ ] free -h 确认 available ≥ Redis maxmemory + MySQL innodb_buffer_pool_size + 12GB
  2. [ ] iostat -x 1 确认磁盘 %util < 70%await < 10ms(SSD)
  3. [ ] /proc/sys/vm/swappiness = 1
  4. [ ] MySQL datadir 和 Redis dir不同物理设备
  5. [ ] Redis save ""(禁用 RDB)且 appendonly yes + appendfsync everysec
  6. [ ] MySQL innodb_flush_log_at_trx_commit=2sync_binlog=1000
  7. [ ] 配置 cgroups 或 systemd resource limits(内存硬限制)

💡 终极建议:单机共存是成本妥协方案。若业务增长,优先拆分为 MySQL 专用服务器 + Redis 专用服务器,这是最简单、最稳定的架构演进路径。

需要我为你生成对应的 my.cnf / redis.conf 完整模板(适配你具体的内存大小),或编写自动化检查脚本(Bash/Python),请随时告知!

未经允许不得转载:云计算HECS » MySQL和Redis共用同一台Linux服务器时,磁盘IO和内存如何优化配置?