当 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 < 2G或rate(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) |
✅ 六、快速检查清单(部署前必做)
- [ ]
free -h确认总内存,分配 Redismaxmemory和 MySQLinnodb_buffer_pool_size - [ ]
lsblk && df -h确认 MySQLdatadir和 Redisdir在不同物理设备或至少不同挂载点 - [ ]
sysctl vm.swappiness=1,vm.overcommit_memory=2 - [ ] Redis
redis.conf中maxmemory和maxmemory-policy已配置 - [ ] MySQL
my.cnf中innodb_buffer_pool_size≤ 可用内存 × 0.6,且innodb_log_file_size≥ 256M - [ ]
systemctl show redis-server --property=MemoryMax和mysqld已设 cgroups 限制(推荐) - [ ]
iostat -x 1观察空载时各磁盘%util< 10%,await < 5ms(NVMe)
如需进一步定制(例如:具体硬件配置推荐、Ansible 自动化脚本、压测对比数据),欢迎提供服务器规格(CPU/内存/磁盘型号/数量)和业务特征(QPS、读写比、数据量级、一致性要求),我可给出精准调优方案。
✨ 最后忠告:在生产环境,宁可让 Redis/MySQL 各自“少吃一口”,也不要让它们“抢破头”。资源隔离不是过度设计,而是稳定性基石。
CLOUD云计算