在仅2核4GB内存的服务器上同时运行 MySQL 和 Redis,资源竞争非常激烈(尤其内存和I/O),需谨慎权衡与精细化调优。以下是务实、可落地的优化方案,兼顾稳定性、性能和运维可持续性:
✅ 一、核心原则(先决条件)
- 绝不让两者内存总和超过 3.2GB(预留 0.8GB 给 OS + 系统进程)
- MySQL 优先保障(通常是业务主数据库),Redis 定位为缓存层,可降级/容忍部分失效
- 禁用 swap(或严格限制):避免内存不足时触发 swap 导致 MySQL/Redis 延迟飙升(
vm.swappiness=1或0) - 关闭非必要服务(如 Apache/Nginx 若非必需,改用轻量级 Caddy;禁用 auditd、bluetooth、GUI 等)
✅ 二、MySQL 资源精简调优(目标:≤2.2GB 内存占用)
✅ 修改
/etc/my.cnf(或/etc/mysql/mysql.conf.d/mysqld.cnf)
[mysqld]
# === 内存控制 ===
innodb_buffer_pool_size = 1.6G # ⚠️ 关键!占 MySQL 总内存 70%+,勿超 1.8G
innodb_log_file_size = 64M # 减小日志文件(默认 48M~256M),降低恢复时间和内存压力
innodb_flush_method = O_DIRECT # 避免双重缓冲(Linux 下推荐)
# === 连接与线程 ===
max_connections = 50 # 默认151,按实际并发调低(查 `SHOW STATUS LIKE 'Threads_connected';`)
wait_timeout = 60 # 空闲连接 60s 断开
interactive_timeout = 120
# === 查询优化 ===
query_cache_type = 0 # ❌ 彻底禁用(MySQL 8.0+ 已移除,5.7 建议关)
tmp_table_size = 32M
max_heap_table_size = 32M # 防止内存临时表暴增
sort_buffer_size = 256K # 每连接排序缓冲,勿设过大
read_buffer_size = 128K
read_rnd_buffer_size = 256K
# === 其他瘦身项 ===
skip_log_bin # ❌ 关闭 binlog(若无需主从/备份,否则保留但设 expire_logs_days=3)
innodb_file_per_table = ON
innodb_flush_log_at_trx_commit = 2 # 平衡安全性与性能(1=安全但慢,2=折中,0=最快但可能丢1s数据)
🔍 验证内存占用:
启动后执行:
SELECT
(SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'innodb_buffer_pool_size') / 1024/1024 AS ibp_mb,
(SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'key_buffer_size') / 1024/1024 AS key_mb;
-- 再结合 `ps aux --sort=-%mem | head -10` 观察 mysqld 实际 RSS 内存
💡 提示:使用
mysqltuner.pl(Perl脚本)自动分析并给出调优建议(官网)
✅ 三、Redis 资源严控(目标:≤800MB 内存 + 低CPU争抢)
✅ 修改
/etc/redis/redis.conf
# === 内存硬限 ===
maxmemory 768mb # ⚠️ 必须设置!超限触发淘汰策略
maxmemory-policy allkeys-lru # 或 volatile-lru(推荐后者,只淘汰带过期时间的key,更安全)
# maxmemory-samples 3 # 默认5,可保持
# === 持久化降载(关键!)===
save "" # ❌ 彻底禁用 RDB(避免 fork 大进程卡顿)
appendonly no # ❌ 禁用 AOF(除非强需求持久化)
# 若必须 AOF:appendonly yes + appendfsync everysec(不选 always)
# === CPU/连接控制 ===
tcp-keepalive 300 # 保活检测,及时释放死连接
timeout 300 # 闲置连接5分钟断开
maxclients 200 # 根据应用连接池调整(避免过多空闲连接耗内存)
# 限制后台任务(如 bgsave/bgaofrewrite)不抢占CPU:
# 当前无直接参数,但可通过 cgroups(见下文)或禁用持久化规避
# === 其他 ===
lazyfree-lazy-eviction yes # 淘汰大key时异步释放内存,防阻塞
lazyfree-lazy-expire yes
lazyfree-lazy-server-del yes
🔍 监控内存水位:
redis-cli info memory | grep -E "used_memory_human|maxmemory_human|mem_fragmentation_ratio"
# 理想值:mem_fragmentation_ratio < 1.5(过高说明内存碎片严重)
💡 Redis 内存估算公式:
key数 × (平均key长度 + 平均value长度 + 16~24字节元数据)
用redis-cli --bigkeys扫描大key,MEMORY USAGE key查单个key内存。
✅ 四、系统级协同优化(防资源互搏)
| 项目 | 推荐配置 | 说明 |
|---|---|---|
| CPU 绑核隔离 | taskset -c 0 mysqld & taskset -c 1 redis-server |
将 MySQL 绑定到 CPU0,Redis 到 CPU1,避免上下文切换抖动(需在 service 启动脚本中设置) |
| I/O 调度器 | echo deadline > /sys/block/*/queue/scheduler(SSD)或 none(NVMe) |
避免 CFQ 等复杂调度器开销 |
| OOM 优先级 | echo -1000 > /proc/$(pgrep mysqld)/oom_score_adjecho -500 > /proc/$(pgrep redis-server)/oom_score_adj |
保证 MySQL 最后被 OOM Killer 杀掉 |
| cgroups 限频(进阶) | 用 systemd 为服务设 CPUQuota=80% |
防止单一服务吃满 CPU(例:CPUQuota=80% 在 /etc/systemd/system/mysqld.service.d/override.conf) |
✅ 五、必须做的监控与告警(防雪崩)
- ✅ 内存:
free -h+cat /proc/meminfo | grep -E "MemAvailable|SwapFree" - ✅ MySQL:
SHOW GLOBAL STATUS LIKE 'Threads_connected'、Innodb_buffer_pool_wait_free(>0 表示 buffer pool 不足) - ✅ Redis:
INFO memory中mem_used接近maxmemory时立即告警 - ✅ 磁盘IO:
iostat -x 1关注%util > 90或await > 50ms - ✅ 工具推荐:
htop(实时)、mytop(MySQL)、redis-cli monitor(抽样)、Prometheus + Grafana(长期)
⚠️ 六、强烈建议的架构演进路径(短期妥协,长期必做)
| 阶段 | 方案 | 理由 |
|---|---|---|
| 立即行动 | 将 Redis 作为「只读缓存」,所有写操作绕过 Redis 直写 MySQL | 避免双写一致性难题和缓存穿透风险 |
| 1个月内 | 使用 redis-cli --bigkeys 清理大Key,用 SCAN 替代 KEYS * |
防止 Redis 单命令阻塞 |
| 3个月内 | 将 Redis 迁移至独立 1C2G 轻量云实例(如腾讯云轻量应用服务器) | 成本≈¥30/月,彻底解耦,性价比极高 |
| 6个月内 | MySQL 开启 performance_schema + 慢查询日志(long_query_time=1),用 pt-query-digest 分析瓶颈 |
从根源减少慢SQL对内存/CPU的消耗 |
📌 总结:关键数字清单(抄作业版)
| 组件 | 推荐上限 | 检查命令 |
|---|---|---|
| 总内存占用 | ≤ 3.2 GB | free -h |
| MySQL Buffer Pool | 1.6 GB | mysql -e "SELECT @@innodb_buffer_pool_size/1024/1024;" |
| Redis maxmemory | 768 MB | redis-cli config get maxmemory |
| MySQL max_connections | ≤ 50 | mysql -e "SHOW VARIABLES LIKE 'max_connections';" |
| Redis maxclients | ≤ 200 | redis-cli config get maxclients |
| Swap 使用率 | 0%(或 <5%) |
swapon --show + free -h |
✅ 最后叮嘱:
- 不要迷信“优化参数”能解决一切——2核4G 是生产环境的底线,业务增长后必须拆分;
- 每次调参后压测:用
sysbench(MySQL)和redis-benchmark验证稳定性;- 备份永远第一:即使资源紧张,也要确保
mysqldump或mydumper定时成功(用ionice -c3降低IO影响)。
如果需要,我可以为你生成:
- ✅ 完整的
my.cnf和redis.conf生产就绪模板 - ✅ systemd 服务文件(含 CPU 绑核 + OOM 调整)
- ✅ 自动化巡检 Shell 脚本(内存/连接/慢查询一键检查)
欢迎随时提出 👇
CLOUD云枢