在单台云服务器上同时部署 MySQL 和 Redis(即“共存部署”)虽常见于开发、测试或轻量级生产场景(如小型网站、内部工具、POC),但需谨慎权衡性能、稳定性与可维护性。以下是经过验证的最佳实践指南,兼顾安全性、资源隔离、稳定性和可观测性:
✅ 一、前提判断:是否真的需要共存?
| 场景 | 推荐做法 |
|---|---|
| 开发/测试/CI环境 | ✅ 合理,节省成本,便于本地复现 |
| 日均 PV < 1万、QPS < 50 的轻量生产应用(如企业官网、后台管理系统) | ⚠️ 可接受,但必须严格遵循下述实践 |
| 高并发、核心交易系统、数据强一致性要求场景 | ❌ 强烈不推荐 —— 应分离部署(至少 MySQL 单独,Redis 可选集群) |
🔔 关键提醒:MySQL 和 Redis 对内存、I/O、CPU 的争用高度敏感,共存易引发“雪崩式干扰”(如 Redis 内存满触发 OOM Killer 杀死 MySQL 进程)。
✅ 二、核心最佳实践(按优先级排序)
1. 资源硬隔离:CPU + 内存 + I/O
-
CPU 绑核(推荐)
# 为 MySQL 分配 CPU 0-1,Redis 分配 CPU 2-3(4核机器) systemctl edit mysqld # 添加: [Service] CPUAffinity=0 1 CPUSchedulingPolicy=fifo systemctl edit redis-server # 添加: [Service] CPUAffinity=2 3 CPUSchedulingPolicy=fifo -
内存限制(强制!)
- ✅ MySQL:
innodb_buffer_pool_size≤ 总内存 × 50%(建议 40–55%,留足 OS+Redis 缓存)
例:16GB 内存 →innodb_buffer_pool_size = 6G - ✅ Redis:
maxmemory必须显式设置(不可为no或0),并启用maxmemory-policy allkeys-lru
例:16GB 内存 →maxmemory 3gb(预留充足内存给 OS/MySQL/文件缓存) - ✅ OS 层限制(推荐 systemd):
# /etc/systemd/system/mysqld.service.d/limits.conf [Service] MemoryLimit=8G CPUQuota=70%
/etc/systemd/system/redis-server.service.d/limits.conf
[Service]
MemoryLimit=4G
CPUQuota=30% - ✅ MySQL:
2. 存储与 I/O 隔离
- 磁盘分离(关键!)
- MySQL 数据目录(
/var/lib/mysql)→ 专用 SSD 磁盘(或独立挂载点) - Redis 持久化(RDB/AOF)→ 另一块 SSD 或
/tmpfs(若禁用持久化) - ❌ 禁止共用同一块机械盘或根分区(避免 I/O 争抢导致 MySQL 响应延迟飙升)
- MySQL 数据目录(
- I/O 调度优化:
# MySQL 数据盘(SSD)使用 none/noop 调度器 echo 'none' > /sys/block/nvme0n1/queue/scheduler # Redis 持久化盘同理
3. 网络与端口安全
-
绑定指定网卡/IP(避免暴露内网):
# my.cnf bind-address = 127.0.0.1 # 或内网IP(如 192.168.1.10) skip-networking = OFF # 若需远程访问,配合防火墙 # redis.conf bind 127.0.0.1 # 禁用 0.0.0.0! protected-mode yes # 强制开启 requirepass your_strong_password # 必设密码(Redis 6+ 支持 ACL) - 防火墙白名单:
ufw allow from 192.168.1.0/24 to any port 3306 # 仅允许内网应用访问 MySQL ufw allow from 192.168.1.0/24 to any port 6379 # Redis 同理
4. 配置调优要点
| 组件 | 关键参数 | 推荐值(16GB内存示例) | 说明 |
|---|---|---|---|
| MySQL | innodb_buffer_pool_size |
6G |
最大内存占用项,勿超 55% |
innodb_log_file_size |
512M |
提升写性能,但需停机调整 | |
max_connections |
200 |
避免连接数爆炸耗尽内存 | |
| Redis | maxmemory |
3gb |
必须设! |
maxmemory-policy |
allkeys-lru |
避免 OOM Kill | |
tcp-keepalive |
300 |
防止连接假死 | |
save "" |
(禁用 RDB) | 若无需持久化,彻底关闭 RDB;否则 save 900 1 |
|
appendonly |
no |
生产环境慎用 AOF(I/O 压力大) |
5. 监控与告警(不可省略)
- 必监指标:
- ✅ 内存使用率(
free -h,systemd-cgtop) - ✅ MySQL
Threads_connected,Innodb_buffer_pool_wait_free,Slow_queries - ✅ Redis
used_memory,evicted_keys,rejected_connections,latency
- ✅ 内存使用率(
- 推荐工具:
- Prometheus + Grafana(采集
mysqld_exporter+redis_exporter) - 日志集中:Filebeat → ELK 或 Loki
- 告警阈值示例:
- Redis
used_memory > 90% of maxmemory→ 立即告警 - MySQL
Threads_connected > 90% of max_connections→ 告警
- Prometheus + Grafana(采集
6. 备份与故障恢复
- MySQL 备份:
- 使用
mysqldump --single-transaction(InnoDB)或mydumper(并发快) - 避开 Redis RDB/AOF fork 时间段(fork 会复制进程页表,加剧内存压力)
- 使用
- Redis 备份:
- 若启用 RDB:
bgsave手动触发后同步.rdb文件(注意磁盘空间) - 禁止在业务高峰执行
bgsave或bgrewriteaof
- 若启用 RDB:
- 一键切换脚本(应急):
# stop-redis-if-mysql-stressed.sh if [[ $(mysql -Nse "SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='THREADS_CONNECTED'") -gt 180 ]]; then systemctl stop redis-server fi
⚠️ 三、绝对禁止事项(血泪教训)
| 行为 | 风险 | 替代方案 |
|---|---|---|
❌ 不设 maxmemory |
Redis 内存无限增长 → 触发 Linux OOM Killer 杀死 MySQL | ✅ 强制配置 maxmemory + maxmemory-policy |
❌ MySQL 和 Redis 共用 / 分区且无磁盘配额 |
一个服务日志/持久化撑爆磁盘 → 全服务宕机 | ✅ 独立挂载点 + df -h 监控 + logrotate |
❌ Redis 开放 0.0.0.0:6379 且无密码 |
10分钟内被X_X木马劫持 | ✅ bind 127.0.0.1 + 密码 + 防火墙 |
| ❌ 在同一台机器跑 MySQL 主从 + Redis | I/O 和内存双重压垮 | ✅ 至少将从库/Redis 拆到其他节点 |
📈 四、扩展建议(当业务增长时)
- 第一阶段(QPS 100+):MySQL 拆出,Redis 留在应用服务器(减少网络跳转)
- 第二阶段(QPS 500+):Redis 升级为哨兵或 Cluster,MySQL 主从分离
- 终极方案:容器化(Docker + cgroups 限频)+ Service Mesh(如 Istio)实现细粒度治理
✅ 总结:一句话原则
“宁可浪费 30% 资源,绝不让两个服务在内存、I/O、CPU 上相互踩踏。”
—— 所有配置的核心目标:用确定性的资源边界,换取不确定的业务稳定性。
如需,我可为你生成:
- 完整的
my.cnf+redis.conf安全模板(适配 4C8G/8C16G) - Prometheus 告警规则 YAML
- 自动化部署 Ansible Playbook
欢迎随时提出 👇
云服务器