配置 GitLab 包内捆绑的 Puma 实例

Puma 是一个用于 Ruby 应用程序的快速、多线程和高度并发的 HTTP 1.1 服务器。它运行提供极狐GitLab 面向用户的功能的核心 Rails 应用程序。

减少内存使用

为了减少内存使用,Puma 派生 worker 进程。每次创建 worker 时,它都会与主进程共享内存。Worker 仅在更改或添加到其内存页面时才使用额外的内存。随着 worker 处理额外的网络请求,这可能会导致 Puma worker 随着时间的推移使用更多的物理内存。随着时间的推移使用的内存量取决于极狐GitLab 的使用情况。极狐GitLab 用户使用的功能越多,随着时间的推移,预期的内存使用量就越高。

为了阻止不受控制的内存增长,Rails 应用程序运行一个 supervision 线程,如果他们在一定时间内超过给定的驻留集大小 (RSS) 阈值,该线程会自动重启 worker。

极狐GitLab 为内存限制设置了默认值 1200Mb。要覆盖默认值,请将 per_worker_max_memory_mb 设置为新的 RSS 限制(以兆字节为单位):

  1. 编辑 /etc/gitlab/gitlab.rb

    puma['per_worker_max_memory_mb'] = 1024 # 1GB
    
  2. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

当 worker 重新启动时,运行极狐GitLab 的能力会在短时间内降低。如果 worker 更换得太频繁,请将 per_worker_max_memory_mb 设置为更高的值。

Worker 计数是根据 CPU 内核计算的。如果 worker 过于频繁地重新启动(每分钟一次或更多次),具有 4-8 个 worker 的小型部署可能会遇到性能问题。

如果服务器有空闲内存,则建议设置 1200 或更高的值。

监控 worker 重启

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

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

{
  "severity": "WARN",
  "time": "2023-01-04T09:45:16.173Z",
  "correlation_id": null,
  "pid": 2725,
  "worker_id": "puma_0",
  "memwd_handler_class": "Gitlab::Memory::Watchdog::PumaHandler",
  "memwd_sleep_time_s": 5,
  "memwd_rss_bytes": 1077682176,
  "memwd_max_rss_bytes": 629145600,
  "memwd_max_strikes": 5,
  "memwd_cur_strikes": 6,
  "message": "rss memory limit exceeded"
}

memwd_rss_bytes 是实际消耗的内存量,memwd_max_rss_bytes 是通过 per_worker_max_memory_mb 设置的 RSS 限制。

更改 worker 超时

默认 Puma 超时为 60 秒

note puma['worker_timeout'] 没有设置最大请求持续时间。

要将 worker 超时更改为 600 秒:

  1. 编辑 /etc/gitlab/gitlab.rb

    gitlab_rails['env'] = {
       'GITLAB_RAILS_RACK_TIMEOUT' => 600
     }
    
  2. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

在内存受限的环境中禁用 Puma 集群模式

caution 这是一个实验性的 Alpha 功能,如有更改,恕不另行通知。该功能尚未准备好用于生产用途。如果您想使用此功能,我们建议您先使用非生产数据进行测试。有关更多详细信息,请参阅 已知问题

在可用 RAM 少于 4GB 的内存受限环境中,请考虑禁用 Puma 集群模式

workers 的数量设置为 0 以减少数百 MB 的内存使用量:

  1. 编辑 /etc/gitlab/gitlab.rb

    puma['worker_processes'] = 0
    
  2. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

与默认设置的集群模式不同,只有一个 Puma 进程将为应用程序提供服务。 有关 Puma worker 和线程设置的详细信息,请参阅 Puma 要求

在这种配置中运行 Puma 的缺点是吞吐量降低,这在内存受限的环境中可以被认为是公平的权衡。

请记住有足够的可用交换空间以避免内存不足 (OOM) 情况。 查看内存要求,了解详细信息。

Puma 单一模式已知问题

在单一模式下运行 Puma 时,不支持某些功能:

将 Puma 与 Rugged 一起使用时的性能警告

对于使用 NFS 存储 Git 仓库的部署,极狐GitLab 通过 Rugged 使用直接 Git 访问来提高性能。

如果直接 Git 访问可用并且 Puma 正在单线程运行,则会自动启用 Rugged 的使用,除非它被功能标志禁用。

MRI Ruby 使用全局 VM 锁 (GVL)。 GVL 允许 MRI Ruby 是多线程的,但最多只能在单个内核上运行。

Git 包括密集的 I/O 操作。当 Rugged 长时间使用一个线程时,可能正在处理请求的其他线程可能会饿死。在单线程模式下运行的 Puma 没有这个问题,因为最多同时处理一个请求。

目前正在努力移除 Rugged 的使用。尽管目前没有 Rugged 的性能是可以接受的,但在某些情况下,使用它运行可能仍然有益。

鉴于使用多线程 Puma 运行 Rugged 的警告以及 Gitaly 可接受的性能,如果使用 Puma 多线程(当 Puma 配置为使用多个线程运行时),我们将禁用 Rugged 使用。

在某些情况下,此默认行为可能不是最佳配置。如果 Rugged 在您的部署中发挥重要作用,我们建议您进行基准测试以找到最佳配置:

  • 最安全的选择是从单线程 Puma 开始。
  • 要强制 Rugged 与多线程 Puma 一起使用,您可以使用功能标志。

将 Puma 配置为通过 SSL 侦听

Puma 与 Linux 软件包安装一起部署时,默认通过 Unix 套接字进行侦听。要将 Puma 配置为通过 HTTPS 端口进行侦听,请按照以下步骤操作:

  1. 为 Puma 侦听的地址生成 SSL 证书密钥对。在下面的示例中是 127.0.0.1

    note 如果使用来自自定义证书颁发机构 (CA) 的自签名证书,请按照文档使它们受到其他极狐GitLab 组件的信任。
  2. 编辑 /etc/gitlab/gitlab.rb

    puma['ssl_listen'] = '127.0.0.1'
    puma['ssl_port'] = 9111
    puma['ssl_certificate'] = '<path_to_certificate>'
    puma['ssl_certificate_key'] = '<path_to_key>'
    
    # Disable UNIX socket
    puma['socket'] = ""
    
  3. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    
note 除了 Unix 套接字,Puma 还在端口 8080 上侦听 HTTP,提供要被 Prometheus 抓取的指标。目前不可能让 Prometheus 通过 HTTPS 抓取它们。因此,从技术上讲,在不丢失 Prometheus 指标的情况下关闭此 HTTP 侦听器是不可能的。

从 Unicorn 切换到 Puma

note 对于基于 Helm 的部署,请参阅 webservice chart 文档

从 13.0 版本开始,Puma 是默认的 Web 服务器,并且 Unicorn 已被禁用。 在 14.0 版本中,Unicorn 已从 Linux 包中删除,不再受支持。

Puma 采用多线程架构,与 Unicorn 等多进程应用服务器相比,它使用的内存更少。大多数 Rails 应用程序请求通常包含一定比例的 I/O 等待时间。

在 I/O 等待期间,MRI Ruby 将 GVL 释放给其它线程。因此,多线程 Puma 仍然可以处理比单个进程更多的请求。

当切换到 Puma 时,由于两个应用程序服务器之间的差异,任何 Unicorn 服务器配置都不会自动继承。

从 Unicorn 切换到 Puma:

  1. 确定合适的 Puma worker 和 thread 设置
  2. /etc/gitlab/gitlab.rb 中,将任何自定义 Unicorn 设置转换为 Puma。

    下表总结了在使用 Linux 包时,哪些 Unicorn 配置键与 Puma 中的配置键对应,哪些没有对应的配置键。

    Unicorn Puma
    unicorn['enable'] puma['enable']
    unicorn['worker_timeout'] puma['worker_timeout']
    unicorn['worker_processes'] puma['worker_processes']
    n/a puma['ha']
    n/a puma['min_threads']
    n/a puma['max_threads']
    unicorn['listen'] puma['listen']
    unicorn['port'] puma['port']
    unicorn['socket'] puma['socket']
    unicorn['pidfile'] puma['pidfile']
    unicorn['tcp_nopush'] n/a
    unicorn['backlog_socket'] n/a
    unicorn['somaxconn'] puma['somaxconn']
    n/a puma['state_path']
    unicorn['log_directory'] puma['log_directory']
    unicorn['worker_memory_limit_min'] n/a
    unicorn['worker_memory_limit_max'] puma['per_worker_max_memory_mb']
    unicorn['exporter_enabled'] puma['exporter_enabled']
    unicorn['exporter_address'] puma['exporter_address']
    unicorn['exporter_port'] puma['exporter_port']
  3. 重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    
  4. (可选)对于多节点部署,将负载均衡器配置为使用 readiness check。