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

在 Linux 服务器上同时运行 MySQL 和 Redis,本质上是在处理两种截然不同的资源竞争模型:MySQL 是 CPU 密集型与随机 IO 密集型(取决于查询模式),而 Redis 是内存密集型与高并发网络 IO 密集型。

当它们共用同一台物理机时,最大的风险在于“资源抢占”导致的抖动。以下是从内核参数、文件系统、应用配置三个层面给出的具体优化方案,旨在隔离干扰、提升吞吐量。

一、 核心原则:隔离与预留

不要试图让两个服务平分资源,而是根据它们的特性进行“硬隔离”或“优先级设定”。

  1. 内存隔离:Redis 必须独占足够内存以保证全量数据在 RAM 中;MySQL 需要剩余内存用于 Buffer Pool 和 OS Cache。
  2. IO 隔离:避免两者同时产生大量随机写操作。如果可能,将 MySQL 的 Redo Log 和 Binlog 放在 SSD/NVMe 上,而 Redis 的 RDB/AOF 也尽量利用 OS Page Cache(因为 Redis 本身是内存数据库,持久化频率可控)。

二、 Linux 内核级优化(sysctl.conf)

这是最基础也是最重要的环节。编辑 /etc/sysctl.conf,添加或修改以下参数:

1. 虚拟内存管理(vm.*)

# 1. 降低 swappiness
# 默认值通常是 60。对于 Redis 这种强依赖内存的应用,必须设为 0 或 1。
# 防止 Redis 热点数据被 swap 出去,导致性能断崖式下跌。
vm.swappiness = 0

# 2. 调整 dirty 页面回写策略
# 减少 MySQL 和 Redis 对磁盘刷盘频率的影响,利用更大的 OS Page Cache。
vm.dirty_background_ratio = 5    # 后台进程开始刷脏页的比例(默认10)
vm.dirty_ratio = 10              # 阻塞用户进程直到刷脏页的比例(默认20)
vm.dirty_expire_centisecs = 3000 # 脏页超过此时间强制刷盘
vm.dirty_writeback_centisecs = 500 # 后台线程刷盘间隔

# 3. 提高 inode 缓存上限
# 如果业务涉及大量小文件或小对象,可适当调高
vm.vfs_cache_pressure = 50       # 默认100,降低可保留更多目录项/inode缓存

注意:vm.swappiness=0 是 Redis 运行的必要条件之一。

2. 网络栈优化(net.*)

Redis 是高并发短连接或长连接场景,MySQL 通常是中等并发。优化 TCP 缓冲:

# 增加 TCP 接收/发送缓冲区大小
net.core.rmem_max = 16777216     # 16MB
net.core.wmem_max = 16777216
net.core.rmem_default = 1048576
net.core.wmem_default = 1048576

# TCP 拥塞控制算法选择
# bbr 在现代 Linux 内核(4.9+)下通常表现更好,尤其在高延迟网络
net.ipv4.tcp_congestion_control = bbr

# 允许重用 TIME_WAIT 套接字
net.ipv4.tcp_tw_reuse = 1

# 增大本地端口范围,避免高并发下端口耗尽
net.ipv4.ip_local_port_range = 1024 65535

3. 调度器与 CPU 亲和性(可选但推荐)

如果服务器核心数较多(如 8C+),可以考虑使用 cgroups 或 taskset 绑定进程到特定 CPU 核,但这属于高级运维范畴,初期建议先优化系统参数。


三、 文件系统与挂载选项

1. 文件系统选择

  • 推荐:XFS 或 ext4。
  • 不推荐:老旧的 ext3 或在高性能场景下的 NTFS/FAT。
  • 日志模式:确保使用 data=ordered(ext4/XFS 默认),这能平衡性能和一致性。

2. Mount Options 优化

在 /etc/fstab 中挂载数据盘时,添加以下选项:

# 示例:/dev/vdb1 /data xfs defaults,noatime,nodiratime,commit=60 0 0
noatime,nodiratime  # 禁止访问时间更新,减少不必要的元数据 IO
commit=60           # XFS 特有,每秒最多刷新一次脏数据到磁盘,降低 IO 压力
barrier=0           # 【谨慎使用】如果使用的是带电池保护的 RAID 卡或 NVMe,可关闭 barrier 提升写入性能;否则保持开启以保数据完整性

重要提醒:barrier=0 会牺牲数据安全性换取性能。如果是云服务器的普通云盘,不建议关闭,因为底层存储可能有断电丢数据风险。如果是自建机房且硬件可靠,可考虑。

3. I/O Scheduler 设置

查看当前调度器:cat /sys/block/sda/queue/scheduler

  • HDD(机械硬盘):设置为 deadline 或 bfq。
  • SSD/NVMe:设置为 none 或 mq-deadline。
# 临时设置
echo none > /sys/block/vda/queue/scheduler
echo mq-deadline > /sys/block/vdb/queue/scheduler

四、 应用层配置优化

1. Redis 配置 (redis.conf)

  • maxmemory:设置为物理内存的 70%-80%,留出空间给 OS 和其他进程。
  • maxmemory-policy:根据业务选择 allkeys-lru 或 volatile-lru。
  • save/aof:
    • 如果追求极致性能,可禁用 RDB(save ""),仅开启 AOF,并设置 appendfsync everysec。
    • 避免在高峰时段触发 bgrewriteaof 或 bgsave,可通过 auto-aof-rewrite-percentage 调整触发阈值。
  • hz:将 hz 从默认的 10 改为 100(需重启),提高内部任务执行频率,但会增加 CPU 开销,视情况而定。
  • tcp-backlog:适当调大,如 1024 或 2048,配合 somaxconn。

2. MySQL 配置 (my.cnf)

  • innodb_buffer_pool_size:设置为物理内存的 50%-70%。
    • 关键点:如果 Redis 占用了大部分内存,MySQL 的 Buffer Pool 会变小,可能导致查询变慢。此时应评估是否可以将 MySQL 迁移到独立实例。
  • innodb_log_file_size:增大日志文件大小(如 1G~4G),减少 Checkpoint 频率,提升写入吞吐。
  • innodb_flush_log_at_trx_commit:
    • 设为 1:最高安全性,每次事务都刷盘,IO 压力大。
    • 设为 2:每秒刷盘,性能提升显著,宕机最多丢失 1 秒数据。在共用服务器上,建议设为 2,通过应用层重试机制补偿极端情况。
  • sync_binlog:设为 1 或 100。如果非X_X级强一致要求,可设为 100 以上。

五、 监控与告警(关键!)

没有监控的优化是盲目的。重点监控以下指标:

  1. Redis:
    • used_memory_rss vs maxmemory:接近上限时需警惕。
    • blocked_clients:反映客户端等待响应的时间。
    • instantaneous_ops_per_sec:观察峰值。
  2. MySQL:
    • Innodb_buffer_pool_read_requests vs Innodb_buffer_pool_reads:计算缓存命中率,目标 > 99%。
    • Threads_running:并发线程数。
  3. 系统级:
    • iostat -x 1:关注 %util(利用率)和 await(平均等待时间)。如果 await > 20ms,说明 IO 瓶颈已出现。
    • free -m:观察 available memory,确保没有频繁 swap。

六、 终极建议:架构解耦

虽然上述优化能在一定程度上缓解冲突,但从工程角度,强烈建议将 MySQL 和 Redis 部署在不同节点。

原因如下:

  1. 故障域隔离:Redis 内存泄漏或 OOM Kill 不会影响 MySQL 进程(反之亦然)。
  2. 资源争用不可控:即使做了 cgroups 隔离,Linux 内核调度仍存在不确定性。
  3. 扩展性:两者负载增长曲线不同步。Redis 可能因缓存穿透瞬间打满 CPU/Memory,而 MySQL 可能因复杂 JOIN 吃光 IO。

如果受限于成本必须共用一台服务器,请遵循以下底线:

  • 使用 SSD/NVMe 存储。
  • vm.swappiness=0。
  • Redis 内存不超过总内存 70%。
  • MySQL InnoDB Log 文件加大。
  • 密切监控 iowait 和 swap 使用情况。
未经允许不得转载:CLOUD云枢 » MySQL和Redis共用同一台Linux服务器时,磁盘IO和内存如何优化配置?