走啊走
加油

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

服务器价格表

当 MySQL 和 Redis 共存于同一台 Linux 服务器时,二者对资源(尤其是内存和磁盘 I/O)的竞争容易引发性能瓶颈。合理优化需遵循「隔离优先、资源可控、I/O 分离、监控驱动」原则。以下是经过生产验证的优化配置建议:


🔑 一、核心原则

资源 原则 说明
内存 严格隔离 + 预留余量 Redis 是内存数据库,MySQL 缓冲池也吃内存;二者不可争抢,必须硬性限制
磁盘 I/O 分离路径 + 优化策略 避免 MySQL 的 redo/log/WAL 与 Redis 的 RDB/AOF 写入同一物理盘或同一 mount point
CPU 合理绑定(可选) 高负载场景下可考虑 taskset 或 cgroups 绑定 CPU 核心,避免调度抖动

🧠 二、内存优化配置(最关键!)

✅ 1. Redis 内存限制(强制)

# redis.conf
maxmemory 4g                    # 硬性上限(根据总内存 × 0.4~0.5 设定)
maxmemory-policy allkeys-lru    # 或 volatile-lru(推荐有 TTL 的业务)
# ⚠️ 必须设置!否则 Redis 可能 OOM kill 或拖垮系统

💡 计算建议

  • 总内存 32G → Redis ≤ 12–14G(预留 4G 系统+缓存+MySQL)
  • 启用 vm.swappiness=1(见下文),禁止 Redis 使用 swap

✅ 2. MySQL 内存限制(关键参数)

# my.cnf
[mysqld]
# —— 必设缓冲区(占可用内存 50%~65%,非总量!)
innodb_buffer_pool_size = 8G     # ≈ 总内存 × 0.3~0.4(如32G机器设8–12G)
innodb_log_file_size = 512M      # 减少 checkpoint 频率(需停机调整)
innodb_log_buffer_size = 16M
key_buffer_size = 32M            # MyISAM 已少用,可设小值
tmp_table_size = 64M
max_heap_table_size = 64M

# —— 限制连接内存消耗
sort_buffer_size = 512K           # 按需调低,避免大排序爆内存
read_buffer_size = 256K
join_buffer_size = 512K
# ❗ 所有 *buffer_size 类参数 × max_connections ≤ 1–2G(防连接数多时OOM)

✅ 3. 系统级内存保障

# /etc/sysctl.conf
vm.swappiness = 1                # ⚠️ 关键!禁止 MySQL/Redis 频繁 swap
vm.overcommit_memory = 2        # 允许 overcommit,但需配合 maxmemory(Redis)和 buffer_pool_size(MySQL)
vm.vfs_cache_pressure = 50       # 降低 inode/dentry 缓存回收压力,保文件系统性能

# 生效
sudo sysctl -p

✅ 4. 进程级内存约束(推荐!cgroups v2)

# 创建 memory.slice(以 systemd 为例)
sudo systemctl edit redis-server
# 添加:
[Service]
MemoryMax=12G
MemoryHigh=10G   # 触发内核内存回收阈值

sudo systemctl edit mysqld
[Service]
MemoryMax=14G
MemoryHigh=12G

sudo systemctl daemon-reload && sudo systemctl restart redis-server mysqld

✅ 效果:彻底防止任一服务吃光内存导致 OOM Killer 杀进程。


💾 三、磁盘 I/O 优化配置

✅ 1. 物理/逻辑分离(强烈推荐)

服务 推荐存储位置 文件系统建议 关键挂载选项
MySQL /data/mysql(独立 SSD/NVMe) XFS(高并发写稳定) noatime,nodiratime,logbufs=8,logbsize=256k
Redis /data/redis(另一块 SSD 或同盘不同分区) XFS 或 ext4 noatime,nodiratime
系统日志 /var/log(可放 SATA 盘)

⚠️ 绝对避免:MySQL 的 datadir 和 Redis 的 dir 指向同一挂载点(如都放在 /data 下无子目录隔离)→ I/O 争抢严重!

✅ 2. Redis 持久化调优(降低 I/O 冲突)

# redis.conf
# —— RDB:低频大写,适合备份
save 900 1
save 300 10
save 60 10000
# —— AOF:高频小写,易与 MySQL redo log 冲突 → 建议关闭或改用 everysec
appendonly yes
appendfsync everysec   # ⚠️ 不要用 always(同步刷盘阻塞主线程且 I/O 压力大)
no-appendfsync-on-rewrite yes  # AOF rewrite 时不触发 fsync

# —— 可选:AOF rewrite 使用后台线程(Redis 7.0+)
aof-use-rdb-preamble yes   # 混合持久化,减少 rewrite 时间和 I/O

✅ 3. MySQL I/O 关键优化

# my.cnf
[mysqld]
# —— 日志分离(最重要!)
innodb_redo_log_capacity = 2G    # ≥ 2× innodb_log_file_size,提升写吞吐
innodb_log_group_home_dir = /data/mysql/redolog/   # 独立目录(建议软链到高速盘)

# —— 刷盘策略平衡
innodb_flush_log_at_trx_commit = 1   # 强一致性(默认),若允许短暂丢失可设2(每秒刷一次)
innodb_flush_method = O_DIRECT       # 绕过 OS cache,避免双重缓存(XFS 推荐)

# —— 表空间分离(可选)
innodb_file_per_table = ON
innodb_data_home_dir = /data/mysql/ibdata/
innodb_data_file_path = ibdata1:1G:autoextend
# 将系统表空间与用户表空间物理隔离

✅ 4. I/O 调度器与队列深度(SSD 场景)

# 查看当前调度器
cat /sys/block/nvme0n1/queue/scheduler

# SSD 推荐使用 none(noop)或 kyber(Linux 5.0+)
echo 'kyber' | sudo tee /sys/block/nvme0n1/queue/scheduler

# 提升队列深度(NVMe)
echo 1024 | sudo tee /sys/block/nvme0n1/queue/nr_requests

📊 四、监控与告警(落地关键)

工具 监控项 阈值建议 说明
htop / free -h Redis RSS vs maxmemory、MySQL RES Redis RSS > maxmemory × 1.1 → 危险 看实际内存占用
iostat -x 2 %util, await, r/s, w/s await > 20ms(SSD)→ I/O 瓶颈 分别看 /dev/nvme0n1p1/dev/sda1
mysqladmin extended -r -i 1 Innodb_buffer_pool_wait_free, Innodb_log_waits > 0 持续出现 → 内存/I/O 不足
redis-cli info memory used_memory_rss, mem_fragmentation_ratio ratio > 1.5 → 内存碎片高;> 2.0 → 考虑重启
dmesg -T | grep -i "killed process" OOM Killer 日志 出现即失败,必须优化内存限制

自动化建议:用 Prometheus + Grafana 配置告警规则(如 node_memory_MemAvailable_bytes < 2Grate(redis_memory_used_bytes[5m]) > 0.9


🚫 五、必须避免的错误配置

错误做法 后果 正解
Redis 不设 maxmemory 内存耗尽触发 OOM Killer,MySQL/SSH 都被杀 ✅ 必设 + maxmemory-policy
MySQL innodb_buffer_pool_size 设为 80% 总内存 Redis 启动即 OOM ✅ Buffer Pool ≤ 可用内存 × 60%(预留系统+Redis)
MySQL 和 Redis 日志共用一块 SATA 盘 随机写 + 顺序写互相干扰,I/O 等待飙升 ✅ 至少分盘,理想是分 NVMe 分区
vm.swappiness=60(默认) Redis/MySQL 大量 swap,延迟飙升至秒级 swappiness=1 + overcommit_memory=2
Redis AOF appendfsync always + MySQL innodb_flush_log_at_trx_commit=1 双重强刷盘,I/O 成瓶颈 ✅ Redis 用 everysec,MySQL 按业务权衡(X_X设1,日志类可设2)

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

  1. [ ] free -h 确认总内存,分配 Redis maxmemory 和 MySQL innodb_buffer_pool_size
  2. [ ] lsblk && df -h 确认 MySQL datadir 和 Redis dir不同物理设备或至少不同挂载点
  3. [ ] sysctl vm.swappiness = 1vm.overcommit_memory = 2
  4. [ ] Redis redis.confmaxmemorymaxmemory-policy 已配置
  5. [ ] MySQL my.cnfinnodb_buffer_pool_size ≤ 可用内存 × 0.6,且 innodb_log_file_size ≥ 256M
  6. [ ] systemctl show redis-server --property=MemoryMaxmysqld 已设 cgroups 限制(推荐)
  7. [ ] iostat -x 1 观察空载时各磁盘 %util < 10%,await < 5ms(NVMe)

如需进一步定制(例如:具体硬件配置推荐、Ansible 自动化脚本、压测对比数据),欢迎提供服务器规格(CPU/内存/磁盘型号/数量)和业务特征(QPS、读写比、数据量级、一致性要求),我可给出精准调优方案。

最后忠告:在生产环境,宁可让 Redis/MySQL 各自“少吃一口”,也不要让它们“抢破头”。资源隔离不是过度设计,而是稳定性基石。