减少内存使用

Rails 应用程序代码存在内存泄漏。对于 Web 请求,使用 supervision thread 可以解决这个问题,如果在一定时间内超过给定的常驻集大小 (RSS) 阈值,它会自动重启 worker。我们将相同的方法应用于极狐GitLab 中处理后台作业的 Sidekiq 进程。

默认情况下,极狐GitLab 仅针对使用 Linux 软件包(Omnibus)或 Docker 的安装监控可用的 RSS 限制。原因是极狐GitLab 依赖 runit 在内存引起的关闭后重新启动 Sidekiq,而极狐GitLab 自编译或基于 Helm chart 的安装不使用 runit 或等效工具。

在默认设置下,Sidekiq 重启的频率不超过每 15 分钟一次,重启会导致传入后台作业延迟约一分钟。

一些后台作业依赖于长时间运行的外部进程。为确保在 Sidekiq 重新启动时完全终止这些进程,每个 Sidekiq 进程都应作为进程组 leader 运行(例如,使用 chpst -P)。如果使用 Omnibus 或安装了 runitbin/background_jobs 脚本,将为您处理。

配置限制

Sidekiq 内存限制是使用环境变量控制的。

  • SIDEKIQ_MEMORY_KILLER_MAX_RSS (KB):定义允许的 RSS 的 Sidekiq 进程软限制。如果 Sidekiq 进程 RSS(以千字节为单位)超过 SIDEKIQ_MEMORY_KILLER_MAX_RSS,且持续时间超过 SIDEKIQ_MEMORY_KILLER_GRACE_TIME,则触发优雅重启。如果 SIDEKIQ_MEMORY_KILLER_MAX_RSS 没有设置,或者它的值设置为 0,则不监控软限制。SIDEKIQ_MEMORY_KILLER_MAX_RSS 默认为 2000000

  • SIDEKIQ_MEMORY_KILLER_GRACE_TIME:定义允许 Sidekiq 进程在允许的 RSS 软限制之上运行的宽限时间(以秒为单位)。如果 Sidekiq 进程在 SIDEKIQ_MEMORY_KILLER_GRACE_TIME 内低于允许的 RSS(软限制),则重启将中止。默认值为 900 秒(15 分钟)。

  • SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS (KB):为允许的 RSS 定义 Sidekiq 进程硬限制。如果 Sidekiq 进程 RSS(以千字节表示)超过 SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS,将立即触发 Sidekiq 的优雅重启。如果此值未设置或设置为 0,则不会监视硬限制。

  • SIDEKIQ_MEMORY_KILLER_CHECK_INTERVAL:定义检查进程 RSS 的频率。 默认为 3 秒。

  • SIDEKIQ_MEMORY_KILLER_SHUTDOWN_WAIT:定义允许所有 Sidekiq 作业完成的最长时间。在此期间不接受新作业。 默认为 30 秒。

    如果进程重启不是Sidekiq执行的,Sidekiq 进程在 Sidekiq 关闭超时(默认 25 秒)的 2 秒后被强制终止。如果作业在此期间没有完成,所有当前正在运行的作业都会被发送到 Sidekiq 进程的 SIGTERM 信号中断。

  • GITLAB_MEMORY_WATCHDOG_ENABLED:默认启用。将 GITLAB_MEMORY_WATCHDOG_ENABLED 设置为 false,使用 15.9 之前使用的旧版 Daemon Sidekiq Memory Killer 实现。16.0 版本中将删除对设置 GITLAB_MEMORY_WATCHDOG_ENABLED 的支持。

监控 worker 重启

如果 worker 因内存使用率过高而重新启动,极狐GitLab 会发出日志事件。

以下是 /var/log/gitlab/gitlab-rails/sidekiq_client.log 中这些日志事件之一的示例:

{
  "severity": "WARN",
  "time": "2023-02-04T09:45:16.173Z",
  "correlation_id": null,
  "pid": 2725,
  "worker_id": "sidekiq_1",
  "memwd_handler_class": "Gitlab::Memory::Watchdog::SidekiqHandler",
  "memwd_sleep_time_s": 3,
  "memwd_rss_bytes": 1079683247,
  "memwd_max_rss_bytes": 629145600,
  "memwd_max_strikes": 5,
  "memwd_cur_strikes": 6,
  "message": "rss memory limit exceeded",
  "running_jobs": [
    {
      jid: "83efb701c59547ee42ff7068",
      worker_class: "Ci::DeleteObjectsWorker"
    },
    {
      jid: "c3a74503dc2637f8f9445dd3",
      worker_class: "Ci::ArchiveTraceWorker"
    }
  ]
}
  • memwd_rss_bytes 是实际消耗的内存量。
  • memwd_max_rss_bytes 是通过 per_worker_max_memory_mb 设置的 RSS 限制。
  • running jobs 列出了进程超过 RSS 限制并开始正常重启时正在运行的作业。