PostgreSQL 튜닝
GitLab v19.3Offering: GitLab Self-Managed
요약
다음과 같은 경우 PostgreSQL을 튜닝해야 합니다: 다음 설정은 외부에서 관리되는 PostgreSQL 인스턴스에 필요합니다. 서버의 모든 데이터베이스가 아닌 특정 데이터베이스에 대해 일부 PostgreSQL 설정을 구성할 수 있습니다.
다음과 같은 경우 PostgreSQL을 튜닝해야 합니다:
- 다른 GitLab 구성요소가 데이터베이스에 영향을 미치는 방식으로 재구성되거나 확장된 경우.
- GitLab 환경의 성능이 저하된 경우.
- GitLab이 외부 PostgreSQL 서비스를 사용하는 경우.
외부 인스턴스에 필요한 설정#
다음 설정은 외부에서 관리되는 PostgreSQL 인스턴스에 필요합니다.
| 조정 가능한 설정 | 필요한 값 | 추가 정보 |
|---|---|---|
| work_mem | 최소 8 MB | 이 값은 Linux 패키지 기본값입니다. 대규모 배포에서 쿼리가 임시 파일을 생성하는 경우 이 설정을 늘려야 합니다. |
| maintenance_work_mem | 최소 64 MB | 더 큰 데이터베이스 서버에는 더 많은 값이 필요합니다. |
| max_connections | 최소 400 | 데이터베이스 호스트가 처리할 수 있는 수준을 기준으로 설정합니다. 데이터베이스 호스트 용량 결정을 참조하십시오. 연결 수요 공식은 프론트엔드 수요를 산출할 뿐, 이 값을 산출하지 않습니다. |
| shared_buffers | 최소 2 GB | 더 큰 데이터베이스 서버에는 더 많은 값이 필요합니다. Linux 패키지 기본값은 서버 RAM의 25%로 설정됩니다. |
| statement_timeout | 15000 ~ 60000 | statement timeout은 잠금과 관련된 폭주 문제 및 데이터베이스가 새 클라이언트를 거부하는 것을 방지합니다. 15 |
| hot_standby_feedback | on | 여러 노드와 데이터베이스 부하 분산이 구성된 환경에서는 지연 누적을 방지하기 위해 모든 복제본 노드에서 hot_standby_feedback을 활성화하십시오. |
서버의 모든 데이터베이스가 아닌 특정 데이터베이스에 대해 일부 PostgreSQL 설정을 구성할 수 있습니다.
- 동일한 서버에서 여러 데이터베이스를 호스팅하는 경우 특정 데이터베이스로 구성을 제한할 수 있습니다.
- 구성을 적용할 위치에 대한 지침은 데이터베이스 관리자 또는 공급업체에 문의하십시오.
- GCP Cloud SQL의 경우 특정 데이터베이스 또는 사용자에 대해
statement_timeout을 설정할 수 있지만, 데이터베이스 플래그로는 설정할 수 없습니다. 예:ALTER DATABASE gitlab SET statement_timeout = '60s';
데이터베이스 연결 계획#
이 공식은 애플리케이션의 프론트엔드 연결 수요, 즉 Rails가 데이터베이스(또는 PgBouncer)에 여는 연결 수를 계산합니다. 이 값은 PostgreSQL
max_connections에 사용할 값이 아닙니다. max_connections 크기를 산정하는 방법은 데이터베이스 호스트 용량 결정을
참조하십시오.
GitLab 16.0 이상 버전은 main 및 ci 테이블에 대해
두 세트의 데이터베이스 연결을 사용합니다. 동일한 PostgreSQL 데이터베이스가 두 테이블 세트를 모두 처리하는 경우에도 연결 사용량이 두 배가 됩니다.
GitLab은 여러 구성요소에서 데이터베이스 연결을 사용합니다. 적절한 연결 계획은 데이터베이스 연결 고갈 및 성능 문제를 방지합니다.
각 GitLab 구성요소는 구성에 따라 데이터베이스 연결을 사용합니다. Sidekiq 및 Puma는 초기화 시 PostgreSQL에 대한 연결 풀을 설정합니다. 연결 스파이크나 수요의 일시적 증가가 있는 경우 풀의 연결 수가 나중에 증가할 수 있습니다:
- 환경 변수
DB_POOL_HEADROOM으로 데이터베이스 풀 여유분을 구성합니다. - PostgreSQL을 튜닝할 때 풀 여유분을 계획하되 변경하지 마십시오. GitLab 배포는 더 많은 용량이 사용 가능한 경우 더 높은 수요에 더 잘 대응합니다: 더 많은 Sidekiq 또는 Puma 워커를 배포하십시오.
Puma#
Puma connections = puma['worker_processes'] × (puma['max_threads'] + DB_POOL_HEADROOM)
기본값:
puma['worker_processes']는 CPU 코어 수를 기반으로 합니다.puma['max_threads']는4입니다.DB_POOL_HEADROOM은10입니다.
워커당 계산: 각 Puma 워커는 4개의 스레드 + 10개의 여유분을 사용하여 총 14개의 연결을 사용합니다.
8 vCPU를 가정한 기본 계산: 8개 워커 × 워커당 14개 연결, 총 112개의 Puma 연결.
Sidekiq#
Sidekiq connections = Number of Sidekiq processes × (sidekiq['concurrency'] + 1 + DB_POOL_HEADROOM)
기본값:
- Sidekiq 프로세스 수는
1입니다. sidekiq['concurrency']는20입니다.DB_POOL_HEADROOM은10입니다.
기본 계산: 1개 Sidekiq 프로세스 × (20 동시성 + 1 + 10 여유분), 총 31개의 Sidekiq 연결.
Geo 로그 커서 (Geo 설치 전용)#
Geo 로그 커서 데몬은 보조 사이트의 모든 GitLab Rails 노드에서 실행됩니다.
Geo log cursor connections = 1 + DB_POOL_HEADROOM
기본 계산: 1 + 10 여유분, 총 11개의 Geo 연결.
총 연결 요구 사항#
단일 노드 설치의 경우:
Total connections = 2 × (Puma + Sidekiq + Geo)
다중 노드 설치의 경우 각 구성요소를 실행하는 노드 수를 곱합니다:
Total connections = 2 × ((Puma × Rails nodes) + (Sidekiq × Sidekiq nodes) + (Geo × secondary Rails nodes))
2를 곱하는 것은 이중 데이터베이스 연결을 고려한 것입니다.
Geo 설치의 경우:
- 기본 사이트:
Geo = 0을 사용합니다. Geo 로그 커서는 기본 사이트에서 실행되지 않습니다. - 보조 사이트: 하나의 보조 사이트에 대한 Geo 로그 커서 데이터베이스 연결을 계산하고 동일한 계산을 모든 보조 사이트에 적용합니다.
- 각 Geo 사이트는 자체 데이터베이스에 연결하므로 여러 Geo 사이트 간에 연결을 합산할 필요가 없습니다.
- 기본 PostgreSQL 데이터베이스와 모든 복제본 데이터베이스에
max_connections를 동일한 값으로 설정하되, 모든 Geo 사이트 중 가장 높은 연결 요구 사항을 사용합니다.
예시#
단일 노드 설치#
이 예시는 초당 20 RPS(요청) 또는 1000명 사용자에 대한 GitLab 참조 아키텍처를 기반으로 합니다:
| 구성요소 | 노드 | 구성 | 구성요소당 연결 수 | 이중 데이터베이스 구성요소 합계 |
|---|---|---|---|---|
| Puma | 1 | 8개 워커, 각 4개 스레드 | 워커당 14개 | 224 |
| Sidekiq | 1 | 1개 프로세스, 20 동시성 | 프로세스당 31개 | 62 |
| 합계 | 286 |
다중 노드 설치#
이 예시는 초당 40 RPS(요청) 또는 2000명 사용자에 대한 GitLab 참조 아키텍처를 기반으로 합니다:
| 구성요소 | 노드 | 구성 | 구성요소당 연결 수 | 이중 데이터베이스 구성요소 합계 |
|---|---|---|---|---|
| Puma | 2 | 노드당 8개 워커, 각 4개 스레드 | 워커당 14개 | 448 |
| Sidekiq | 1 | 4개 프로세스, 각 20 동시성 | 프로세스당 31개 | 248 |
| 합계 | 696 |
Geo를 사용하는 단일 노드 설치#
이 예시는 초당 20 RPS(요청) 또는 1000명 사용자에 대한 GitLab 참조 아키텍처를 기반으로 합니다.
| Geo 사이트당 구성요소 | 노드 | 구성 | 구성요소당 연결 수 | 이중 데이터베이스 구성요소 합계 |
|---|---|---|---|---|
| Puma | 1 | 8개 워커, 각 4개 스레드 | 워커당 14개 | 224 |
| Sidekiq | 1 | 1개 프로세스, 20 동시성 | 프로세스당 31개 | 62 |
| Geo 로그 커서 (보조 사이트 전용) | 1 | 1개 프로세스 | 프로세스당 11개 | 22 |
| 합계 | 308 |
Geo를 사용하는 다중 노드 설치#
이 예시는 초당 40 RPS(요청) 또는 2000명 사용자에 대한 GitLab 참조 아키텍처를 기반으로 합니다:
| Geo 사이트당 구성요소 | 노드 | 구성 | 구성요소당 연결 수 | 이중 데이터베이스 구성요소 합계 |
|---|---|---|---|---|
| Puma | 2 | 노드당 8개 워커, 각 4개 스레드 | 워커당 14개 | 448 |
| Sidekiq | 1 | 4개 프로세스, 각 20 동시성 | 프로세스당 31개 | 248 |
| Geo 로그 커서 (보조 사이트 전용) | 2 | Rails 노드당 1개 프로세스 | 프로세스당 11개 | 44 |
| 합계 | 740 |
데이터베이스 호스트 용량 결정 (max_connections)#
max_connections는 데이터베이스 호스트가 실제로 처리할 수 있는 범위, 즉 CPU, 메모리, IO 용량에 따라 제한됩니다. 이 값은 애플리케이션 연결 수요 공식에서 도출되지 않습니다.
- 일반적인 규칙으로
max_connections는 vCPU 수의 배수, 일반적으로 2~10배 범위로 설정합니다. 이는 시작점일 뿐이며, 호스트가 감당할 수 있는 값은 사용 가능한 메모리, IO 용량, 워크로드에 따라서도 달라집니다. - 더 세밀하게 튜닝하려면 메모리, 스토리지 유형, 워크로드를 고려하는 PGTune을 사용하십시오.
- 관리형 PostgreSQL 데이터베이스(RDS, Cloud SQL, Azure Database for PostgreSQL)를 사용하는 경우 공급업체 문서를 참조하십시오.
max_connections값을 변경하려면 모든 PostgreSQL 노드를 재시작해야 합니다.
Geo 설치의 경우 기본 PostgreSQL 데이터베이스와 모든 복제본 데이터베이스에 max_connections를 동일한 값으로 설정하십시오.
Geo 관련 지침은 총 연결 요구 사항을 참조하십시오.
토폴로지에 맞는 연결 크기 산정#
애플리케이션과 데이터베이스 사이에 PgBouncer가 있는지 여부에 따라 다음 지침을 사용하십시오.
PgBouncer를 사용하지 않는 경우#
애플리케이션이 PostgreSQL에 직접 연결하므로 수요 계산에 포함된 모든 연결을 백엔드에서 처리해야 합니다.
- 데이터베이스 연결 계획 공식을 사용하여 총 프론트엔드 연결 수요를 계산합니다.
- 호스트가 처리할 수 있는 경우 PostgreSQL
max_connections를 최소한 그 값으로 설정합니다. 데이터베이스 호스트 용량 결정을 참조하십시오. - 총 연결 수요가 호스트가 처리할 수 있는 수준을 초과하는 경우(대략적인 기준으로 vCPU의 2~10배 범위를 넘어서거나
CPU, 메모리, IO를 정상 수준 이상으로 몰아붙이는 경우)
max_connections를 거기에 맞춰 올리지 마십시오. 이는 해당 설치에 연결 풀링이 필요하다는 명확한 신호입니다. PgBouncer를 추가하고 PgBouncer를 사용하는 경우에 설명된 대로 크기를 산정하십시오.
PgBouncer를 사용하는 경우#
PgBouncer가 연결을 풀링하므로 애플리케이션의 프론트엔드 수요와 데이터베이스의 백엔드 연결은 별도로 크기를 산정합니다.
PgBouncer 용어로는 다음과 같습니다:
pgbouncer['max_client_conn']은 프론트엔드 풀, 즉 Rails에서 PgBouncer로의 연결입니다.pgbouncer['default_pool_size']는 백엔드 풀, 즉 PgBouncer에서 데이터베이스로의 연결입니다. 이 값은 풀별(데이터베이스/사용자 쌍별)로 크기가 산정됩니다. GitLab은main과ci에 대해 별도의 풀을 열기 때문에 백엔드 풀 예산은 PgBouncer 노드당 두 풀을 모두 고려해야 합니다.
PgBouncer를 사용할 때 연결 크기를 산정하려면:
- 데이터베이스 연결 계획 공식을 사용하여 최악의 경우 프론트엔드 연결 수요를 계산합니다.
- 그 합계를 PgBouncer 노드 수로 나누고, 그 결과에 2를 곱한 값을 각 노드의
pgbouncer['max_client_conn']에 사용합니다. - PostgreSQL
max_connections는 프론트엔드 수요 공식이 아니라 데이터베이스 호스트가 처리할 수 있는 용량을 기준으로 결정합니다. - 그
max_connections값을 PgBouncer 노드 수로 나누고, 그 결과를 각 노드의pgbouncer['default_pool_size']에 사용합니다.
이러한 매개변수에 대한 자세한 참고 자료는 PgBouncer 문서의 세부 튜닝을 참조하십시오.