速卖通素材
奋斗

小型项目用1核1G服务器部署MySQL和Redis,如何优化避免性能瓶颈?

服务器

在 1 核 1G(1 vCPU, 1GB RAM)的服务器上同时部署 MySQL 和 Redis,属于典型的“资源极度受限”场景。MySQL 默认配置通常远超此限制,而 Redis 虽然轻量,但两者争抢内存和 CPU 极易导致 OOM(内存溢出)或高延迟。

以下是针对该环境的核心优化策略,按优先级排序:

1. 内存分配与隔离(最关键)

1GB 内存非常宝贵,必须严格划分。

  • Redis 内存限制
    • Redis 是单线程处理命令的,但内存占用大。建议将 maxmemory 设置为 256MB – 300MB
    • 保留至少 200-300MB 给操作系统缓存和其他进程。
    • 设置淘汰策略:maxmemory-policy allkeys-lru(所有键空间下最近最少使用),防止内存爆满。
    • 开启压缩:如果存储的是字符串类型,Redis 会自动压缩,无需额外配置。
  • MySQL 内存限制
    • MySQL 的 InnoDB Buffer Pool 是最大开销来源。
    • 修改 my.cnf (或 mysql.cnf):
      [mysqld]
      # 总内存 1G,减去 OS 预留 300M,减去 Redis 预留 300M,留给 MySQL 约 400M
      innodb_buffer_pool_size = 256M
      # 关键:关闭不必要的内存消耗组件
      table_open_cache = 200
      thread_cache_size = 8
      sort_buffer_size = 2M
      read_rnd_buffer_size = 2M
      join_buffer_size = 2M
      # 禁用不常用的日志以节省 IO 和内存(视业务需求而定)
      # sync_binlog = 0  (若数据安全性要求不高,可牺牲少量一致性换取性能)
    • 注意:不要开启 query_cache,它在现代 MySQL 版本中不仅无效且消耗内存。

2. 存储引擎与表结构优化

  • 强制使用 InnoDB:确保所有表都使用 InnoDB 引擎,避免 MyISAM(MyISAM 在并发下锁表更严重,且缓冲池管理不如 InnoDB 灵活)。
  • 精简索引
    • 1 核 CPU 无法承受过多的索引维护开销。
    • 只为核心查询字段建立索引,删除冗余索引。
    • 避免在大字段(如 TEXT/BLOB)上建立索引。
  • 小表设计:尽量将大表拆分,或者对于非核心数据使用简单的扁平化存储(如 JSON 字段),减少 Join 操作(Join 极其消耗 CPU)。

3. 应用层架构调整(规避瓶颈的核心)

在硬件受限的情况下,软件架构优化比硬件调优更有效

  • 读写分离/缓存优先
    • 利用 Redis 缓存热点数据(如用户信息、配置项、Session),让 MySQL 只负责写操作和复杂统计。
    • 设置合理的 TTL(过期时间),减少数据库读取压力。
  • 批量操作
    • 应用层尽量将多次 SQL 合并为一次执行(Batch Insert/Update),减少网络往返和上下文切换。
  • 异步处理
    • 对于非实时任务(如发送通知、生成报表),通过消息队列(甚至可以用 Redis List 模拟简易队列)异步处理,避免阻塞主线程。

4. 操作系统与内核参数调优

Linux 内核参数对 I/O 和连接数有巨大影响。

  • 增加 Swap(虚拟内存)
    • 虽然 Swap 会降低速度,但在 1G 内存下,没有 Swap 会导致服务直接崩溃(OOM Killer)
    • 建议创建 1GB – 2GB 的 Swap 分区或文件。
    • 调整 vm.swappiness:建议设为 10,让系统优先使用物理内存,只有实在不够时才用 Swap。
    • 命令示例:echo "vm.swappiness=10" >> /etc/sysctl.conf && sysctl -p
  • 文件描述符限制
    • MySQL 和 Redis 在高并发下需要大量文件句柄。
    • 修改 /etc/security/limits.conf
      * soft nofile 65535
      * hard nofile 65535
      root soft nofile 65535
      root hard nofile 65535
  • I/O 调度器
    • 如果是 SSD,建议使用 deadlinenone 调度器;如果是机械硬盘,使用 cfq
    • 检查当前调度器:cat /sys/block/sda/queue/scheduler

5. 监控与运维策略

  • 开启慢查询日志
    • 在 MySQL 中开启 slow_query_log,阈值设为 1s 或 2s,定期分析并优化最慢的 SQL。
  • 监控工具
    • 安装轻量级监控(如 Prometheus Node Exporter + Grafana,或者简单的 htop + watch)。
    • 重点监控指标:MemAvailable(可用内存)、SwapUsedInnoDB Page Read RateRedis Hit Rate
  • 定时清理
    • 定期清理 MySQL 的慢查询日志、错误日志,防止磁盘占满。
    • 定期备份数据到外部存储(如对象存储 S3),释放本地空间。

总结配置清单参考

Redis (redis.conf)

maxmemory 256mb
maxmemory-policy allkeys-lru
timeout 300
tcp-keepalive 300
save ""  # 如果数据允许丢失,关闭持久化可极大提升性能(生产环境慎用)
# 或者保留 AOF,但设置为每秒同步
appendonly yes
appendfsync everysec

MySQL (my.cnf)

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
port=3306
user=mysql

# 核心内存控制
innodb_buffer_pool_size = 256M
innodb_log_file_size = 64M
innodb_flush_log_at_trx_commit = 2  # 牺牲一点点数据安全性换取写入性能

# 连接与缓存
table_open_cache = 200
thread_cache_size = 8
sort_buffer_size = 2M
read_rnd_buffer_size = 2M
join_buffer_size = 2M

# 其他
skip-name-resolve  # 禁止 DNS 解析,加快连接速度
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

最终建议

如果经过上述优化后,业务高峰期依然频繁出现超时或卡顿,说明 1 核 1G 确实无法满足当前的业务负载量。此时最经济的方案是:

  1. 升级配置:将服务器升级到 2 核 2G(成本增加很少,性能提升显著)。
  2. 云数据库:将 MySQL 迁移到云厂商的 RDS(按量付费),本地仅保留 Redis 和应用代码。
  3. 容器化隔离:使用 Docker Compose 或 K8s 限制资源配额,防止一个服务把另一个吃光。
未经允许不得转载:轻量云Cloud » 小型项目用1核1G服务器部署MySQL和Redis,如何优化避免性能瓶颈?