在单台云服务器上同时部署 MySQL 和 Redis(即“共存部署”)虽常见于开发、测试或轻量级生产场景(如中小流量 Web 应用、内部工具),但需谨慎权衡资源竞争与稳定性风险。这不是高可用/高性能生产环境的推荐架构,但若必须共存,以下是经过验证的最佳实践:
✅ 一、核心原则(先决条件)
- 明确适用场景:仅限于 QPS < 500、并发连接 < 200、数据量 < 50GB 的轻量级业务(如博客、后台管理系统、小型 SaaS 试用环境)。
- 绝不用于关键生产系统:MySQL(持久化+事务)与 Redis(内存+高吞吐)资源模型冲突显著,共存易引发雪崩(如 Redis 内存耗尽触发 OOM Killer 杀死 MySQL)。
- 必须监控告警先行:无监控=裸奔,部署前确保已配置基础指标采集与阈值告警。
✅ 二、资源隔离与分配(最关键!)
| 资源类型 | MySQL 建议分配 | Redis 建议分配 | 说明 |
|---|---|---|---|
| CPU | 绑定 2~4 核(numactl --cpunodebind=0 --membind=0 mysqld) |
绑定剩余 1~2 核(taskset -c 4-5 redis-server) |
避免 CPU 抢占;Redis 单线程,无需多核,但需独占避免调度延迟 |
| 内存 | innodb_buffer_pool_size = 总内存 × 50%~60%(例:16GB → 8~10GB) |
maxmemory = 总内存 × 20%~30%(例:16GB → 3~4GB),必须设置 maxmemory-policy(推荐 allkeys-lru) |
⚠️ 禁止 Redis 使用 swap!echo 'vm.swappiness = 1' >> /etc/sysctl.conf && sysctl -p;MySQL 的 buffer pool 是性能生命线 |
| 磁盘 I/O | MySQL 数据目录挂载 独立 SSD 分区(如 /data/mysql),启用 innodb_flush_method=O_DIRECT |
Redis 持久化(RDB/AOF)目录挂载 同一 SSD 但不同分区(如 /data/redis),禁用 AOF 或设为 appendfsync everysec |
避免 I/O 争抢;禁止将 Redis RDB/AOF 与 MySQL 放在同一慢速磁盘(如系统盘) |
| 网络端口 | MySQL: 3306(建议改非标端口如 3307 并限制 bind-address=127.0.0.1) | Redis:6379(同理改6380,bind 127.0.0.1`) |
防止外部直接访问,减少攻击面 |
🔍 验证命令:
# 查看内存实际占用(排除缓存干扰) free -h && cat /proc/meminfo | grep -E "MemAvailable|Buffers|Cached" # 检查 Redis 是否使用 swap redis-cli info memory | grep mem_allocator # 应为 jemalloc
✅ 三、配置优化(针对性调优)
▶ MySQL 关键配置(my.cnf)
[mysqld]
# 内存安全边界(防止OOM)
innodb_buffer_pool_size = 8G # 严格 ≤ 可用内存 × 0.6
innodb_log_file_size = 256M # 日志大小适中,避免频繁刷盘
innodb_flush_method = O_DIRECT # 绕过 OS 缓存,减少双写开销
max_connections = 200 # 严控连接数,避免内存爆炸
wait_timeout = 60 # 快速回收空闲连接
skip_name_resolve = ON # 禁用 DNS 解析,提速连接
▶ Redis 关键配置(redis.conf)
# 内存与持久化
maxmemory 3gb
maxmemory-policy allkeys-lru
save 900 1 # 降低 RDB 触发频率(默认 900s/1次 → 可放宽至 3600s)
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes # RDB 失败时拒绝写入,避免数据丢失
rdbcompression yes
rdbchecksum yes
# 禁用 AOF(除非强一致性要求)或设为 everysec
appendonly no # 或 appendonly yes + appendfsync everysec
# 安全与资源
bind 127.0.0.1
protected-mode yes
tcp-keepalive 300
# 内存优化(重要!)
activerehashing yes
lazyfree-lazy-eviction yes
lazyfree-lazy-expire yes
💡 为什么禁用 AOF?
AOF 重写(BGREWRITEAOF)会 fork 进程,与 MySQL 的InnoDB后台线程竞争内存和 CPU,极易触发 OOM。RDB 更轻量,且配合maxmemory-policy已满足多数缓存场景。
✅ 四、进程与系统级防护
| 措施 | 命令/配置 | 目的 |
|---|---|---|
| OOM 优先级控制 | echo -1000 > /proc/$(pgrep mysqld)/oom_score_adjecho -800 > /proc/$(pgrep redis-server)/oom_score_adj |
降低 MySQL 被 OOM Killer 杀死的概率(数值越小越不易被杀) |
| CPU 亲和性绑定 | systemd 服务文件中添加:CPUAffinity=0-3(MySQL)CPUAffinity=4-5(Redis) |
避免跨 NUMA 节点访问内存,提升性能稳定性 |
| I/O 调度器优化 | echo deadline > /sys/block/vda/queue/scheduler(SSD) |
SSD 场景下 deadline 比 cfq 更低延迟 |
| 禁用 Transparent Huge Pages (THP) | echo never > /sys/kernel/mm/transparent_hugepage/enabled |
THP 导致 Redis 内存分配延迟飙升,MySQL 也会受影响 |
✅ 五、监控与告警(必须落地)
| 指标 | 告警阈值 | 工具建议 |
|---|---|---|
| 内存使用率 | > 85%(总内存) | node_exporter + Prometheus + Alertmanager |
| Redis 内存使用率 | > 90% of maxmemory |
redis_exporter |
| MySQL 连接数 | > 90% of max_connections |
mysqld_exporter |
| 磁盘 I/O Wait | > 20%(iowait) |
node_exporter |
| Redis 拒绝连接数 | rejected_connections > 0 |
redis-cli info stats |
| MySQL Slow Queries | > 5/sec | 开启 slow log + pt-query-digest 分析 |
🚨 立即响应项:
- Redis
evicted_keys > 0→ 立即扩容或优化缓存策略- MySQL
Threads_created > 10/sec→ 检查连接池配置(应用层未复用连接)
✅ 六、替代方案建议(强烈推荐演进路径)
| 场景 | 推荐方案 | 优势 |
|---|---|---|
| 开发/测试环境 | Docker Compose 隔离 + --memory=4g --cpus=2 限制 |
快速启停,资源硬隔离 |
| 轻量生产(预算有限) | 云厂商托管服务(如阿里云 RDS MySQL + 云数据库 Redis) | 免运维、自动备份、故障转移、按量付费 |
| 中高流量生产 | 物理分离:MySQL 独占 1 台(8C16G+SSD),Redis 独占 1 台(4C8G+大内存) | 彻底消除资源争抢,支持横向扩展 |
| 成本敏感但需弹性 | Kubernetes + StatefulSet:MySQL 主从 + Redis Cluster | 利用 K8s 资源配额(resources.limits)和拓扑感知调度 |
❌ 绝对禁止的操作(血泪教训)
- ❌ 不设置
maxmemory→ Redis 吃光内存导致 MySQL 被 OOM Kill - ❌ 将 MySQL 和 Redis 数据目录放在系统盘(
/)→ 磁盘满导致系统崩溃 - ❌ 开启 Redis AOF +
always同步 → I/O 瓶颈拖垮 MySQL - ❌ 使用
swap交换分区 → Redis 内存页换入换出造成毫秒级延迟突增 - ❌ 不限制 MySQL
max_connections→ 小程序连接泄漏即可压垮服务器
✅ 总结:一张检查清单
| 项目 | 是否完成 | 备注 |
|---|---|---|
| ☐ 内存严格分配(MySQL 60% + Redis 30% + 系统 10%) | free -h 验证可用内存 |
|
☐ CPU 亲和性绑定(taskset / systemd CPUAffinity) |
top -H -p $(pgrep redis) 查看线程 CPU |
|
☐ Redis maxmemory + allkeys-lru 已配置 |
redis-cli config get maxmemory |
|
☐ MySQL innodb_buffer_pool_size ≤ 可用内存×0.6 |
mysql -e "show variables like 'innodb_buffer_pool_size'" |
|
| ☐ 禁用 THP & swappiness=1 | cat /sys/kernel/mm/transparent_hugepage/enabled |
|
☐ 所有服务 bind 127.0.0.1,关闭公网访问 |
ss -tlnp | grep -E "(3306|6379)" |
|
| ☐ 部署 Prometheus + Grafana 基础监控 | 至少包含内存、CPU、连接数、Redis evictions |
最后忠告:共存部署是技术债务。上线后第一件事——规划迁移至分离架构。每多运行一天,故障风险指数级增长。
如需,我可提供:
🔹 完整的 systemd 服务配置模板(含资源限制)
🔹 Docker Compose 示例(带内存/CPU 限制)
🔹 Prometheus 告警规则 YAML
欢迎随时提出具体需求!
云知识CLOUD