在 2 核 4G 内存的服务器上同时运行 MySQL 和 Redis,资源竞争非常激烈。核心策略是严格限制两者的最大内存占用,并根据业务负载动态调整参数。以下是具体优化方案:
一、内存分配原则(总内存 4GB)
| 组件 | 建议最大内存 | 说明 |
|---|---|---|
| MySQL | 1.5~2 GB | 预留操作系统 + 其他进程缓冲 |
| Redis | 1.0~1.5 GB | 避免 OOM 导致服务崩溃 |
| OS/其他 | ≥0.5 GB | 系统缓存、日志、监控等 |
⚠️ 关键:必须通过配置显式限制上限,否则默认行为可能导致 OOM Kill。
二、MySQL 优化配置(my.cnf)
[mysqld]
# 连接数控制(2 核 CPU 建议低并发)
max_connections = 50
# 内存核心参数(总和需 < 1.8GB)
innodb_buffer_pool_size = 1.2G # InnoDB 缓存(占物理内存 60%)
key_buffer_size = 64M # MyISAM 索引(若不用可设为 0)
sort_buffer_size = 2M # 排序缓冲区(每个连接独立)
read_buffer_size = 2M # 读缓冲区
read_rnd_buffer_size = 2M # 随机读缓冲区
tmp_table_size = 32M # 临时表内存上限
max_heap_table_size = 32M # 同上
# 其他关键设置
thread_cache_size = 8 # 线程缓存
query_cache_type = 0 # 禁用查询缓存(高并发下反而降速)
log_bin = /var/log/mysql/mysql-bin.log
slow_query_log = 1
long_query_time = 2
注意事项:
innodb_buffer_pool_size是核心,优先保障它。- 所有
_buffer_size参数都是每个连接独占,需结合max_connections计算总风险:
总缓冲内存 ≈ (sort+read+read_rnd) × max_connections→ 本例中约(2+2+2)×50=300MB,安全。 - 若使用 MyISAM 引擎,
key_buffer_size可适当调大,但现代应用多推荐 InnoDB。
三、Redis 优化配置(redis.conf)
# 内存限制(硬上限)
maxmemory 1.2gb
maxmemory-policy allkeys-lru # 或 volatile-lru(根据数据过期策略选择)
# 持久化策略(减少 I/O 压力)
appendonly yes # AOF 开启(RDB 可能阻塞主线程)
appendfsync everysec # 每秒刷盘(平衡性能与安全)
no-appendfsync-on-rewrite no # 重写时不阻塞
# 网络与连接
bind 0.0.0.0
protected-mode yes
tcp-backlog 511
timeout 0
tcp-keepalive 300
# 禁用不必要的功能
save "" # 关闭 RDB 快照(AOF 已足够)
rdbcompression yes
rdbchecksum yes
关键点:
maxmemory必须严格小于物理内存剩余值(建议 1.2GB)。- 采用
allkeys-lru策略自动淘汰旧数据,防止内存溢出。 - 关闭 RDB 避免
fork()子进程导致的瞬时内存峰值。
四、操作系统级优化
1. 交换空间(Swap)谨慎使用
# 查看当前 swap
free -h
# 若需创建(仅作为最后防线,频繁 swap 会拖垮性能)
dd if=/dev/zero of=/swapfile bs=1G count=1
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
# 调整 swappiness(降低 swap 倾向)
echo "vm.swappiness=10" >> /etc/sysctl.conf
sysctl -p
💡 建议:生产环境尽量不设 swap,依赖内存管理更可靠;测试环境可设小 swap(如 1GB)。
2. Cgroup 资源隔离(高级方案)
# 创建 cgroup 限制 MySQL 和 Redis 内存
mkdir /cgroup/memory/mysql
mkdir /cgroup/memory/redis
echo "mysql" > /cgroup/memory/mysql/cgroup.procs
echo "1.8G" > /cgroup/memory/mysql/memory.limit_in_bytes
echo "redis" > /cgroup/memory/redis/cgroup.procs
echo "1.2G" > /cgroup/memory/redis/memory.limit_in_bytes
适用场景:需要强制隔离,防止一方耗尽内存影响另一方。
3. 内核参数调优
# 增加文件描述符限制
echo "fs.file-max = 65535" >> /etc/sysctl.conf
echo "* soft nofile 65535" >> /etc/security/limits.conf
echo "* hard nofile 65535" >> /etc/security/limits.conf
# 优化 TCP 参数
net.core.somaxconn = 1024
net.ipv4.tcp_max_syn_backlog = 2048
五、监控与应急措施
-
实时监控工具:
# 安装 htop + redis-cli + mysqltuner apt install htop redis-tools mysqltuner-perl htop # 观察整体内存/CPU redis-cli info memory # 检查 Redis 内存使用率 mysqltuner # 分析 MySQL 配置合理性 -
告警阈值:
- 内存使用率 > 85% → 触发告警
- Swap 使用 > 10% → 立即介入
- Redis
used_memory_human接近maxmemory→ 扩容或清理
-
应急预案:
- 准备一键重启脚本(按优先级:先停 Redis → 再停 MySQL)
- 定期备份数据到外部存储,避免本地磁盘写满
六、替代方案建议
如果业务负载持续较高,考虑以下升级路径:
- 分离部署:将 Redis 迁移到独立小服务器(1 核 2G),释放 MySQL 资源。
- 云数据库:使用云厂商的 RDS + 云缓存服务(自动弹性伸缩)。
- 容器化隔离:用 Docker/K8s 为 MySQL 和 Redis 分配固定资源配额。
✅ 最终验证:压测后观察
dmesg | grep -i oom是否出现 OOM Killer 日志,若有则需进一步收紧配置。
通过以上组合策略,可在 2 核 4G 环境下稳定支撑中小型业务的混合负载场景。
云服务器