- 메모리 사용 줄이기
- 작업자 타임아웃 변경
- 메모리 제약 환경에서 Puma 클러스터 모드 비활성화
- Puma를 SSL로 수신 대기하도록 구성하기
- Unicorn에서 Puma로 전환
- Puma 문제 해결
- 관련 주제
GitLab 패키지의 번들된 Puma 인스턴스 구성
Offering: Self-managed
Puma는 Ruby 애플리케이션을 위한 빠르고 다중 스레드 및 고도로 동시성을 지원하는 HTTP 1.1 서버입니다. 이는 GitLab의 사용자 인터페이스 기능을 제공하는 핵심 Rails 애플리케이션을 실행합니다.
메모리 사용 줄이기
Puma는 메모리 사용을 줄이기 위해 작업자 프로세스를 포크합니다. 작업자를 생성할 때마다 기본 프로세스와 메모리를 공유합니다. 작업자는 메모리 페이지를 변경하거나 추가할 때만 추가 메모리를 사용합니다. 시간이 지남에 따라 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이 available한 메모리 제약 환경에서 Puma 클러스터 모드를 비활성화하는 것을 고려하세요.
메모리 사용량을 수백 MB 줄이기 위해 workers
수를 0
으로 설정하세요:
-
/etc/gitlab/gitlab.rb
를 편집합니다:puma['worker_processes'] = 0
-
GitLab을 재구성합니다:
sudo gitlab-ctl reconfigure
클러스터 모드와 달리 기본적으로 설정된 이 구성에서는 애플리케이션을 단일 Puma 프로세스만 제공하게 됩니다. Puma 워커 및 스레드 설정에 대한 자세한 내용은 Puma 요구 사항을 참조하세요.
이 구성이 Puma를 실행할 때의 단점은 처리량이 감소되며, 이는 메모리 제약 환경에서는 공정한 거래로 간주될 수 있습니다.
메모리 부족(OOM) 상황을 피하기 위해 충분한 스왑 공간이 있는지 확인하세요. 자세한 내용은 메모리 요구 사항을 확인하세요.
Puma 단일 모드 알려진 문제
Puma를 단일 모드로 실행할 때 지원되지 않는 몇 가지 기능이 있습니다:
자세한 내용은 엡틱 5303를 참조하세요.
Puma를 SSL로 수신 대기하도록 구성하기
Linux 패키지 설치로 배포된 Puma는 기본적으로 Unix 소켓을 통해 수신 대기합니다. Puma가 HTTPS 포트를 통해 수신 대기하도록 구성하려면 아래 단계를 따르세요:
-
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
참고: Unix 소켓 외에도 Puma는 Prometheus에서 수집할 수 있는 메트릭을 제공하기 위해 포트 8080에서 HTTP로 수신 대기합니다. 현재 Prometheus가 HTTPS를 통해 이를 수집하는 것은 불가능하며, 이에 대한 지원은 이 문제에서 논의되고 있습니다. 따라서 Prometheus 메트릭을 잃지 않고 이 HTTP 리스너를 끌 수는 기술적으로 불가능합니다.
암호화된 SSL 키 사용
- GitLab 16.1에서 도입됨.
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로 전환
메모:
Helm 기반 배포의 경우,
webservice
차트 문서를 참조하세요.
Puma는 기본 웹 서버이며 Unicorn은 더 이상 지원되지 않습니다.
Puma는 Unicorn과 같은 다중 프로세스 응용 프로그램 서버보다 적은 메모리를 사용하는 다중 스레드 아키텍처를 가지고 있습니다. GitLab.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와 어떤 대응 관계가 있는지와 대응되는 counterpart가 없는 항목을 요약합니다.
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 게이트웨이 시간 초과
이 오류는 웹 서버가 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
GDB는 Puma 프로세스가 이러한 명령을 실행하기 전에 종료되면 오류를 보고합니다. 시간을 더 벌기 위해 항상 Puma 작업자 타임아웃을 늘릴 수 있습니다.
리눅스 패키지 설치 사용자인 경우 /etc/gitlab/gitlab.rb
를 편집하고 60초에서 600초로 증가시킬 수 있습니다:
gitlab_rails['env'] = {
'GITLAB_RAILS_RACK_TIMEOUT' => 600
}
자체 컴파일된 설치의 경우 환경 변수를 설정하십시오. Puma 작업자 타임아웃을 참조하세요.
변경 사항이 적용되도록 Reconfigure 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 핸들)
이 문제를 진단하기 위해, 문제를 재현해보고 top
을 통해 작동 중인 Puma 작업자가 있는지 확인하세요. 위의 gdb
기법을 사용해 보세요. 또한, strace
를 사용하면 문제를 격리하는 데 도움을 줄 수 있습니다:
strace -ttTfyyy -s 1024 -p <Puma 작업자의 PID> -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
의 출력은 근본 원인을 진단하는 데 도움이 될 수 있습니다.