在 1 核 1G(1 vCPU, 1GB RAM)这种极度受限的服务器上,同时运行 MySQL 和 Redis 极易导致系统负载(Load Average)飙升甚至服务崩溃。这通常不是单一原因造成的,而是资源竞争、配置不当和操作系统调度机制共同作用的结果。
以下是导致高负载的常见原因及分析:
1. 内存不足导致的频繁 Swap(最常见原因)
这是 1G 内存服务器最致命的瓶颈。
- 现象:MySQL 默认配置通常会尝试占用较多内存(如
innodb_buffer_pool_size),Redis 也有自己的内存限制。当两者加起来超过物理内存时,Linux 内核会开始使用 Swap(交换分区)。 - 后果:Swap 读写速度比内存慢几个数量级。一旦触发 Swap,进程状态会变成
D(Uninterruptible sleep),CPU 虽然空闲但系统负载极高,响应极慢。 - 关键点:检查
free -h中的available是否接近 0,以及vmstat中si/so(swap in/out) 是否有数值。
2. CPU 单核上下文切换与线程争抢
- 单核瓶颈:只有 1 个核心意味着同一时间只能处理一个线程。MySQL 和 Redis 都是多进程/多线程模型。
- MySQL 启动后,主线程 + 多个工作线程(由
thread_cache_size或连接数决定)会抢占 CPU。 - Redis 虽然是单线程模型(命令执行),但在处理大 Key、持久化(RDB/AOF)或网络 I/O 阻塞时,会占用大量 CPU 周期。
- MySQL 启动后,主线程 + 多个工作线程(由
- 上下文切换:当两个应用都在活跃运行时,操作系统需要在它们之间频繁切换上下文。如果连接数较多,CPU 大部分时间花在“切换任务”而不是“执行任务”上,导致 Load 升高但实际计算效率极低。
3. 默认配置过于激进
很多用户直接使用了官方默认的配置文件,未针对小内存环境进行裁剪:
- MySQL:
innodb_buffer_pool_size默认可能是总内存的 50% 或更多(在旧版本中),在 1G 机器上这会瞬间吃光内存。max_connections默认值较高,每个连接都会消耗少量内存和线程资源。
- Redis:
- 如果没有设置
maxmemory,Redis 会尝试使用所有可用内存,可能与 MySQL 发生恶性竞争。 - 开启了
appendonly yes(AOF) 且同步策略为everysec或always,在写入压力大时会频繁触发磁盘 I/O 和 CPU 计算。
- 如果没有设置
4. 磁盘 I/O 瓶颈
- 机械硬盘 vs SSD:如果是机械硬盘,频繁的随机读写(尤其是 MySQL 的 InnoDB 日志和页文件,以及 Redis 的 AOF 重写)会导致 I/O Wait 飙升。
- 表现:
top命令中%wa(I/O wait) 很高。此时 CPU 实际上在等待磁盘数据,但系统负载依然显示很高。
5. 缺乏监控与自动重启循环
- 由于内存紧张,Linux OOM Killer(内存溢出杀手)可能会频繁杀死 MySQL 或 Redis 进程以保护系统。
- 如果配置了
systemd自动重启服务,会出现“启动 -> 耗尽内存 -> 被杀 -> 重启 -> 再耗尽”的死循环,导致系统持续处于高负载状态。
建议排查与优化方案
针对 1 核 1G 环境,必须对两个服务进行严格的“瘦身”配置:
1. 调整 MySQL 配置 (my.cnf)
[mysqld]
# 关键:将缓冲池限制在物理内存的 10%-20%,绝对不要超过 256M
innodb_buffer_pool_size = 128M
# 减少最大连接数,避免线程过多
max_connections = 20
# 禁用不必要的功能
skip-name-resolve = 1
performance_schema = OFF
# 关闭二进制日志(如果不需要主从复制,可暂时关闭以节省 IO)
log_bin = OFF
# 或者设置为低频率同步
sync_binlog = 0
innodb_flush_log_at_trx_commit = 2
# 确保有 Swap 空间,防止 OOM 直接杀进程(作为最后防线)
# 建议创建 1-2G 的 Swap 分区
2. 调整 Redis 配置 (redis.conf)
# 关键:严格限制最大内存,给 OS 和 MySQL 留足空间(例如留 400M 给系统/MySQL)
maxmemory = 500mb
# 设置淘汰策略,防止内存写满报错
maxmemory-policy allkeys-lru
# 关闭 RDB 快照(可选,如果数据量小且允许丢失)
save ""
# 如果开启 AOF,降低刷盘频率
appendfsync everysec
3. 系统级优化
- 增加 Swap:在 1G 内存下,强烈建议至少配置 1G-2G 的 Swap 分区,虽然速度慢,但能防止服务被直接杀掉。
# 示例:创建 1G swap 文件 dd if=/dev/zero of=/swapfile bs=1M count=1024 chmod 600 /swapfile mkswap /swapfile swapon /swapfile - 调整 CPU 亲和性(高级):如果可能,尝试将 Redis 绑定到某个核心(虽然只有一核),但这在单核上意义不大,主要靠减少并发。
- 监控工具:使用
htop查看具体是哪个进程占用了 CPU 或 Memory,使用iostat -x 1查看磁盘等待情况。
总结:在 1 核 1G 上同时跑这两个数据库属于“极限操作”。如果业务允许,最稳妥的方案是放弃其中一个(例如只用 Redis 做缓存,数据存在云数据库;或者只用 MySQL,用内存变量代替 Redis 缓存)。如果必须共存,必须严格执行上述的内存隔离配置。
云知道CLOUD