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

MySQL 与 Redis 共用 Linux 服务器的资源优化配置

一、整体架构原则

┌─────────────────────────────────────────────┐
│           Linux Server (共享资源)             │
│                                             │
│  ┌──────────┐    ┌──────────┐               │
│  │  MySQL   │    │  Redis   │               │
│  │ (磁盘IO) │    │(内存为主) │               │
│  └────┬─────┘    └────┬─────┘               │
│       │               │                      │
│  ┌────▼───────────────▼────┐                 │
│  │     Linux Kernel        │                 │
│  │  - cgroups / cpuset     │                 │
│  │  - I/O Scheduler        │                 │
│  │  - Page Cache           │                 │
│  │  - Swap Management      │                 │
│  └─────────────────────────┘                 │
└─────────────────────────────────────────────┘

核心矛盾:MySQL 重度依赖磁盘 IO + 页缓存,Redis 重度依赖内存。两者共存时需在 内存分配、磁盘 IO 调度、CPU 隔离 三个维度做精细调优。


二、内存优化配置

1. 明确各自内存预算

# 查看当前内存使用
free -h
cat /proc/meminfo | grep -E "MemTotal|MemFree|Buffers|Cached"

2. MySQL 内存配置(my.cnf)

[mysqld]
# --- 关键内存参数 ---

# InnoDB Buffer Pool: 占总内存的 50%~70%
innodb_buffer_pool_size = 4G

# InnoDB Buffer Pool 实例数(大内存时提升并发)
innodb_buffer_pool_instances = 8

# Redo Log 大小(避免频繁刷盘)
innodb_log_file_size = 1G
innodb_log_buffer_size = 64M

# 连接相关内存(每个连接额外占用)
max_connections = 200
thread_cache_size = 16

# sort_buffer, join_buffer 等每连接参数要小!
sort_buffer_size = 2M
read_buffer_size = 1M
read_rnd_buffer_size = 4M
join_buffer_size = 1M

# tmp_table_size 和 max_heap_table_size 限制临时表内存
tmp_table_size = 64M
max_heap_table_size = 64M

# Query Cache 已废弃,不要启用
query_cache_type = 0
query_cache_size = 0

3. Redis 内存配置(redis.conf)

# --- 关键内存参数 ---

# 最大内存限制(必须设置!防止 OOM)
maxmemory 2gb

# 淘汰策略(根据业务选择)
maxmemory-policy allkeys-lru
# 或: volatile-lru / allkeys-random / noeviction(生产慎用)

# LRU 采样精度
maxmemory-samples 10

# AOF vs RDB 内存影响
aof-use-rdb-preamble yes          # 混合持久化,减少内存峰值
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 客户端输出缓冲区限制(防止慢客户端耗尽内存)
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60

# THP 透明大页禁用(见内核参数部分)

4. 内存压力监控与告警

# 创建监控脚本 /opt/monitor/memory_alert.sh
#!/bin/bash
TOTAL_MEM=$(free -m | awk '/^Mem:/{print $2}')
AVAIL_MEM=$(free -m | awk '/^Mem:/{print $7}')
USED_PERCENT=$(( (TOTAL_MEM - AVAIL_MEM) * 100 / TOTAL_MEM ))

if [ $USED_PERCENT -gt 90 ]; then
    echo "$(date): Memory usage critical: ${USED_PERCENT}%" >> /var/log/memory_alert.log
    # 可触发 kill 或通知
fi
# 添加 crontab 每分钟检查
* * * * * /opt/monitor/memory_alert.sh

三、磁盘 I/O 优化配置

1. I/O 调度器选择

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

# SSD/NVMe → 推荐 none 或 mq-deadline
echo "none" > /sys/block/sda/queue/scheduler

# HDD → 推荐 deadline 或 bfq
echo "deadline" > /sys/block/sda/queue/scheduler

持久化配置(写入 /etc/default/grub 或 udev 规则):

# /etc/default/grub 中 GRUB_CMDLINE_LINUX 添加:
GRUB_CMDLINE_LINUX="elevator=deadline"

# 然后更新 grub
update-grub
reboot

2. MySQL InnoDB 磁盘 IO 优化

[mysqld]
# 双写缓冲与刷盘策略
innodb_flush_method = O_DIRECT          # 绕过 OS page cache,避免双重缓存
innodb_flush_log_at_trx_commit = 1      # 强持久性;若性能优先可设为 2

# IOPS 密集型场景
innodb_io_capacity = 2000               # SSD 可设 5000+
innodb_io_capacity_max = 4000

# 预读机制
innodb_read_io_threads = 8
innodb_write_io_threads = 8

# 数据文件路径分散到不同物理盘(如果有多块盘)
# datadir=/data/mysql/data
# innodb_log_group_home_dir=/data/mysql/logs

3. Redis 磁盘 IO 优化

# Redis 主要写操作是 AOF/RDB,减少 IO 频率
save ""                              # 如果配合 AOF 可禁用 RDB save
appendonly yes                       # 启用 AOF
appendfsync everysec                 # 每秒刷盘,平衡性能与安全
no-appendfsync-on-rewrite no         # 重写期间不阻塞 fsync

# 如果追求极致性能且可接受少量数据丢失:
# appendfsync always                # 每次写都刷盘(极慢)
# appendfsync no                    # 由 OS 决定(最快但风险高)

4. 多磁盘分离方案(最优解)

# 假设: /dev/sda (SSD, 系统+MySQL), /dev/sdb (HDD, 备份/日志)

# MySQL 数据目录放 SSD
mkdir -p /data/mysql
chown mysql:mysql /data/mysql
# my.cnf: datadir=/data/mysql

# MySQL binlog 放独立盘(如果有)
# log_bin=/data/binlog/mysql-bin

# Redis dump 文件放另一盘
# dbfilename dump.rdb
# dir /data/redis/dump

四、CPU 与进程隔离

1. cgroups CPU 隔离

# 安装 cgroup tools
apt-get install cgroup-tools    # Debian/Ubuntu
yum install libcgroup-tools     # CentOS

# 创建 MySQL CPU 控制组
cgcreate -g cpu,memory:/mysql
cgset -r cpu.cfs_quota_us=50000 mysql   # 限制 MySQL 最多用 50% CPU (2核机器)
cgset -r memory.limit_in_bytes=6G mysql # 限制 MySQL 最大内存 6G

# 创建 Redis CPU 控制组
cgcreate -g cpu,memory:/redis
cgset -r cpu.cfs_quota_us=50000 redis
cgset -r memory.limit_in_bytes=3G redis

# 启动服务时绑定 cgroup
cgexec -g cpu,memory:/mysql mysqld_safe
cgexec -g cpu,memory:/redis redis-server /etc/redis/redis.conf

2. NUMA 优化

# 查看 NUMA 拓扑
numactl --hardware

# MySQL 启动时绑定 NUMA 节点
numactl --cpunodebind=0 --membind=0 /usr/sbin/mysqld

# Redis 启动时绑定 NUMA 节点
numactl --interleave=all /usr/local/bin/redis-server /etc/redis/redis.conf

3. CPU 亲和性与线程绑定

# 查看 MySQL 线程 CPU 分布
top -H -p $(pgrep mysqld)

# 手动绑定关键线程(高级用法)
taskset -c 0,1 mysqld_safe      # 将 MySQL 绑定到 CPU 0,1
taskset -c 2,3 redis-server     # 将 Redis 绑定到 CPU 2,3

五、Linux 内核参数调优

1. /etc/sysctl.conf 核心参数

# ============================================
# 内存管理
# ============================================

# 降低 swappiness,避免 MySQL 页缓存被换出
vm.swappiness = 1

# 提高 inode 缓存效率
vm.vfs_cache_pressure = 50

# 透明大页(THP)对数据库有害,必须禁用
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

# 持久化 THP 禁用
cat > /etc/systemd/system/disable-thp.service << 'EOF'
[Unit]
Description=Disable Transparent Huge Pages
[Service]
ExecStart=/bin/sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled && echo never > /sys/kernel/mm/transparent_hugepage/defrag"
[Install]
WantedBy=multi-user.target
EOF
systemctl enable disable-thp.service

# ============================================
# 网络优化(Redis 高频短连接友好)
# ============================================

# TCP 快速回收
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30

# TCP 窗口缩放
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# ============================================
# I/O 队列深度
# ============================================

# 增加 blk-mq 队列深度(SSD 适用)
echo 128 > /sys/block/sda/queue/nr_requests
echo 256 > /sys/block/sdb/queue/nr_requests

# ============================================
# 文件描述符限制
# ============================================

# /etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535
root soft nofile 65535
root hard nofile 65535

# sysctl 也需调整
fs.file-max = 100000

2. 应用层 ulimit

# /etc/security/limits.d/20-nofile.conf
mysql soft nofile 65535
mysql hard nofile 65535
redis soft nofile 65535
redis hard nofile 65535

# MySQL my.cnf 中确认
[mysqld]
open_files_limit = 65535

六、文件系统优化

1. 挂载选项

# ext4 推荐挂载选项
defaults,noatime,nodiratime,discard

# xfs 推荐挂载选项
defaults,noatime,nodiratime,allocsize=64k

# /etc/fstab 示例
/dev/sda1  /data/mysql  ext4  defaults,noatime,nodiratime,discard  0 2
/dev/sdb1  /data/redis  ext4  defaults,noatime,nodiratime           0 2

noatime 避免每次读取文件都更新访问时间戳,显著减少不必要的磁盘写入。

2. 磁盘分区建议

推荐布局:
├── /              (系统盘, SSD)
├── /data/mysql    (MySQL data, binlog, 独立 SSD 分区)
├── /data/redis    (Redis dump, AOF, 独立 SSD 分区)
└── /backup        (备份, HDD 或远程存储)

七、监控与诊断工具

1. 实时监控脚本

#!/bin/bash
# /opt/monitor/mysql_redis_health.sh

echo "=== System Status ==="
uptime
free -h
df -h /data/mysql /data/redis

echo -e "n=== MySQL Status ==="
mysqladmin -u root -p${MYSQL_PASS} status 2>/dev/null || echo "MySQL not running"
mysql -u root -p${MYSQL_PASS} -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_%';" 2>/dev/null | head -5

echo -e "n=== Redis Status ==="
redis-cli info memory | grep -E "used_memory_human|maxmemory_human|mem_fragmentation_ratio"
redis-cli info stats | grep -E "instantaneous_ops_per_sec|rejected_connections"

echo -e "n=== Disk IO ==="
iostat -x 1 1 | grep -A 10 "^Device"

echo -e "n=== Load Average ==="
cat /proc/loadavg

2. 关键指标阈值

指标 MySQL 警戒线 Redis 警戒线
CPU 使用率 > 80% 持续 5min > 80% 持续 5min
内存使用率 > 85% > 90%
InnoDB Buffer Pool 命中率 < 99% N/A
Redis 内存碎片率 N/A > 1.5 需 MEMORY PURGE
磁盘 IO 等待时间 iowait > 20% iowait > 20%
QPS/OPS 突降 > 50% 下降 > 50% 下降
连接数 > max_connections * 0.8 > maxclients * 0.8

八、故障排查清单

## 当出现性能问题时按以下顺序排查:

1. **内存不足?**
   - `free -h` → 检查可用内存
   - `vmstat 1` → 观察 si/so (swap in/out)
   - 如果 swap 活跃 → 增大物理内存或缩小 MySQL buffer pool

2. **磁盘 IO 瓶颈?**
   - `iostat -x 1` → 看 %util, await, svctm
   - `%util > 80%` → 考虑加盘或优化查询
   - `await > 10ms` (SSD) / `> 50ms` (HDD) → 异常

3. **CPU 争抢?**
   - `top -H` → 看 MySQL 和 Redis 线程 CPU 分布
   - `mpstat -P ALL 1` → 看各核负载均衡性
   - 使用 cgroups 隔离

4. **锁竞争?**
   - MySQL: `SHOW ENGINE INNODB STATUSG` → 看行锁等待
   - Redis: `SLOWLOG GET 10` → 看慢命令

5. **网络问题?**
   - `ss -s` → 看 TCP 连接状态
   - `netstat -an | grep TIME_WAIT | wc -l` → TIME_WAIT 过多

九、终极建议:是否应该分离部署?

场景 建议
测试/开发环境 ✅ 可以共用,做好上述优化即可
中小生产环境(QPS < 5000) ⚠️ 可以共用,但需严格监控
大型生产环境(QPS > 10000) ❌ 强烈建议分离部署
对延迟敏感(< 1ms) ❌ 必须分离

根本原则:当 MySQL 和 Redis 在同一台服务器上时,任何一方的突发负载都会直接影响另一方。分离部署是最可靠的解决方案。如果因成本限制必须共用,请确保:

  1. 使用 cgroups 做资源隔离
  2. 设置合理的内存上限防止 OOM
  3. 启用实时监控系统
  4. 预留至少 30% 的资源余量
未经允许不得转载:云知识CLOUD » MySQL和Redis共用同一台Linux服务器时,磁盘IO和内存如何优化配置?