This page contains information related to upcoming products, features, and functionality. It is important to note that the information presented is for informational purposes only. Please do not rely on this information for purchasing or planning purposes. The development, release, and timing of any products, features, or functionality may be subject to change or delay and remain at the sole discretion of GitLab Inc.
Status Authors Coach DRIs Owning Stage Created
proposed -

데이터베이스 확장성: GitLab.com의 디스크 테이블 크기 제한을 100GB 이하로 설정

이 문서는 GitLab.com의 테이블 크기를 줄이고 제한하는 방안에 대한 제안서입니다. 우리는 가능한 목표를 설정하여 일정한 한도 이내로 테이블 크기를 제한함으로써 이를 데이터베이스에 중점을 두고 의사결정을 내릴 수 있는 지표로 활용합니다. GitLab.com이 성장함에 따라, 우리는 지속적으로 어떤 테이블을 작업해야 하는지 재평가하여 오류를 사전에 방지하거나 수정해야 합니다.

이는 단순히 엄격한 규칙이 아니라, 테이블을 나누거나 크기를 줄이기 위해 작업해야 함을 강력히 시사하는 것입니다.

이 문서는 데이터베이스 샤딩 설계도와 함께 이해하는 것이 목적입니다. 이 제안서는 우리가 저장 요구 사항을 줄이고 데이터 모델링을 개선하기 위한 “디블로팅 단계”의 일환으로 여겨지며, 가능한 경우 분할을 이미 솔루션으로 사용할 수 있습니다. 두 가지 방법은 이미 준비되어 있음으로써(데이터베이스 사용이 이미 최적화됨) 분해 및 샤딩과 같은 노력을 준비하는 데 도움이 됩니다.

graph LR Fe(기능 선택) --> D D[(데이터베이스)] --> De De[디블로팅] --> Dc Dc[분해] --> P P[파티셔닝] --> S S[샤딩] --> R P --> M M[마이크로서비스] --> R R{반복?} --> Fe style De fill:#fca326 style P fill:#fc6d26

동기: GitLab.com의 안정성과 성능

GitLab.com의 대형 테이블은 운영 및 개발 모두에 많은 문제를 일으킵니다. 이로 인해 여러 가지 문제가 발생합니다.

  1. 쿼리 시간 및 따라서 전체 응용 프로그램 성능이 저하됩니다.
  2. 테이블 유지 관리가 훨씬 더 비용이 많이 듭니다. GitLab.com에서는 대형 테이블에서만 일회성(하루에 한 번) 처리를 하고 진공 실행에는 많은 시간이 걸리므로 이는 다양한 부정적인 결과를 초래하며 매우 큰 테이블은 데이터베이스의 다른 부분에 영향을 미칠 수 있고 전체 응용 프로그램 성능에 영향을 줍니다.
  3. 대형 테이블의 데이터 이전은 구현하기가 훨씬 복잡하며 개발 오버헤드가 발생합니다. 이로 인해 GitLab.com에 안정성 문제를 야기할 가능성이 있고 대규모 데이터 집합에서 실행하는데 시간이 오래 걸립니다.
  4. 인덱스 크기가 상당히 큽니다. 이는 성능에 직접적인 영향을 미치며 인덱스의 작은 부분만 메모리에 유지되며 인덱스를 유지하기가 더 어려워집니다(재팩킹 고려).
  5. 인덱스 생성 시간이 상당히 증가합니다. 2021년에는 단일 B-Tree 인덱스에 최대 6시간이 걸립니다. 이는 우리의 자주 배포하는 능력에 영향을 미치고 진공 관련 문제(지연된 정리)를 야기합니다.
  6. 우리는 이를 해결하기 위해 많은 인덱스를 추가하지만, 이로 인해 결과적으로 상당한 오버헤드가 발생하며 쿼리 플래너를 혼란스럽게 할 수 있으며 많은 수의 인덱스는 설계 문제의 신호입니다.

예시

가장 두드러지게, ci_builds 테이블은 2021년 6월 기준으로 1.5TB이고, 연관된 31개의 인덱스가 있으며 이는 총 1TB의 크기를 갖습니다. 이 테이블의 디스크 크기는 현재 2.5TB입니다. 현재 이는 매월 300GB씩 증가하고 있습니다. 올해 말까지 이러한 조치를 취하지 않으면 크기가 5TB에 가까워질 것으로 생각됩니다.

다음 예시는 매우 큰 테이블이 종종 GitLab.com의 사건의 근본 원인으로 작용한다는 것을 보여줍니다.

  1. 자주 발생하고 오래 걸리는 진공 실행으로 CI 대기열의 쿼리 성능이 반복적으로 저하됨
  2. ci_builds와 같은 대형 테이블에서 인덱스 생성 소요 시간이 바쁜 시간에 따라 1.5시간에서 6시간 사이로 변동됩니다. 이 프로세스는 마이그레이션이 동기화로 실행되기 때문에 배포를 차단하여 우리의 자주 배포 능력을 감소시킵니다.
  3. 대규모 인덱스 생성은 데이터베이스 기본에 활동 폭주를 야기할 수 있습니다:
    1. merge_request_diff_commits 테이블에서: 높은 네트워크 포화로 인한 원인,
    2. 주말에 정기적인 재인덱싱 활동: 증가하는 WAL 큐(복구 목표에 영향을 줌),
    3. notes 테이블: 유지 보수 목적으로 GIN 트리그램 인덱스를 다시 생성하는 것이 거의 불가능하였으며, 첫 번째 시도에서 12시간 후에 중단되었습니다 다른 진공 작업을 차단하였습니다.

GitLab.com의 문제가 되는 테이블

2021년 6월 중순 기준으로 GitLab.com의 총 데이터 크기(인덱스 크기를 포함)에 따른 TOP30 테이블을 보여줍니다. table_size, index_size는 실제 데이터 및 연관된 인덱스의 디스크 크기이며 percentage_of_total_database_size는 총 테이블 크기 대비 데이터베이스 크기 비율을 나타냅니다.

우리는 현재 1TB 이상의 매우 큰 테이블이 있으며, 이러한 테이블은 매우 큰 인덱스를 갖는 경향이 있음을 볼 수 있습니다.

다른 관찰은 매우 많은 수의 인덱스를 갖는 테이블도 있고 그것의 총 인덱스 크기가 저장된 데이터보다 상당히 크다는 것입니다. 예를 들어, deployments는 30GB이며 추가 123GB의 인덱스 데이터가 24개의 인덱스에 걸쳐 분산되어 있습니다.

테이블 총 크기 테이블 크기 인덱스 크기 인덱스 수 데이터베이스 총 크기 대비 비율
ci_builds 2975 GB 1551 GB 941 GB 30 22.7
merge_request_diff_commits 1890 GB 1454 GB 414 GB 2 14.4
ci_build_trace_sections 1123 GB 542 GB 581 GB 3 8.6
notes 748 GB 390 GB 332 GB 13 5.7
merge_request_diff_files 575 GB 481 GB 88 GB 1 4.4
events 441 GB 95 GB 346 GB 12 3.4
ci_job_artifacts 397 GB 187 GB 210 GB 10 3.0
ci_pipelines 266 GB 66 GB 200 GB 23 2.0
taggings 238 GB 60 GB 179 GB 5 1.8
ci_builds_metadata 237 GB 88 GB 149 GB 5 1.8
issues 219 GB 47 GB 150 GB 28 1.7
web_hook_logs_202103 186 GB 122 GB 8416 MB 3 1.4
ci_stages 182 GB 58 GB 124 GB 6 1.4
web_hook_logs_202105 180 GB 115 GB 7868 MB 3 1.4
merge_requests 176 GB 44 GB 125 GB 36 1.3
web_hook_logs_202104 176 GB 115 GB 7472 MB 3 1.3
web_hook_logs_202101 169 GB 112 GB 7231 MB 3 1.3
web_hook_logs_202102 167 GB 111 GB 7106 MB 3 1.3
sent_notifications 166 GB 88 GB 79 GB 3 1.3
web_hook_logs_202011 163 GB 113 GB 7125 MB 3 1.2
push_event_payloads 162 GB 114 GB 48 GB 1 1.2
web_hook_logs_202012 159 GB 106 GB 6771 MB 3 1.2
web_hook_logs_202106 156 GB 101 GB 6752 MB 3 1.2
deployments 155 GB 30 GB 125 GB 24 1.2
web_hook_logs_202010 136 GB 98 GB 6116 MB 3 1.0
web_hook_logs_202009 114 GB 82 GB 5168 MB 3 0.9
security_findings 109 GB 21 GB 88 GB 8 0.8
web_hook_logs_202008 92 GB 66 GB 3983 MB 3 0.7
resource_label_events 66 GB 47 GB 19 GB 6 0.5
merge_request_diffs 63 GB 39 GB 22 GB 5 0.5

목표: GitLab.com의 모든 물리적 테이블은 인덱스를 포함하여 100GB 미만입니다.

참고: PostgreSQL 컨텍스트에서 물리적 테이블은 일반 테이블이나 파티셔닝된 테이블의 파티션 중 하나입니다.

운영 안정성을 유지하고 향상시키며 개발 부담을 줄이기 위해, GitLab.com의 물리적 테이블에 대한 테이블 크기가 100GB 미만을 목표로 합니다(인덱스를 포함). 이에는 다양한 이점이 있습니다.

  1. 쿼리 실행 성능 향상 및 더 안정적인 쿼리 계획
  2. VACUUM 실행 시간을 크게 줄이고 건강한 상태를 유지하기 위해 VACUUM 실행 빈도를 늘림 - 데이터베이스 주 서버에 대한 오버헤드 감소
  3. 인덱스 생성 시간이 크게 단축됨 (인덱스 당 읽어야 하는 데이터 양이 현저히 줄어듦)
  4. 인덱스 크기가 작아져 더 효율적으로 유지보수되고 메모리에 더 잘 맞음
  5. 데이터 이관이 이해하기 쉽고 구현 및 실행 시간이 짧아짐

이 목표는 실용적입니다: 테이블 크기는 기능 사용, 코드 변경 및 기타 요소에 따라 달라집니다. 시간이 지남에 따라 이러한 변화들이 일어날 수 있습니다. 우리가 한 번에 모든 것을 항상 엄격하게 제한할 수 있는 해결책을 항상 찾을 수 있는 것은 아닙니다. 이는 수용 가능하며 주로 GitLab.com의 상황을 통제하려는 것입니다. 노력을 GitLab.com의 상황에 맞추고 자주 재평가합니다.

시간이 지남에 따라 테이블 크기가 일정한 최대값을 가지도록 할 수 있는 변경 사항이 있지만, 이것이 반드시 그렇다고 말할 수는 없습니다. 예를 들어 테이블을 정적인 파티션 수로 분할하는 해시 파티셔닝을 고려해보세요. 시간이 지남에 따라 데이터 성장과 함께 개별 파티션도 크기가 커지고 결국 다시 임계 크기에 도달할 수 있습니다. 테이블 크기가 일정하도록 노력하지만 이러한 특성을 가지지 않는 더 쉬운 해결책을 제공해도 오랜 기간 동안 상황을 개선하는 데는 문제가 없습니다.

따라서 리팩터링 후 물리적 테이블의 목표 크기는 상황에 따라 다르며 이에 대한 엄격한 규칙은 없습니다. 특정 솔루션이 언제 물리적 테이블이 다시 100GB의 임계값에 도달할 것으로 예측할 수 있도록 데이터 성장과 예측을 고려하는 것이 좋습니다. 이를 통해 특정 솔루션이 언제 모델을 재검토해야 하는 지를 이해할 수 있습니다.

솔루션

테이블 크기를 줄이는 표준 솔루션이 없습니다. 많은 솔루션이 있습니다!

  1. 유지 : 필요 없는 데이터를 삭제하세요. 예를 들어 오래된 필요없는 레코드를 만료시킵니다.
  2. STI 제거 : 아직 single-table inheritance를 몇 군데에서 사용하고 있는데, 이것은 안티 패턴으로 간주됩니다. 이것을 재설계하여 데이터를 여러 테이블로 나눌 수 있습니다.
  3. 인덱스 최적화 : 불필요한 인덱스를 제거하고 가능하다면 중복되는 인덱스를 통합하세요.
  4. 데이터 유형 최적화 : 데이터 유형 결정을 검토하고 가능한 경우 데이터 유형을 최적화하세요 (예: enum 열에 텍스트 대신 정수 사용)
  5. 파티셔닝 : 공통 액세스 척도가 있는 경우 파티셔닝 계획을 적용하세요.
  6. 정규화 : 관계 모델링을 검토하고 중복 데이터를 제거하기 위해 정규화 기술을 적용하세요.
  7. 수직 테이블 분할 : 열 사용을 검토하고 테이블을 수직으로 분할하세요.
  8. 외부화 : 대형 데이터 유형을 데이터베이스에서 완전히 이동하세요. 예를 들어 JSON 문서는 필터링에 사용되지 않을 때 데이터베이스 외부, 예를 들어 객체 리포지터리에 더 잘 저장될 수 있습니다.

참고: 물리적 테이블 크기를 제한하려는 노력에도 불구하고, 성능 유지 또는 개선 또한 목표로 여깁니다.

정규화와 같은 솔루션에 대해 이것은 트레이드 오프입니다: 비정규화된 모델은 적절하게 사용될 때 쿼리 실행을 가속화시킬 수 있지만, 이는 테이블 크기를 희생하는 대가입니다. 모델을 정규화하거나 테이블을 분할하거나 데이터를 외부화할 때, 성능에 미치는 영향을 이해하고 성능에 중대한 영향을 미치지 않는 해결책을 찾기 위해 노력합니다.

노력의 예

다음은 몇 가지 예시입니다. 그 밖에도 Database efficiency 에픽 아래에서 더 많이 구성되어 있습니다.

  1. ci_builds의 인덱스 수 줄이기
  2. merge_request_diff_commits에서 커미터 및 작성자 세부 정보를 정규화하고 중복 제거하기 (https://gitlab.com/gitlab-org/gitlab/-/issues/331823)
  3. ci_build_trace_sections의 유지 전략 (https://gitlab.com/gitlab-org/gitlab/-/issues/32565#note_603138100)
  4. 오래된 CI 작업 메타데이터를 하드 삭제하는 워커 구현하기 (https://gitlab.com/gitlab-org/gitlab/-/issues/215646)
  5. merge_request_diff_files가 100GB 목표를 위반 (에픽) (https://gitlab.com/groups/gitlab-org/-/epics/6215)

목표

~group::database에 대한 에픽은 목표를 수립하고 전달하고 그에 도달하기 위해 필요한 변경 사항을 확인하고 제안하는 결정을 주도합니다. 이러한 변경 사항은 데이터를 소유한 해당 스테이지 그룹(및 해당 데이터를 사용하는 기능)이 주도하되, ~group::database가 지원해야 합니다.

담당자

문제가 되는 테이블에 대한 솔루션을 식별하는 데 기여하는 것은 GitLab 데이터베이스 팀 및 해당 스테이지 그룹입니다.

역할 담당자
저자 Andreas Brandl
엔지니어링 리더 Craig Gomes