Status | Authors | Coach | DRIs | Owning Stage | Created |
---|---|---|---|---|---|
implemented |
@abrandl
|
@glopezfernandez
|
@fabian
@craig-gomes
| devops data stores | 2021-02-08 |
데이터베이스 테스트
주의: 이 설계안은 일부만 구현되었습니다. 여전히 도구 개선에 대해 계획 중입니다. 아래 내용은 개발 워크플로에 데이터베이스 테스트를 통합하기 전에 작성된 설계안의 이전 버전입니다.
일반적으로 되돌린 마이그레이션 핵심 테마를 확인했으며, 개발 환경에서 성공적으로 테스트한 것과는 다르게 프로덕션 및 스테이징에서 실패한 마이그레이션이 발견되었습니다. 또한 스테이징에서 성공적으로 테스트한 상태에서도 프로덕션에서 문제가 발생했습니다. 이러한 실패는 상당히 비용이 많이 들 수 있습니다. 이는 가용성에 상당한 영향을 미치며 배포를 차단하고 사건을 격상시킵니다. 이러한 격상을 분류하고 되돌리거나 고치는 것은 원래 작성자의 개입없이 시간대 및/또는 격상의 중요성으로 인해 종종 발생합니다. 증가된 배포 속도 및 엄격해진 가동 시간 요구 사항으로 인해 데이터베이스 테스트를 개선하는 필요성은 특히 개발 초기 단계(좌측 이동)에서 중요합니다.
개발자의 관점에서는 프로덕션으로 마이그레이션을 확인하는 것이 어렵거나 실현 가능하지 않을 수 있습니다.
우리의 주요 목표는 개발자에게 프로덕션 데이터베이스의 전체 사본에서 신규 마이그레이션 및 기타 데이터베이스 관련 변경 사항에 대한 즉각적인 피드백을 제공하고 이를 높은 효율성(특히 인프라 비용 측면)과 보안 측면에서 수행하는 것입니다.
현재
개발자는 어떤 환경에 배포하기 전에 데이터베이스 마이그레이션을 테스트하는 것을 기대됩니다. 그러나 우리는 GitLab.com과 같은 대형 환경에서 테스트를 수행할 수 있는 능력이 부족합니다. 개발자용 데이터베이스 마이그레이션 스타일 가이드는 마이그레이션에 대한 지침을 제공하며, 우리는 코드 검토 및 CI 및 스테이징에서 마이그레이션을 유효성 검사하는 데 중점을 두고 있습니다.
코드 검토 단계는 Database Reviewers 및 Maintainers가 커밋된 마이그레이션을 수동으로 확인하는 단계입니다. 이 과정은 주로 GitLab.com에서 문제가 있는 패턴을 파악하는 데 관련 경험을 토대로 하는 것을 포함합니다. 병합되기 전에 마이그레이션을 테스트할 수 있는 대규모 환경은 존재하지 않습니다.
CI에서의 테스트는 매우 작은 데이터베이스에서 수행됩니다. 주로 전진/후진 마이그레이션 일관성을 확인하고, 문제가 있는 패턴을 감지하고(RuboCop 규칙을 평가하여 정적 코드를 확인함) 다른 몇 가지 기술적인 확인 사항을 갖추고 있습니다(적절한 파일 추가 등). 다시 말해서, 일반적으로 코드나 다른 상당히 단순한 오류를 찾지만 일반적으로 유닛 테스트에서도 다루지 않습니다.
한 번 병합되면 마이그레이션은 스테이징 환경에 배포됩니다. 2021년 1월 기준으로 해당 데이터베이스의 크기는 프로덕션 데이터베이스 크기의 5% 미만이며 최근 데이터 분포는 프로덕션 사이트와 유사하지 않습니다. 종종 우리는 스테이징에서 성공하고 프로덕션에서 쿼리 타임아웃 또는 다른 예상치 못한 문제로 실패하는 마이그레이션을 볼 수 있습니다. 스테이징에서 문제를 찾았더라도 결합하는 것은 여전히 비용이 많이 들며 이상적으로는 이러한 문제를 개발 주기 초기에 가능한 한 빨리 잡고 싶습니다.
오늘날, 프로덕션 데이터베이스의 얇은 클론(아래 자세한 내용 참조)에서 작업하는 경험을 쌓았으며 이미 이를 사용하여 개발자에게 프로덕션 쿼리 계획, 최적화를 위한 자동화된 쿼리 피드백 및 제안을 제공하고 있습니다. 이는 Database Lab 및 Joe를 중심으로 하며 이는 Slack(챗옵스를 사용)과 postgres.ai를 통해 이루어집니다.
비전
개발자로서:
- GitLab 코드 변경 작업 중에 데이터 마이그레이션을 수행하고 무거운 데이터베이스 쿼리를 변경합니다.
- 내 코드를 푸시하고 병합 요청을 작성하고 설명에 예제 쿼리를 제공합니다.
- 파이프라인에서 데이터 마이그레이션을 수행하고 GitLab.com의 복사본과 비슷한 규모의 환경에서 쿼리를 조사합니다.
- 파이프라인이 완료되면 병합 요청에는 마이그레이션과 제공한 쿼리에 대한 상세한 피드백 및 정보가 포함됩니다. 이는 프로덕션 데이터베이스의 전체 복제를 기반으로 합니다.
데이터베이스 마이그레이션에 대한 정보 수집은 클론에서 실행 된 내용을 포함합니다:
- 전체 런타임.
- 마이그레이션에서 실행되는 쿼리에 대한 자세한 통계(쿼리 정규화 및 플롯 형식으로 표시된 빈도 및 실행 시간).
- 마이그레이션 중에서 발생하는 위험한 락(프로덕션에서 차단 상황을 초래할 수 있는 것).
데이터베이스 쿼리에 대해 자동으로 수집할 수 있는 것:
- 시각화와 함께 쿼리 계획.
- 실행 시간과 프로덕션에 대한 예측.
- Joe로부터 최적화 제안.
- 메모리와 IO 통계.
이러한 피드백을 받은 후:
- 데이터 마이그레이션의 성능 문제를 조사할 수 있습니다.
- 수정 사항을 푸시한 후 위의 주기를 반복하고 최종적으로 데이터베이스 검토를 위해 병합 요청을 보낼 수 있습니다. 데이터베이스 검토 중에 데이터베이스 리뷰어와 유지보수자는 도입된 변경 사항의 성능에 대한 판단을 내리기 위해 생성된 추가 정보를 모두 활용할 수 있습니다.
이 정보 수집은 보호되며 안전한 환경에서 수행되며, 프로덕션 데이터에는 무단 액세스가 없으며 이 환경에서 코드를 안전하게 실행할 수 있도록 합니다.
의도된 이점은 다음과 같습니다:
- 좌측 이동: 개발자가 GitLab.com에서 대규모 데이터베이스 성능을 이해하고 스스로 서비스하는 방법
- 실제 데이터베이스에서만 발생하는 오류 식별(불일치 또는 예기치 않은 패턴과 함께) 및 자동 정보 수집 단계를 자동화하여 코드 검토에 참여하는 모든 사람(개발자, 리뷰어, 유지보수자)들을 위한 관련 세부 정보를 자동으로 제공함으로써 모든 사람들에게 용이하게 만들기
기술 및 다음 단계
우리는 이미 thin-cloning 기술인 postgres.ai의 Database Lab을 사용하고 있습니다. 우리는 프로덕션 데이터와 최신 상태를 유지하는 PostgreSQL 복제본을 유지하지만 프로덕션 트래픽을 처리하지는 않습니다. 이것은 Database Lab을 실행하고 우리에게 프로덕션 데이터셋의 완전한 복제본을 빠르게(초 단위로) 생성할 수 있도록 해줍니다.
내부적으로 이는 ZFS에 기반하며 “thin-cloning 기술”을 구현합니다. 즉, ZFS 스냅샷을 사용하여 데이터를 복제하고, 복제된 데이터를 기반으로 한 완전한 읽기/쓰기 PostgreSQL 클러스터를 노출합니다. 이것이 thin clone이라고 불리며, 상당히 짧은 수명을 가지며 사용이 끝나면 곧 제거될 것입니다.
thin clone은 완전히 읽기/쓰기가 가능합니다. 이를 통해 마이그레이션을 실행할 수 있습니다.
Database Lab은 thin clone을 관리하기 위해 상호 작용할 수 있는 API를 제공합니다. 마이그레이션 및 쿼리 테스트를 자동화하기 위해 gitlab/gitlab-org
CI 파이프라인에 단계를 추가합니다. 이는 특정 병합 요청에 대해 다음 단계를 수행하는 자동화를 트리거합니다.
- 이 테스트 세션을 위해 프로덕션 데이터로 thin clone을 생성합니다.
- 병합 요청에서 GitLab 코드를 가져옵니다.
- 마이그레이션을 실행하고 해당 작업의 모든 필요한 정보를 수집합니다.
- 쿼리 테스트를 실행하고 해당 작업의 모든 필요한 정보를 수집합니다.
- 마이그레이션 및 쿼리 테스트의 결과를 병합 요청에 다시 보냅니다.
- thin clone을 파괴합니다.
단기
단기 목표는 일반적인 마이그레이션(일반적으로 스키마 변경)을 테스트하고 기존의 postgres.ai의 Database Lab 인스턴스를 사용하는 것에 중점을 두고 있습니다.
이 프로세스를 안전하게 유지하고 규정 준수 목표를 충족시키기 위해 러너 환경은 프로덕션 환경으로 취급되고 유사하게 잠겨 있으며, 모니터링되고 감사됩니다. 데이터베이스 유지 관리자만이 CI 파이프라인과 해당 작업 출력에 액세스할 수 있습니다. 다른 모든 사용자는 병합 요청에 다시 게시된 결과와 통계만 볼 수 있습니다.
우리는 내부 GitLab for Operations에 보안 CI 파이프라인을 구현하여 위에서 설명한 실행 단계를 추가합니다. 이 목표는 다음 문제를 해결하기 위해 이 파이프라인을 안전하게 유지하는 것입니다:
모든 사람(GitLab 팀/개발자)이 프로덕션 데이터가 포함된 thin-clone에서 임의의 코드를 실행할 수 있도록 하지만, 프로덕션 데이터를 강력하게 보호합니다.
우리는 네트워크 수준에서 GitLab Runner 인스턴스 및 해당 컨테이너를 잠그고, 컨테이너 내에서 GitLab Rails 코드(및 그 데이터베이스 마이그레이션)를 실행하는 동안 네트워크를 통해 데이터가 유출되지 않도록 합니다.
게다가, 우리는 Internal GitLab for Operations 파이프라인에서 작업 결과(코드에서 출력된 내용 포함)를 유지 관리자 및 소유자 수준으로만 볼 수 있도록 제한하고, 원본 MR에는 간략한 요약만 제공합니다. 작업에 문제나 오류가 있는 경우, MR을 검토하도록 할당된 데이터베이스 유지 관리자는 더 많은 세부 정보를 위해 원본 작업을 확인할 수 있습니다.
이 단계가 구현되면 이미 thin-cloned GitLab.com 데이터베이스에서 GitLab CI를 통해 자동으로 데이터베이스 마이그레이션을 실행하고 병합 요청 및 개발자에게 피드백을 제공할 수 있는 능력을 보유하게 됩니다. 피드백 내용은 시간이 흐름에 따라 발전할 것으로 예상되며, 지속적으로 추가할 수 있습니다.
우리는 참고용으로 파이프라인에 대한 MVC 스타일 구현과 파이프라인에서의 피드백이 포함된 예시 병합 요청을 이미 보유하고 있습니다.
단기 목표에 대한 자세한 내용은 이 Epic에서 확인할 수 있습니다.
중기 - 향상된 피드백, 쿼리 테스트 및 백그라운드 마이그레이션 테스트
중기적으로, 테스트 파이프라인이 병합 요청으로 돌아와서 쿼리 테스트를 포함한 보다 자세한 정보 수준으로 확장할 계획입니다. 이를 통해 데이터베이스 코드 검토 및 thin-clone 기술 사용 경험을 활용하고 이를 GitLab의 작업 흐름에 다시 적용합니다. 우리는 다양한 도구(postgres.ai
, joe
, Slack, 계획 시각화 등)에 대한 정보 수집 대신에 GitLab으로 이를 되돌리고 병합 요청에 직접 작업합니다.
둘째로, 백그라운드 마이그레이션 테스트도 커버할 계획입니다. 이들은 일반적으로 오랜 기간 동안 실행되도록 예약된 데이터 마이그레이션입니다. 예약 단계와 작업 실행 단계의 성공은 일반적으로 데이터 분배에 많이 의존하며, 이는 실제 프로덕션 데이터에서 이러한 마이그레이션을 실행할 때만 나타납니다. 백그라운드 마이그레이션에 대한 확신을 얻기 위해 다음 피드백을 제공할 계획입니다:
- 예약 단계 - 쿼리 통계(예: 쿼리 실행 시간 히스토그램), 작업 통계(작업 수, 전체 기간 등), 배치 사이즈.
- 실행 단계 - 일부 작업 인스턴스를 예시로 사용하여 쿼리 및 실행 시간 통계를 수집합니다.
장기적 - GitLab 제품에 통합
GitLab 자체에 이러한 기능을 추출하여 통합할 수 있는 기회가 있습니다. 예를 들어, 병합 요청을 쿼리 예제로 주석을 다는 것과 테스트 실행에서 수집한 피드백을 첨부하는 것은 병합 요청 설명과 댓글 대신에 일등 시민이 될 수 있습니다. 우리는 이러한 아이디어들을 초기 단계에서 사용되는 것을 보고 경험을 제품에 되돌리기 위해 그런 아이디어들을 평가할 계획입니다.
논의된 대안: 익명화
이 문제의 핵심에는 프로덕션 데이터 세트에서 (잠재적으로 임의의) 코드를 실행하는 데 대한 우려와 프로덕션 데이터의 안전한 보호가 있습니다. 위에서 논의된 접근 방식은 해당 코드의 출력에 대한 액세스를 강력하게 제한함으로써 이 문제를 해결합니다.
우리가 논의하고 포기한 대체적인 접근 방식은 “스크럽”하고 프로덕션 데이터를 익명화하는 것입니다. 이 아이디어는 데이터베이스에서 민감한 데이터를 제거하고 그 결과 데이터셋을 데이터베이스 테스트에 사용하는 것입니다. 하지만 이로 인해 포기한 이것에는 많은 단점이 있습니다:
- 익명화는 본질적으로 복잡합니다 - “스크럽된 복제본”이 실제로 공개에서 작동할 수 있는 안전한 해결책으로 보장하기가 어렵습니다. 서로 다른 데이터 유형은 서로 다른 익명화 기법이 필요할 수 있으며(예: JSON 필드 내의 민감한 정보 익명화), 한 번에 하나의 속성에만 초점을 맞추는 것으로는 데이터셋이 완전히 익명화되었음을 보장할 수 없습니다(예: 조인 공격 또는 타임스탬프를 사용하여 공개 프로필/프로젝트와 결합하여 사용자의 익명화를 탈취).
- 익명화는 민감한 속성으로 간주되고 있는 속성 집합을 추적하고 업데이트하기 위한 추가 프로세스가 필요하며, 데이터베이스 스키마가 변경될 때마다 지속적인 유지보수 및 보안 검토가 필요합니다.
- 데이터를 “민감한”으로 주석 처리하는 것은 오류를 유발하며, 잘못된 익명화 접근 방식이 데이터 유형에 사용되거나 하나의 민감한 속성이 실수로 그렇지 않게 표시된 경우에는 데이터 침해로 이어질 수 있습니다.
- 스크럽은 민감한 데이터뿐만 아니라 데이터 분포도 변경시키며, 마이그레이션 및 쿼리의 성능에 큰 영향을 미칩니다.
- 스크럽은 데이터베이스 내용을 심각하게 변경시키고, 많은 양의 데이터를 업데이트할 수 있으므로 서로 다른 데이터 저장 세부 정보(예: MVC 팽창)로 이어지며, 마이그레이션 및 쿼리의 성능에 영향을 줍니다.