- 메모리 사용량 줄이기
- 워커 타임아웃 변경
- 제한된 메모리 환경에서 Puma 클러스터 모드 비활성화
- SSL을 통해 Puma 구성하기
- 유니콘에서 퓨마로 전환
- Puma 문제 해결
- 관련 주제
GitLab 패키지의 번들된 Puma 인스턴스 구성
Puma는 빠르고 멀티 스레드이며 고도로 동시성이 뛰어난 Ruby 애플리케이션용 HTTP 1.1 서버입니다. GitLab의 사용자 지향 기능을 제공하는 핵심 Rails 애플리케이션을 실행합니다.
메모리 사용량 줄이기
메모리 사용량을 줄이기 위해 Puma는 워커 프로세스를 fork합니다. 워커가 생성될 때마다 기본 프로세스와 메모리를 공유합니다. 워커는 메모리 페이지에 변경 사항이나 추가가 있을 때에만 추가 메모리를 사용합니다. 이로 인해 Puma 워커가 시간이 지남에 따라 더 많은 물리적 메모리를 사용할 수 있습니다. 시간이 지남에 따른 메모리 사용량은 GitLab의 사용에 따라 달라집니다. GitLab 사용자가 사용하는 기능이 더 많을수록 예상 메모리 사용량도 더 높아집니다.
메모리 증가를 제어하기 위해 GitLab Rails 애플리케이션은 지정된 주거 집합 크기 (RSS) 임계값을 일정 시간 동안 초과하는 경우 워커를 자동으로 다시 시작하는 감시 스레드를 실행합니다.
GitLab은 기본적으로 메모리 제한을 1200Mb
로 설정합니다. 기본값을 재정의하려면 per_worker_max_memory_mb
를 새로운 RSS 제한으로 설정하세요(메가바이트).
-
/etc/gitlab/gitlab.rb
파일을 편집합니다:puma['per_worker_max_memory_mb'] = 1024 # 1GB
-
GitLab을 다시 구성합니다:
sudo gitlab-ctl reconfigure
워커가 다시 시작되면 일시적으로 GitLab을 실행할 수 있는 용량이 감소합니다. 워커가 자주 교체되는 경우 per_worker_max_memory_mb
값을 더 높은 값으로 설정하세요.
워커 수는 CPU 코어를 기반으로 계산됩니다. 4-8개의 워커를 사용하는 소규모 GitLab 배포는 워커가 자주 재시작되는 경우(1분당 한 번 이상) 성능 문제가 발생할 수 있습니다.
서버에 더 많은 메모리가 있는 경우 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초입니다.
puma['worker_timeout']
설정은 최대 요청 기간을 설정하지 않습니다.워커 타임아웃을 600초로 변경하려면:
-
/etc/gitlab/gitlab.rb
파일을 편집합니다:gitlab_rails['env'] = { 'GITLAB_RAILS_RACK_TIMEOUT' => 600 }
-
GitLab을 다시 구성합니다:
sudo gitlab-ctl reconfigure
제한된 메모리 환경에서 Puma 클러스터 모드 비활성화
4GB 미만의 RAM이 있는 메모리 제한 환경에서 Puma 클러스터 모드를 비활성화하는 것을 고려하세요.
workers
수를 0
으로 설정하여 수백 MB의 메모리 사용량을 줄일 수 있습니다:
-
/etc/gitlab/gitlab.rb
파일을 편집합니다:puma['worker_processes'] = 0
-
GitLab을 다시 구성합니다:
sudo gitlab-ctl reconfigure
기본적으로 설정된 클러스터 모드와 달리, 하나의 Puma 프로세스만 응용 프로그램을 제공하게 됩니다. Puma 워커 및 스레드 설정에 대한 자세한 내용은 Puma 요구 사항을 참조하세요.
이 구성에서 Puma를 실행하는 단점은 처리량이 감소되는 것인데, 메모리 제한이 있는 환경에서 합당한 교환으로 간주될 수 있습니다.
메모리 부족 (OOM) 상태를 피하기 위해 충분한 스왑 공간이 있는지 확인하세요. 자세한 내용은 메모리 요구 사항을 참조하세요.
Puma 단일 모드 알려진 문제
Puma를 단일 모드로 실행하는 경우 일부 기능이 지원되지 않습니다:
자세한 내용은 에픽 5303을 참조하세요.
SSL을 통해 Puma 구성하기
Linux 패키지 설치로 배포된 Puma는 기본적으로 Unix 소켓을 통해 듣습니다. 대신 HTTPS 포트로 Puma를 듣도록 구성하려면 다음 단계를 따르세요:
-
Puma가 듣도록 할 주소에 대한 SSL 인증서 키 쌍을 생성합니다. 여기서는
127.0.0.1
로 설정합니다.사용자 지정 인증 기관(CA)에서 제공하는 자체 서명된 인증서를 사용하는 경우 다른 GitLab 컴포넌트에서 신뢰하도록 하려면 문서를 참조하세요. -
/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>' # UNIX 소켓 비활성화 puma['socket'] = ""
-
GitLab을 다시 구성합니다:
sudo gitlab-ctl reconfigure
암호화된 SSL 키 사용
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 키를 제거할 수 있어야 합니다.
유니콘에서 퓨마로 전환
webservice
차트 문서를 참조하세요.GitLab 13.0부터 Puma가 기본 웹 서버이며 유니콘이 비활성화되었습니다. GitLab 14.0에서는 유니콘이 제거되었으며 더 이상 지원되지 않습니다.
Puma는 멀티 스레드 아키텍처를 사용하여 유니콘과 같은 멀티 프로세스 애플리케이션 서버보다 적은 메모리를 사용합니다. GitLab.com에서는 메모리 소비량이 40% 감소했습니다. 대부분의 Rails 애플리케이션 요청에는 일반적으로 I/O 대기 시간의 일부가 포함됩니다.
I/O 대기 시간 동안 MRI 루비는 GVL(Global VM Lock)을 다른 스레드에게 릴리스합니다. 멀티 스레드 Puma는 따라서 하나의 프로세스보다 더 많은 요청을 처리할 수 있습니다.
Puma로 전환하면 두 애플리케이션 서버 간의 차이로 인해 유니콘 서버 설정이 자동으로 전달되지 않습니다.
유니콘에서 퓨마로 전환하려면:
- 적절한 Puma 워커 및 스레드 설정을 결정합니다.
-
/etc/gitlab/gitlab.rb
에서 사용자 정의 유니콘 설정을 Puma로 변환합니다.다음 표는 리눅스 패키지를 사용할 때, 유니콘 구성 키와 Puma의 대응 키를 요약한 것이며 대응되지 않는 키에는 대응 키가 없음을 나타냅니다.
유니콘 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 게이트웨이 타임아웃
이 오류는 웹 서버가 (기본: 60초) Puma 워커로부터 응답을 받지 못한 후 시간 초과되었을 때 발생합니다. CPU가 100%로 회전하면, 예상보다 더 오랜 시간이 걸리는 작업이 있을 수 있습니다.
이 문제를 해결하려면 먼저 무슨 일이 일어나고 있는지 파악해야 합니다. 사용자에게 영향을 미치는 것을 신경 쓰지 않는다면, 다음 섹션으로 건너뛰세요. 그렇지 않으면, 다음 팁을 실행하세요.
- 문제가 있는 URL을 로드합니다.
-
sudo gdb -p <PID>
를 실행하여 Puma 프로세스에 연결합니다. -
GDB 창에서 다음을 입력합니다:
call (void) rb_backtrace()
-
이렇게 하면 프로세스가 루비 백트레이스를 생성하게 됩니다. 백트레이스를 확인하기 위해
/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 Worker timeout을 참조하세요.
변경 사항이 적용되려면 GitLab을 다시 구성하십시오.
기타 사용자에게 영향을 미치지 않고 문제 해결
이전 섹션은 실행 중인 Puma 프로세스에 첨부되어 있을 수 있으며, 이는 이때 GitLab에 접근하려는 사용자들에게 원치 않은 영향을 미칠 수 있습니다. 운영 중인 시스템에서 다른 사람에게 영향을 주지 않는 것에 대해 우려된다면 문제를 해결하기 위해 별도의 Rails 프로세스를 실행할 수 있습니다:
- GitLab 계정에 로그인합니다.
- 문제가 되는 URL을 복사합니다 (예:
https://gitlab.com/ABC
). - 사용자 토큰 (사용자 설정 -> 액세스 토큰)을 생성합니다.
- GitLab Rails 콘솔을 실행합니다.
-
Rails 콘솔에서 다음을 실행합니다:
app.get '<단계 2의 URL>/?private_token=<단계 3의 토큰>'
예시:
app.get 'https://gitlab.com/gitlab-org/gitlab-foss/-/issues/1?private_token=123456'
- 새 창에서
top
을 실행합니다. 해당 Ruby 프로세스가 CPU를 100% 사용 중인 것을 보여줘야 합니다. PID를 메모합니다. - 이전 섹션에서 GDB 사용 단계 2를 따릅니다.
GitLab: API에 접근할 수 없음
이는 종종 GitLab Shell이 내부 API (예: http://localhost:8080/api/v4/internal/allowed
)를 통해 권한 요청을 시도할 때 발생하며, 확인하는 중에 어떤 문제가 발생할 수 있습니다. 이런 경우가 발생하는 이유는 다양합니다:
- 데이터베이스에 연결하는 시간이 초과됨 (예: PostgreSQL 또는 Redis)
- Git 후크 또는 푸시 규칙에서 오류가 발생함
- 저장되지 않은 NFS 핸들과 같은 리포지터리에 접근하는 중 오류가 발생함
이 문제를 진단하려면 문제를 재현한 후 top
명령을 사용하여 Puma 워커가 무한 루프에 빠졌는지 확인합니다. 또한, strace
를 사용하여 문제를 분리하는 데 도움이 될 수 있습니다:
strace -ttTfyyy -s 1024 -p <Puma 워커의 PID> -o /tmp/puma.txt
만약 어떤 Puma 워커가 문제인지 분리할 수 없다면, 모든 Puma 워커에서 /internal/allowed
엔드포인트가 어디에서 막혔는지 확인하기 위해 다음을 실행합니다:
ps auwx | grep puma | awk '{ print " -p " $2}' | xargs strace -ttTfyyy -s 1024 -o /tmp/puma.txt
/tmp/puma.txt
의 출력 내용이 근본 원인을 진단하는 데 도움이 될 수 있습니다.