{{< details >}}
- Tier: 基础版, 专业版, 旗舰版
- Offering: 私有化部署
{{< /details >}}
Puma 是一个快速、多线程和高并发的 HTTP 1.1 服务器,适用于 Ruby 应用程序。它运行核心 Rails 应用程序,提供极狐GitLab 的用户界面功能。
减少内存使用
为了减少内存使用,Puma 会派生工作进程。每次创建一个工作进程时,它会与主进程共享内存。只有当工作进程更改或添加其内存页面时才会使用额外的内存。随着工作进程处理更多的 Web 请求,Puma 的工作进程可能会随着时间的推移使用更多的物理内存。随着极狐GitLab 的使用量增加,内存使用量也会随之增加。极狐GitLab 用户使用的功能越多,预计内存使用量随时间的增加也越多。
为了阻止不受控制的内存增长,极狐GitLab Rails 应用程序运行一个监督线程,如果工作进程超过给定驻留集大小 (RSS) 阈值持续一段时间,就会自动重新启动工作进程。
极狐GitLab 将内存限制的默认值设置为 1200Mb
。要覆盖默认值,请将 per_worker_max_memory_mb
设置为新的 RSS 限制(以 MB 为单位):
-
编辑
/etc/gitlab/gitlab.rb
:puma['per_worker_max_memory_mb'] = 1024 # 1GB
-
重新配置极狐GitLab:
sudo gitlab-ctl reconfigure
当工作进程重新启动时,运行极狐GitLab 的容量会在短时间内减少。如果工作进程被替换过于频繁,请将 per_worker_max_memory_mb
设置为更高的值。
工作进程数根据 CPU 核心数计算。一个小型的极狐GitLab 部署,拥有 4-8 个工作进程,如果工作进程被过于频繁地重新启动(每分钟一次或更多),可能会遇到性能问题。
如果服务器有空闲内存,设置 1200
或更高的值可能会有益。
监控工作进程重启
极狐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 限制。
更改工作进程超时时间
默认的 Puma 超时时间为 60 秒。
{{< alert type=”note” >}}
puma['worker_timeout']
设置不会设置最大请求持续时间。
{{< /alert >}}
要将工作进程超时更改为 600 秒:
-
编辑
/etc/gitlab/gitlab.rb
:gitlab_rails['env'] = { 'GITLAB_RAILS_RACK_TIMEOUT' => 600 }
-
重新配置极狐GitLab:
sudo gitlab-ctl reconfigure
在内存受限环境中禁用 Puma 集群模式
{{< alert type=”warning” >}}
此功能是一个实验,可能会在不通知的情况下更改。此功能尚未准备好用于生产环境。如果您想使用此功能,您应该先在生产环境之外进行测试。有关详细信息,请参阅已知问题。
{{< /alert >}}
在可用 RAM 少于 4 GB 的内存受限环境中,考虑禁用 Puma 集群模式。
将 workers
的数量设置为 0
可以减少数百 MB 的内存使用:
-
编辑
/etc/gitlab/gitlab.rb
:puma['worker_processes'] = 0
-
重新配置极狐GitLab:
sudo gitlab-ctl reconfigure
不像默认设置的集群模式,只有单个 Puma 进程将为应用程序提供服务。有关 Puma 工作进程和线程设置的详细信息,请参阅 Puma 要求。
在这种配置下运行 Puma 的缺点是吞吐量减少,这在内存受限环境中可以被视为一个公平的权衡。
请记住要有足够的交换空间可用,以避免内存不足 (OOM) 情况。查看 内存要求 获取详细信息。
Puma 单一模式已知问题
在单一模式下运行 Puma 时,某些功能不受支持:
配置 Puma 通过 SSL 监听
当使用 Linux 软件包安装部署时,Puma 默认通过 Unix 套接字监听。要配置 Puma 通过 HTTPS 端口监听,请按照以下步骤操作:
-
为 Puma 将要监听的地址生成一个 SSL 证书密钥对。对于以下示例,这是
127.0.0.1
。{{< alert type=”note” >}}
如果使用来自自定义证书颁发机构 (CA) 的自签名证书,请按照文档使其被其他极狐GitLab 组件信任。
{{< /alert >}}
-
编辑
/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'] = ""
-
重新配置极狐GitLab:
sudo gitlab-ctl reconfigure
{{< alert type=”note” >}}
除了 Unix 套接字,Puma 还通过端口 8080 上的 HTTP 监听,为 Prometheus 提供可抓取的指标。因此,无法在不丢失 Prometheus 指标的情况下关闭此 HTTP 监听器。
{{< /alert >}}
使用加密的 SSL 密钥
{{< history >}}
- 引入于极狐GitLab 16.1。
{{< /history >}}
Puma 支持使用加密的私有 SSL 密钥,可以在运行时解密。以下说明展示了如何配置:
-
如果密钥尚未加密,请使用密码加密:
openssl rsa -aes256 -in /path/to/ssl-key.pem -out /path/to/encrypted-ssl-key.pem
输入密码两次以写入加密文件。在此示例中,我们使用
some-password-here
。 -
创建一个打印密码的脚本或可执行文件。例如,在
/var/opt/gitlab/gitlab-rails/etc/puma-ssl-key-password
中创建一个基本脚本来回显密码:#!/bin/sh echo some-password-here
避免将密码存储在磁盘上,并使用安全机制来检索密码,例如 Vault。例如,脚本可能看起来像:
#!/bin/sh export VAULT_ADDR=http://vault-password-distribution-point:8200 export VAULT_TOKEN=<some token> echo "$(vault kv get -mount=secret puma-ssl-password)"
-
确保 Puma 进程有足够的权限来执行该脚本并读取加密密钥:
chown git:git /var/opt/gitlab/gitlab-rails/etc/puma-ssl-key-password chmod 770 /var/opt/gitlab/gitlab-rails/etc/puma-ssl-key-password chmod 660 /path/to/encrypted-ssl-key.pem
-
编辑
/etc/gitlab/gitlab.rb
,用加密密钥替换puma['ssl_certificate_key']
并指定puma['ssl_key_password_command]
:puma['ssl_certificate_key'] = '/path/to/encrypted-ssl-key.pem' puma['ssl_key_password_command'] = '/var/opt/gitlab/gitlab-rails/etc/puma-ssl-key-password'
-
重新配置极狐GitLab:
sudo gitlab-ctl reconfigure
-
如果极狐GitLab 成功启动,您应该可以删除存储在极狐GitLab 实例上的未加密 SSL 密钥。
从 Unicorn 切换到 Puma
{{< alert type=”note” >}}
对于基于 Helm 的部署,请参阅webservice
图表文档。
{{< /alert >}}
Puma 是默认的 Web 服务器,Unicorn 不再受支持。
Puma 具有多线程架构,比多进程应用服务器(如 Unicorn)使用更少的内存。在 JihuLab.com 上,我们看到内存消耗减少了 40%。大多数 Rails 应用程序请求通常包含一定比例的 I/O 等待时间。
在 I/O 等待时间期间,MRI Ruby 会将 GVL 释放给其他线程。因此,多线程的 Puma 仍然可以比单个进程服务更多请求。
当切换到 Puma 时,由于两个应用服务器之间的差异,任何 Unicorn 服务器配置都不会自动携带过来。
要从 Unicorn 切换到 Puma:
- 确定合适的 Puma 工作进程和线程设置。
-
将
/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']
不适用 puma['ha']
不适用 puma['min_threads']
不适用 puma['max_threads']
unicorn['listen']
puma['listen']
unicorn['port']
puma['port']
unicorn['socket']
puma['socket']
unicorn['pidfile']
puma['pidfile']
unicorn['tcp_nopush']
不适用 unicorn['backlog_socket']
不适用 unicorn['somaxconn']
puma['somaxconn']
不适用 puma['state_path']
unicorn['log_directory']
puma['log_directory']
unicorn['worker_memory_limit_min']
不适用 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']
-
重新配置极狐GitLab:
sudo gitlab-ctl reconfigure
- 可选。对于多节点部署,配置负载均衡器以使用 就绪检查。
Puma 故障排除
Puma 在 100% CPU 负载下导致 502 网关超时
当 Web 服务器在没有收到 Puma 工作进程的响应后超时(默认:60 秒)时,会出现此错误。如果在此过程中 CPU 达到 100% 负载,可能有某些事情需要比预期更长的时间。
要解决此问题,我们首先需要弄清楚发生了什么。如果您不介意用户受到停机的影响,则仅推荐以下提示。否则,请跳至下一部分。
- 加载问题 URL
- 运行
sudo gdb -p <PID>
来附加到 Puma 进程。 -
在 GDB 窗口中输入:
call (void) rb_backtrace()
-
这会强制进程生成一个 Ruby 回溯。检查
/var/log/gitlab/puma/puma_stderr.log
中的回溯。例如,您可能会看到:from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:33:in `block in start' from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:33:in `loop' from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:36:in `block (2 levels) in start' from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:44:in `sample' from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:68:in `sample_objects' from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:68:in `each_with_object' from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:68:in `each' from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:69:in `block in sample_objects' from /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/metrics/sampler.rb:69:in `name'
-
要查看当前线程,请运行:
thread apply all bt
-
完成
gdb
调试后,确保从进程分离并退出:detach exit
如果 Puma 进程在您能够运行这些命令之前终止,GDB 会报告错误。为了争取更多时间,您可以始终提高 Puma 工作进程超时。对于 Linux 软件包安装用户,您可以编辑 /etc/gitlab/gitlab.rb
并将其从 60 秒增加到 600 秒:
gitlab_rails['env'] = {
'GITLAB_RAILS_RACK_TIMEOUT' => 600
}
对于自编译安装,请设置环境变量。请参阅 Puma 工作进程超时。
重新配置 极狐GitLab 以使更改生效。
不影响其他用户的故障排除
上一节附加到了正在运行的 Puma 进程,这可能会对试图在此期间访问极狐GitLab 的用户产生不利影响。如果您担心在生产系统期间影响其他用户,您可以运行一个单独的 Rails 进程来调试问题:
- 登录到您的极狐GitLab 账户。
- 复制导致问题的 URL(例如,
https://gitlab.com/ABC
)。 - 为您的用户创建一个个人访问令牌(用户设置 -> 访问令牌)。
- 启动 极狐GitLab Rails 控制台。
-
在 Rails 控制台中,运行:
app.get '<URL FROM STEP 2>/?private_token=<TOKEN FROM STEP 3>'
例如:
app.get 'https://gitlab.com/gitlab-org/gitlab-foss/-/issues/1?private_token=123456'
- 在新窗口中运行
top
。它应该显示此 Ruby 进程使用 100% 的 CPU。记下 PID。 - 按照上一节中使用 GDB 的步骤 2。
极狐GitLab:API 不可访问
当极狐GitLab Shell 尝试通过内部 API请求授权(例如,http://localhost:8080/api/v4/internal/allowed
)时,通常会发生这种情况,并且检查中出现了一些问题。可能发生这种情况的原因有很多:
- 连接到数据库(例如,PostgreSQL 或 Redis)超时
- Git 钩子或推送规则中的错误
- 访问存储库时出错(例如,陈旧的 NFS 句柄)
要诊断此问题,请尝试重现该问题,然后查看是否有 Puma 工作进程通过 top
旋转。尝试使用上述 gdb
技术。此外,使用 strace
可能有助于隔离问题:
strace -ttTfyyy -s 1024 -p <PID of puma worker> -o /tmp/puma.txt
如果无法隔离哪个 Puma 工作进程是问题,请尝试在所有 Puma 工作进程上运行 strace
,以查看
/internal/allowed
端点在哪里卡住:
ps auwx | grep puma | awk '{ print " -p " $2}' | xargs strace -ttTfyyy -s 1024 -o /tmp/puma.txt
/tmp/puma.txt
中的输出可能有助于诊断根本原因。