1核1G服务器上MySQL和Redis启动后系统负载很高,常见原因有哪些?

在 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 周期。
  • 上下文切换:当两个应用都在活跃运行时,操作系统需要在它们之间频繁切换上下文。如果连接数较多,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 » 1核1G服务器上MySQL和Redis启动后系统负载很高,常见原因有哪些?