奋斗
努力

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

云计算

在 MySQL 和 Redis 共用一台 Linux 服务器时,若未合理规划资源(尤其是磁盘 I/O 和内存),极易出现资源争抢、性能抖动、响应延迟飙升甚至服务不可用等问题。以下是基于生产实践的系统性优化配置建议,兼顾稳定性、性能与可维护性:


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

  1. 不推荐共用生产环境:高负载场景下强烈建议物理/逻辑隔离(如容器+资源限制、或拆分到不同节点)。本文假设受限于成本/架构暂需共存。
  2. 监控先行:部署 iostat, vmstat, htop, redis-cli info memory, mysqladmin extended-status 及 Prometheus + Grafana,明确瓶颈再调优。
  3. 避免“一刀切”配置:需根据实际 workload(读写比、数据量、QPS、延迟敏感度)动态调整。

💾 二、磁盘 I/O 优化策略

维度 MySQL 优化 Redis 优化 协同避坑
存储介质 ✅ 强烈建议 MySQL 数据目录(datadir)、日志(innodb_log_group_home_dir, slow_query_log_file, general_log_file)挂载到 SSD/NVMe 分区;
❌ 禁止与系统盘或 Redis 共用机械盘
✅ Redis 持久化(RDB/AOF)文件必须放在 独立 SSD 分区(如 /data/redis/);
❌ 禁止与 MySQL 日志/数据混放(避免顺序写 vs 随机写冲突)
⚠️ 关键:MySQL 的 InnoDB 日志(ib_logfile*)和 Redis 的 AOF 重写(BGREWRITEAOF)都是大块顺序写,若共用同一物理盘,会因磁头/队列争抢导致写延迟飙升(>100ms)→ 必须物理分离
I/O 调度器 ✅ MySQL(随机读写为主):
echo deadline > /sys/block/nvme0n1/queue/scheduler(NVMe 用 none,SATA SSD 用 deadlinemq-deadline
✅ Redis(顺序写为主):
同上,但更推荐 none(NVMe)或 deadline(SATA SSD)
✅ 统一设置:echo 'vm.swappiness = 1' >> /etc/sysctl.conf(降低 swap 倾向,避免 I/O 放大)
文件系统 ✅ XFS(推荐):支持大文件、延迟分配、noatime,nobarrier(若硬件有断电保护)
❌ 避免 ext4(小文件多时元数据开销大)
✅ XFS 同样适用;
✅ 挂载参数:noatime,nodiratime,logbufs=8,logbsize=256k(提升日志性能)
统一挂载参数示例
mount -o noatime,nodiratime,barrier=1 /dev/nvme0n1p1 /var/lib/mysql
mount -o noatime,nodiratime,logbufs=8,logbsize=256k /dev/nvme0n1p2 /var/lib/redis
持久化策略协同 ✅ 关闭 innodb_flush_log_at_trx_commit=2(牺牲少量安全性换性能,配合电池缓存 RAID 卡)
sync_binlog=1000(降低 binlog 刷盘频率)
✅ RDB:save 900 1(低频大快照)
✅ AOF:appendfsync everysec(平衡安全与性能)
❌ 禁用 always(每命令刷盘 → I/O 雪崩)
⚠️ 禁止同时触发:避免 MySQL checkpoint + Redis AOF rewrite + RDB save 同时发生 → 用 cron 错峰(如 MySQL 备份在凌晨2点,Redis RDB 在凌晨3点)

🧠 三、内存优化与隔离(重中之重!)

✅ 1. 内存总量分配(硬性约束)

  • 总内存 = M(例如 64GB)
  • Redis 内存上限
    maxmemory 32gbredis.conf
    maxmemory-policy allkeys-lru(避免 OOM kill)
    预留至少 2GB 给 OS 缓存 + Redis 自身开销
  • MySQL 内存上限
    # my.cnf
    innodb_buffer_pool_size = 24G   # ≤ 总内存 × 0.4(若 Redis 占 32G,则 64×0.4=25.6G → 取24G)
    key_buffer_size = 32M            # MyISAM 仅用于系统表,可忽略
    sort_buffer_size = 2M            # 按需调小,避免线程级内存爆炸
    read_buffer_size = 1M
    join_buffer_size = 2M
    tmp_table_size = 64M
    max_heap_table_size = 64M
  • OS 预留:≥ 4GB(文件缓存、网络栈、内核页表等)

验证公式Redis_maxmemory + MySQL_innodb_buffer_pool_size + 4GB ≤ 总内存

✅ 2. 防止 OOM Killer 杀进程(生死线!)

# 为 Redis 进程降低 OOM 优先级(越负越不易被杀)
echo -500 > /proc/$(pgrep redis-server)/oom_score_adj

# 为 MySQL 进程设为中等优先级
echo -200 > /proc/$(pgrep mysqld)/oom_score_adj

# 永久生效(systemd 服务文件中添加)
# /etc/systemd/system/redis.service
[Service]
OOMScoreAdjust=-500

# /etc/systemd/system/mysqld.service  
[Service]
OOMScoreAdjust=-200

✅ 3. 内存透明大页(THP)—— 必须禁用!

# 临时禁用
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

# 永久禁用(/etc/rc.local 或 systemd)
echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.local
echo 'echo never > /sys/kernel/mm/transparent_hugepage/defrag' >> /etc/rc.local

❗原因:MySQL/Redis 的内存访问模式高度随机,THP 会导致内存碎片、延迟毛刺,实测 QPS 下降 20%+。

✅ 4. NUMA 优化(多路 CPU 服务器)

# 查看 NUMA 节点
numactl --hardware

# 启动 MySQL 时绑定到本地内存节点(避免跨 NUMA 访问)
numactl --cpunodebind=0 --membind=0 /usr/sbin/mysqld &

# Redis 同理(但 Redis 单线程,通常只需绑 CPU)
numactl --cpunodebind=1 redis-server /etc/redis.conf

🛠 四、进阶协同优化技巧

场景 方案 命令/配置
日志 I/O 隔离 MySQL 的 slow_query_logerror_log 单独挂 SSD 小分区 slow_query_log_file = /ssd-logs/mysql-slow.log
Redis 不持久化? 若业务允许(纯缓存),彻底关闭 RDB+AOF → 零磁盘 I/O save "" + appendonly no
MySQL 压缩表 对历史归档表启用 ROW_FORMAT=COMPRESSED,减少 buffer pool 占用 ALTER TABLE t1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
内核参数加固 减少 swap 使用、优化 TCP、文件句柄 bash<br>echo 'vm.swappiness = 1' >> /etc/sysctl.conf<br>echo 'net.ipv4.tcp_tw_reuse = 1' >> /etc/sysctl.conf<br>echo '* soft nofile 65536' >> /etc/security/limits.conf<br>
定时任务错峰 避免备份、清理、AOF rewrite 同时运行 bash<br># MySQL 备份(凌晨2:00)<br>0 2 * * * /backup/mysql-backup.sh<br># Redis RDB(凌晨3:30)<br>30 3 * * * redis-cli bgsave<br>

📉 五、必须规避的致命错误

  • innodb_buffer_pool_size + maxmemory > 总内存 → 触发频繁 swap → I/O 雪崩
  • ❌ Redis 使用 vm.overcommit_memory=1(默认)+ maxmemory 未设 → 内存超卖 → OOM Kill
  • ❌ MySQL 和 Redis 日志写入同一块 SATA 盘 → 随机写(InnoDB)与顺序写(AOF)互相干扰 → 平均延迟翻倍
  • ❌ 忽略 ulimit -n(文件描述符)→ 连接数暴涨时大量 Too many open files 错误
  • ❌ 未关闭 THP → Redis INFO memory 显示 mem_allocator:jemalloc 但仍有延迟毛刺

✅ 六、快速检查清单(部署后必做)

# 1. 内存是否超限?
free -h && cat /proc/meminfo | grep -E "MemAvailable|Buffers|Cached"

# 2. Redis 是否受 OOM 影响?
redis-cli info memory | grep -E "used_memory|maxmemory|mem_fragmentation_ratio"

# 3. MySQL Buffer Pool 命中率?
mysql -e "SHOW ENGINE INNODB STATUSG" | grep -A 5 "Buffer pool hit rate"

# 4. 磁盘 I/O 是否争抢?
iostat -x 1 5 | grep -E "(nvme|sda)"  # 观察 %util, await, r_await, w_await

# 5. OOM Score 是否生效?
cat /proc/$(pgrep redis-server)/oom_score_adj  # 应为 -500
cat /proc/$(pgrep mysqld)/oom_score_adj         # 应为 -200

🌐 结语

共存不是不可以,但必须以“隔离”为设计前提,以“监控”为决策依据,以“渐进调优”为实施路径。建议:

  • 第一阶段:按本文配置基础参数 + 错峰调度,跑 3 天压力测试(sysbench + redis-benchmark);
  • 第二阶段:根据 iostat/vmstat 数据微调 innodb_io_capacityredis maxmemory
  • 第三阶段:长期观察 mem_fragmentation_ratio(Redis > 1.5 需重启)、Innodb_buffer_pool_wait_free(MySQL > 0 需增大 buffer pool)。

如仍有性能问题,终极方案:用 cgroups v2 严格限制 I/O bandwidth 和 memory usage(需 Linux 5.0+),但这已接近容器化管理范畴。

需要我为你生成 完整的 my.cnf + redis.conf 示例模板(含注释),或提供 cgroups 限速脚本,可随时告知 👇

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