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. As with all projects, the items mentioned on this page are subject to change or delay. The development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab Inc.
Status Authors Coach DRIs Owning Stage Created
proposed -

시간 감쇠 데이터

이 문서는 데이터베이스 확장성 워킹 그룹에서 도입된 시간 감쇠 패턴을 설명합니다. 시간 감쇠 데이터의 특성을 논의하고, GitLab 개발을 위해 이러한 맥락에서 고려해야 할 모범 사례를 제안합니다.

일부 데이터셋은 최근 데이터가 오래된 데이터보다 훨씬 더 자주 액세스되는 강한 시간 감쇠 효과를 받습니다. 시간 감쇠의 또 다른 측면은 시간이 지남에 따라 일부 유형의 데이터가 덜 중요해지는 것입니다. 이는 우리가 오래된 데이터를 상대적으로 덜 내구성(또는 덜 이용 가능)인 저장소로 이동하거나, 극단적인 경우에는 데이터를 삭제할 수도 있다는 것을 의미합니다.

이러한 영향들은 일반적으로 제품이나 애플리케이션 의미론적인 측면과 관련이 있습니다. 오래된 데이터가 액세스되는 정도와 사용자나 응용 프로그램에게 오래된 데이터가 얼마나 유용하거나 필수적인지에 따라 다를 수 있습니다.

우선 데이터의 시간 관련 편향이 없는 엔터티를 고려해 봅시다.

사용자나 프로젝트에 대한 레코드는 생성된 시점과 관계없이 동일하게 중요하고 자주 액세스될 수 있습니다. 사용자의 idcreated_at을 사용하여 해당 레코드가 얼마나 자주 액세스되거나 업데이트되는지를 예측할 수는 없습니다.

반면, 로그 및 시계열 데이터와 같은 시간 감쇠 효과가 극심한 데이터의 좋은 예는 사용자 작업 기록 이벤트를 기록한 것입니다.

대부분의 경우, 이러한 유형의 데이터는 몇 일이나 몇 주가 지나면 업무적인 용도가 없어지고, 데이터 분석적인 관점에서도 빠르게 중요성을 잃습니다. 이들은 빠르게 현재 응용 프로그램 상태와 거리가 멀어지는 스냅샷을 나타내다가 어느 순간부터는 실제 가치가 없어집니다.

두 극단 사이에서 초기 (짧은) 시간 간격 이후에는 오래된 레코드가 거의 액세스되지 않지만 유용한 정보를 포함하는 데이터셋을 찾을 수 있습니다.

시간 감쇠 데이터의 특성

다음과 같은 특성을 보이는 데이터셋에 관심이 있습니다:

  • 데이터셋의 크기: 상당히 큽니다.
  • 액세스 방법: 데이터셋에 액세스하는 쿼리를 대부분 시간 관련 차원이나 시간 감쇠 효과가 있는 범주형 차원으로 필터링할 수 있습니다.
  • 불변성: 시간 감쇠 상태는 변경되지 않습니다.
  • 유지: 오래된 데이터를 유지할 것인지, 오래된 데이터를 사용자가 응용 프로그램을 통해 계속 액세스할 수 있게 할 것인지 여부.

데이터셋의 크기

강한 시간 감쇠 효과를 보이는 다양한 크기의 데이터셋이 있을 수 있지만, 이 설계도의 맥락에서는 상당히 큰 데이터셋에 집중하기로 합니다.

더 작은 데이터셋은 데이터베이스 관련 자원 사용에 중요한 기여를 하지 않으며, 쿼리에 상당한 성능 저하를 초래하지 않습니다.

반면, 약 5천만 레코드 또는 100GB 이상의 크기에 해당하는 대규모 데이터셋은 실제로 데이터의 매우 작은 하위 집합을 지속적으로 액세스하는 중대한 오버헤드를 추가합니다. 이러한 경우에는 시간 감쇠 효과를 활용하여 활발하게 액세스되는 데이터셋을 줄이고 싶어합니다.

데이터 액세스 방법

시간 감쇠 데이터의 두 번째로 가장 중요한 특성은 대부분의 경우 데이터를 날짜 필터를 사용하여 암묵적 또는 명시적으로 액세스할 수 있다는 것입니다.

이러한 차원은 여러 개일 수 있지만, 우리는 가장 널리 사용되는 창조일만을 다루고, 조절하고 최적화할 수 있는 차원에만 초점을 맞출 것입니다. 이것은:

  • 불변합니다.
  • 레코드가 생성될 때 설정됩니다.
  • 레코드를 물리적으로 클러스터링하는데 활용할 수 있습니다.

시간 감쇠 데이터가 응용 프로그램에서 이러한 방식으로 액세스되지 않더라도 대부분의 쿼리가 명시적으로 데이터를 이러한 방식으로 필터링하도록 할 수 있습니다. 시간 감쇠 관련 액세스 방법이 없는 시간 감쇠 데이터는 최적화적 관점에서는 쓸모가 없습니다. 크기 조절 패턴을 설정하고 따를 방법이 없기 때문입니다.

매우 드물지만 응용 프로그램에서 기본적인 방식으로 이러한 방식으로 액세스되지 않는 시간 감쇠 데이터에 대해 몇 가지 예외 동작이 있을 수 있습니다. 이러한 경우에는 나머지 액세스 방법이 크기를 조절할 수 있다면 그러한 예외적인 동작을 수용할 수 있습니다. 예를 들어, 관리자가 특정 유형의 모든 이전 이벤트에 액세스하는 경우에는 다른 모든 작업이 6개월 전에 1개월간의 이벤트만 액세스하도록 제한된 상황 등이 있을 수 있습니다.

불변성

시간 감쇠 데이터의 세 번째 특성은 그들의 시간 감쇠 상태가 변경되지 않는다는 것입니다. 한 번 “오래된”으로 간주되면 “새로운” 상태로 다시 변경되거나 중요해질 수 없습니다.

이 정의는 당연한 것처럼 들릴 수 있지만, 우리는 “오래된” 데이터에 대해 연산을 수행할 수 있어야 합니다. 이러한 연산을 적용하여 데이터를 아카이빙하거나 덜 비싼 저장소로 이동시켜야 할 때에도 “새로운” 상태로 다시 변경하거나 중요한 응용프로그램 동작의 결과에 영향을 끼치지 않을 수 있어야 합니다.

시간 감쇠 데이터 액세스 패턴에 대한 반례로 문제가 업데이트된 순서로 이슈를 표시하는 응용 프로그램 뷰를 들 수 있습니다. “업데이트” 관점에서 가장 최근 데이터에 관심이 있지만, 이러한 정의는 불변성이 없으며 실질적으로 취할 수 있는 조치가 없습니다.

보존

마지막으로, 하위 카테고리별 시간 감소 데이터를 더 구분하는 특성은 이전 데이터를 유지할지 여부 (예: 보존 정책) 및/또는 응용 프로그램에서 이전 데이터에 사용자가 액세스할 수 있는지 여부와 같이 약간 다른 접근 방법을 사용할 수 있는지입니다.

(선택 사항) 시간 감소 데이터의 확장된 정의

패턴 기반의 접근성을 제한하도록 하는 접근 패턴을 데이터의 잘 정의된 하위 집합으로 제한하는 지금까지의 정의를 확장한다면 시간 감소 스케일링 패턴을 다른 유형의 데이터에도 사용할 수 있습니다.

예를 들어, 완료로 표시되지 않은 할 일, 병합되지 않은 병합 요청의 파이프라인(또는 유사한 시간 기반 제한 조건)과 같이 활성화된 상태라고 라벨이 지정된 동안에만 액세스되는 데이터를 고려해 보겠습니다. 이 경우, 감소를 정의하기 위해 시간 차원 대신 범주적인 차원(즉, 유한한 값 집합을 사용하는 차원)을 사용합니다. 해당 하위 집합이 데이터 집합의 전체 크기에 비해 작으면 같은 접근 방식을 사용할 수 있습니다.

비슷하게, 시간 차원과 CI 파이프라인과 같은 추가 상태 속성을 기반으로 데이터를 이전으로 정의할 수 있으며, 이러한 속성은 6개월 전에 실패한 CI 파이프라인과 같습니다.

시간 감소 데이터 전략

분할 테이블

이것은 순수한 데이터베이스 관점에서 시간 감소 데이터를 처리하는 대표적인 모범 사례입니다. PostgreSQL에 대한 테이블 분할에 대한 자세한 내용은 테이블 분할 문서에서 찾을 수 있습니다.

날짜 간격에 따라 분할(예: 월, 년)하여 매우 작은 테이블(분할)을 각 날짜 간격마다 생성하고, 모든 응용 프로그램 관련 작업에 대해 가장 최근의 분할만 액세스할 수 있습니다.

흥미 있는 날짜 간격에 따라 분할 키를 설정해야 하는 두 가지 요인에 따라 달라집니다.

  1. 과거에 액세스해야 하는 데이터가 얼마나 오랜 기간입니까? 매주 분할하는 것은 항상 1년 전 데이터에 액세스해야 하는 경우에는 쓸모가 없습니다. 이에 대한 예로는 GitLab 사용자의 프로필의 활동 피드를 고려하세요.

    반면에, 생성된 레코드의 마지막 7일만 액세스하려면 연 단위로 분할하는 것은 각 분할에 많은 불필요한 레코드를 포함하게 되어 낭비가 됩니다(web_hook_logs의 경우).

  2. 생성되는 분할이 얼마나 큽니까? 분할의 주요 목적은 가능한 한 작은 테이블에 액세스하는 것입니다. 단독으로 너무 커지면 쿼리 수행이 저하됩니다. 더 작은 분할로 다시 분할해야 할 수도 있습니다.

완벽한 분할 체계는 데이터 집합에 대한 모든 쿼리가 거의 항상 단일 분할에서 이루어지며, 일부 경우에는 2개의 분할 이상을 거치며 드물게 여러 분할을 경유하는 것이 합리적인 균형입니다. 또한 가능한 한 작은 분할, 최대 5-10M 레코드 및/또는 각각 최대 10GB 이하를 목표로해야 합니다.

분할은 이전 분할을 버리거나, 데이터를 더 싼 저장소로 이동하거나, 데이터베이스 외부로 이동하여(아카이빙 및 다른 유형의 저장 엔진 사용) 다른 전략과 결합하여 사용할 수 있습니다.

오래된 레코드를 유지하고자 하지 않고 분할을 사용하는 경우, 이전 데이터를 삭제하는 것과 비교해 이전 데이터를 자르는 것은 거의 제로 비용이 듭니다. 해당 분할 내 모든 데이터가 보존 정책 기간을 벗어나면 백그라운드 프로세스가 해당 분할을 삭제해야 합니다.

예를 들어, 6개월 이상 오래된 레코드만 유지하려는 경우, 월별로 분할하면 항상 최신 7개 분할을 안전하게 유지할 수 있습니다(현재 월 및 6개월 전). 즉, 매월 초에 8번째로 오래된 분할을 삭제하는 작업이 수행될 수 있습니다.

PostgreSQL에서 같은 데이터베이스 내에서 저렴한 저장소로 분할을 이동하는 것은 테이블 스페이스를 사용하여 상대적으로 간단합니다. 각 분할에 대해 테이블 스페이스 및 저장 매개변수를 별도로 지정할 수 있으므로, 이 경우의 접근 방법은 다음과 같습니다.

  1. 저렴하고 느린 디스크에 대한 새 테이블 스페이스 생성.
  2. PostgreSQL 옵티마이저가 디스크가 느리다는 것을 인지할 수 있도록 새 테이블 스페이스의 저장 매개변수를 더 높게 설정.
  3. 백그라운드 프로세스를 사용하여 이전 분할을 자동으로 느린 테이블 스페이스로 이동.

마지막으로, 데이터베이스 외부로 분할을 이동하는 것은 데이터베이스 아카이빙이나 데이터를 다른 저장 엔진(전용 하위 섹션에서 자세한 내용 참조)으로 수작업으로 내보내는 것으로 달성할 수 있습니다.

오래된 데이터 자르기

데이터를 어떤 형태에서도 오래 보관하고 싶지 않은 경우, 데이터 자르기 전략을 구현하여 오래된 데이터를 삭제할 수 있습니다.

이는 과거 데이터를 삭제하는 자르기 작업자를 사용하는 간단한 구현 전략입니다. 예를 들어 이후 자세히 분석할 예정인 web_hook_logs에서 90일 이전의 오래된 데이터를 자르고 있습니다.

대규모이자 분할되지 않은 테이블에 비해 이러한 솔루션의 단점은 더 이상 관련이 없는 모든 레코드에 대해 수동으로 액세스하고 삭제해야 한다는 것입니다. 이는 PostgreSQL의 다중 버전 동시성 제어로 인해 매우 비용이 많이 드는 작업입니다. 또한 이로 인해 자르기 작업자가 쓰기 임계값을 초과하는 새 레코드에 따라잡지 못할 수도 있습니다. 이는 이 문서 작성 당시 web_hook_logs의 경우에 해당됩니다.

위에서 언급한 이유로, 파티셔닝을 기반으로 데이터 보존 전략의 모든 구현을 해야 한다는 제안을 하고자 합니다, 강력한 이유가 없는 이상입니다.

데이터베이스 외부로 오래된 데이터 이동

대부분의 경우, 우리는 오래된 데이터를 값진 것으로 여기기 때문에 그것들을 가지고 싶지 않습니다. 동시에 그 데이터가 데이터베이스와 관련된 작업에 필요하지 않다면(예: 직접 액세스되거나 조인 및 기타 쿼리에서 사용되지 않는다면), 해당 데이터를 데이터베이스 외부로 이동할 수 있습니다.

그것은 사용자가 애플리케이션을 통해 직접적으로 접근할 수 없다는 것을 의미하지는 않습니다. 데이터를 데이터베이스 외부로 옮겨 다른 저장 엔진이나 액세스 유형을 사용하여 메타데이터를 언로드하는 것과 유사하게 오래된 데이터의 경우에만 수행할 수 있습니다.

가장 간단한 유스케이스에서는 최근 데이터에 대한 빠르고 직접적인 액세스를 제공할 수 있으며, 사용자가 오래된 데이터가 포함된 아카이브를 다운로드할 수 있도록 할 수 있습니다. 이것은 ‘audit_events’ 사용 사례에서 검토된 옵션입니다. 나라와 산업에 따라서 감사 이벤트는 매우 오래 유지되는 반면, 지나간 몇 달 동안의 데이터만이 GitLab 인터페이스에서 활발하게 액세스됩니다.

추가적인 사용 사례는 데이터를 데이터 웨어하우스나 다른 유형의 데이터 저장소로 내보내거나 처리할 수 있는 저장소에 더 적합한 경우를 포함할 수 있습니다. JSON 로그와 같은 예시는 때로는 테이블에 저장하지만, 해당 데이터를 BigQuery나 Redshift와 같은 칼럼형 저장소에 로드하는 것이 데이터를 분석하거나 쿼리하는 데 더 적합할 수 있습니다.

데이터를 데이터베이스 외부로 이동하는 데에는 여러 가지 전략을 고려할 수 있습니다:

  1. 해당 유형의 데이터를 로그로 스트리밍하고 나서 이를 보조 저장 옵션으로 이동하거나 CSV/JSON 데이터로 다른 유형의 데이터 저장소로 로드하는 것
  2. 데이터를 CSV로 내보내는 ETL 프로세스를 만들고, 객체 저장소에 업로드한 다음 이 데이터를 데이터베이스에서 삭제하고 CSV를 다른 데이터 저장소에 로드하는 것
  3. 데이터 저장소에서 제공하는 API를 사용하여 데이터를 백그라운드로 로드하는 것

대용량 데이터셋에 대해서는 이 방법이 비실용적일 수 있지만, 파일을 사용하여 대량 업로드가 가능한 한이 있는 한, API 호출보다 우수한 성능을 발휘해야 합니다.

사용 사례

웹 후크 로그

관련 이픽: 파티셔닝: web_hook_logs 테이블

web_hook_logs의 중요한 특성은 다음과 같습니다:

  1. 데이터셋 크기: 매우 큰 테이블입니다. 우리는 그것을 (2021-03-01)을 기준으로 파티셔닝하기로 결정했을 때, 대략 527M의 레코드와 전체 크기로 대략 1 TB였습니다

    • 테이블: web_hook_logs
    • 레코드: 대략 527M
    • 전체 크기: 1.02 TiB (10.46%)
    • 테이블 크기: 713.02 GiB (13.37%)
    • 인덱스 크기: 42.26 GiB (1.10%)
    • TOAST 크기: 279.01 GiB (38.56%)
  2. 액세스 방법: 항상 최대 7일 이내의 로그를 요청합니다.
  3. 불변성: created_at으로 파티셔닝할 수 있으며, 이 속성은 변하지 않습니다.
  4. 유지 기간: 90일의 유지 정책이 설정되어 있습니다.

또한 우리는 그 당시에 PruneWebHookLogsWorker라는 백그라운드 워커를 사용하여 데이터를 가지치기하려고 시도중이었는데, 이는 데이터 삽입률을 따라잡지 못했습니다.

결국, 2021년 3월에는 2020년 7월 이후에도 삭제되지 않은 레코드가 아직 있었으며, 테이블의 크기가 상대적으로 안정적인 크기를 유지하는 대신 하루에 2백만 건 이상의 레코드가 계속해서 증가했습니다.

마지막으로, 2021년 3월까지는 삽입률이 한 달에 170GB 이상으로 성장하였고 현재도 성장중이기 때문에 오래 된 데이터의 가지치기에 대한 유일한 실용적인 해결책은 파티셔닝이었습니다.

우리의 접근 방식은 90일의 유지 정책과 일치하도록 테이블을 월별로 파티셔닝하는 것이었습니다.

필요한 과정은 다음과 같습니다:

  1. 파티셔닝 키를 결정하기

    이러한 경우에 created_at 열을 사용하는 것은 직관적입니다: 유지 정책이 있으며 충돌하는 액세스 패턴이 없을 때 자연스러운 파티셔닝 키이기 때문입니다.

  2. 파티셔닝 키를 결정한 후에 파티션을 생성하고 백필을 진행합니다(기존 테이블에서 데이터 복사). 기존 테이블을 그대로 파티셔닝할 수는 없습니다. 새로운 파티셔닝된 테이블을 생성해야 합니다.

    따라서, 파티셔닝된 테이블 및 모든 관련 파티션을 생성하고 모든 것을 복사한 다음, 새로운 파티셔닝된 테이블에 대한 새로운 데이터나 기존 데이터의 업데이트/삭제가 동기화되도록 동기화 트리거를 추가해야 합니다.

    테이블을 파티셔닝하는 방법에 대한 모든 필요한 세부 정보가 있는 MR

    이 과정을 완료하는 데에는 15일 7.6시간이 소요되었습니다.

  3. 초기 파티셔닝 후에 마지막 단계, 백필링에 사용된 백그라운드 마이그레이션 후처리 및 나머지 작업 실행, 실패한 작업 다시 시도 등.

    모든 필요한 세부 정보가 있는 MR

  4. 파티셔닝된 테이블에 나머지 외래 키와 보조 인덱스 추가. 다음 단계에서 그 테이블을 교체하기 전에는 그것의 스키마를 기존의 비파티셔닝된 테이블과 동일하게 가져와야 합니다.

    이러한 작업은 삽입 시간이 추가적으로 소요되고 초기 백필링을 느리게 만들 수 있기 때문에 처음에는 추가하지 않습니다(이 경우에는 50억 건의 레코드에 대한 것이므로 상당히 누적될 수 있습니다). 간단한, 원시적인 버전의 테이블을 생성하고 모든 데이터를 복사한 다음 나머지 인덱스와 외래 키를 추가합니다.

  5. 파티셔닝된 복사본으로 기본 테이블을 교체: 이것은 파티셔닝된 테이블이 애플리케이션에서 활발하게 사용되기 시작하는 시점입니다.

    기본 테이블을 삭제하는 것은 파괴적인 작업이기 때문에, 프로세스 동안 문제가 없었는지 확인하려고 합니다. 따라서 우리는 이전의 비파티셔닝 테이블을 유지하고 있습니다. 또한 모든 작업에 대한 비파티셔닝 테이블이 여전히 최신 상태로 유지되도록 동기화 트리거를 반대로 전환하여야합니다. 그것은 필요한 경우 다시 테이블을 교체할 수 있도록 해줍니다.

    모든 필요한 세부 정보가 있는 MR

  6. 교체 후에 마지막 단계, 교체된 비파티셔닝 테이블 삭제

    모든 필요한 세부 정보가 있는 이슈

  7. 비파티셔닝 테이블이 삭제된 후에, 가지치기 전략을 구현하기 위한 워커를 추가

    이 경우에는 유지 정책이 90일이므로 항상 4개의 파티션만이 활성화되도록 워커를 설정하고, 4개월 이전의 파티션은 삭제합니다. 현재 달이 활성화되어 있는 동안에는 4개월치의 파티션을 유지해야합니다. 왜냐하면 90일 전으로 이동하면 네 번째로 오래된 파티션으로 이동하기 때문입니다.

감사 이벤트

관련 이픽: 파티셔닝: 감사 이벤트 파티셔닝 전략을 디자인하고 구현

audit_events 테이블은 이전 서브 섹션에서 논의된 web_hook_logs 테이블과 많은 특성을 공유하므로, 우리는 그들이 다른 점에 초점을 맞춥니다.

의견이 일치하는 바와 같이, 파티셔닝은 대부분의 성능 문제를 해결할 수 있다고 합니다.

대부분의 다른 대형 테이블과는 달리, 이 테이블은 주요 충돌하는 액세스 패턴이 없습니다: 우리는 액세스 패턴을 월별 파티셔닝에 맞추어 변경할 수 있었습니다. 예를 들어, 네임스페이스별로 파티셔닝 접근 방식을 정당화할 수 있는 다른 테이블의 경우에도 이렇지 않습니다. 그러나 다른 테이블들은 많은 충돌하는 액세스 패턴이 있기 때문에 파티셔닝 접근 방식을 정당화할 수는 있습니다.

게다가, audit_events는 매우 적은 쿼리를 통한 쓰기 중심의 테이블이며 매우 간단한 스키마를 갖고 있으며 데이터베이스의 나머지 부분과 연결되어 있지 않습니다(수신 또는 발신 FK 제약 조건 없음) 그리고 정의된 인덱스가 두 개뿐입니다.

나중에는, PostgreSQL 11에서 여전히 파티셔닝할 수 있었던 이유로써 외래 키 제약 조건이 없다는 것이 중요했습니다. 우리가 이제 필수 기본값으로 PostgreSQL 12로 이동했기 때문에 web_hook_logs 사용 사례에서 확인할 수 있듯이, 더는 이겨 걱정할 필요가 없습니다.

audit_events를 파티셔닝하기 위한 마이그레이션 및 필요한 단계는 web_hook_logs의 이전 섹션에서 설명한 것과 유사합니다. 현재 audit_events에 대한 보존 전략이 정의되어 있지 않으므로 그 위에 구현된 가치 평가 전략이 없지만, 우리는 미래에 아카이빙 솔루션을 구현할 수도 있습니다.

audit_events 사례에서 흥미로운 점은 우리가 파티셔닝의 최적의 쿼리를 촉진하기 위해 필요한 UI/UX 변경을 구현하기 위해 따라야 했던 단계에 대한 논의입니다. 파티셔닝과 관련된 시간 감소 액세스 방법과 모든 액세스 패턴을 일치시키기 위해 응용 프로그램 수준에서 요구되는 변경에 대한 시작점으로 활용할 수 있습니다.

CI 테이블

참고: CI 테이블 사용 사례의 요구 사항 및 분석: 여전히 진행 중인 작업입니다. 분석이 진행된 후에 자세한 내용을 추가할 예정입니다.