올해 초 우리는 회사 최대 규모의 프로젝트에 착수했습니다.
당연히 우리는 TimescaleDB를 핵심으로 하는 성숙한 클라우드 플랫폼인 Timescale을 선택했습니다. 우리는 PostgreSQL 작업에 익숙하며 PostgreSQL을 더 빠르고 확장 가능하게 만들기 위해 TimescaleDB를 구축했습니다. 우리 자신의 예를 따르는 것보다 더 나은 것은 무엇입니까?
이 Dogfooding 실험을 설명하는 가장 쉬운 방법은 규모를 정량화하는 데 도움이 되는 숫자를 사용하는 것입니다. Insights를 구축하려면 지속적으로 실행되는 프로덕션 데이터베이스 전체에서 쿼리 정보를 수집해야 했습니다. 우리는 플랫폼에서 개별(삭제된) 쿼리에 대한 1조 개 이상의 기록을 신속하게 수집했습니다.
이제 Insights가 프로덕션 단계에 있으므로 우리는 하루에 100억 개가 넘는 새로운 기록을 수집하고 있습니다. 단일 Timescale 서비스에서 제공하는 데이터 세트는 매일 약 3TB 씩 증가하여 현재 총 350TB 가 넘으며 동일한 데이터베이스 서비스가 모든 고객의 실시간 대시보드를 지원합니다.
이 블로그 게시물에서는 Insights 구축 과정에 대한 비하인드 스토리를 제공합니다. 이 규모로 운영한다는 것은 단일 Timescale 서비스의 한계를 뛰어넘고 PostgreSQL뿐만 아니라 개발자의 공감도 확장하는 것을 의미했습니다. 우리는 작업보다 Timescale을 더 많이 찾았지만 개선하고 싶은 영역도 있습니다!
Insights를 실현하기 위해 우리는 데이터베이스 관리자 모자를 쓰고🤠 PostgreSQL을 수 테라바이트의 데이터로 확장하기 위한 몇 가지 기술적 과제를 해결해야 했습니다. 우리는 "특별한" 인프라 없이 플랫폼에서 호스팅되는 Timescale 서비스를 중앙 데이터베이스로 사용하고 싶었습니다. 이는 다음을 의미합니다.
우리는 하루에 수십억 개의 레코드를 단일 Timescale 서비스로 수집할 수 있는 파이프라인을 구축해야 했습니다. Timescale은 높은 수집 속도를 처리할 수 있으며 고객을 위해 정기적으로 처리하지만 프로덕션 쿼리 로드 시 이러한 수준의 규모는 항상 눈살을 찌푸리게 합니다.
우리 고객은 Insights가 제공하는 모든 분석을 강화할 수 있는 유연성으로 이 데이터베이스에 쿼리할 수 있어야 했으며, 우리는 고객이 응답을 몇 분씩 기다리게 만들고 싶지 않았습니다.
매일 몇 TB가 추가되므로 단일 Timescale 서비스에 수백 TB를 저장해야 했습니다. 오래된 데이터(즉, 몇 주 이상 된 데이터)에 액세스할 수 있어야 했지만 쿼리 속도가 반드시 빠르지는 않았습니다.
데이터 수집 측면에서 우리는 Timescale 플랫폼의 아키텍처를 활용했습니다. Timescale은 Kubernetes(k8s)에서 실행되며 여러 지리적 지역에서 실행되는 여러 k8s 클러스터가 있습니다. 이러한 클러스터에는 하나 이상의 고객 데이터베이스 서비스를 보유하는 노드가 있습니다. 모든 데이터베이스에 대한 쿼리 실행을 수집하기 위해 해당 데이터베이스에서 지역 수준으로 버블링한 다음 Insights를 지원하는 Timescale 데이터베이스 서비스에 레코드 배치를 저장하는 지역 작성자를 보유합니다.
낮은 수준의 잔혹한 세부 사항을 피하기 위해 수작업을 많이 해야 한다는 점을 이해하십시오. 그러나 넓은 의미에서 이것이 작동 방식입니다. 플릿 전체에서 실행되는 각 데이터베이스는 다음을 포함하여 모든 쿼리 후에 레코드(개인 정보 보호 및 보안을 위해 삭제됨)를 생성하도록 계측됩니다. 쿼리 자체와 우리가 관심을 갖는 통계입니다.
이러한 레코드는 노드 수준에서 수집되고, 해당 레코드가 어떤 데이터베이스 서비스에서 왔는지 연결되도록 레이블로 태그가 지정되며, 일괄 처리되어 지역 작성자에게 전송됩니다. 지역 기록기 서비스는 각 지역의 로드를 처리하기 위해 필요에 따라 복제됩니다. 각 작성자는 각 클러스터의 노드에서 배치를 수집하고 더 큰 배치를 만듭니다.
그런 다음 먼저 `COPY`를 사용하여 이러한 대규모 배치를 임시 테이블에 기록합니다(Write-Ahead Logging 없음 = 빠름). 그런 다음 해당 임시 테이블의 항목을 사용하여 필요한 테이블을 업데이트합니다(아래 참조). 임시 테이블을 사용하면 임시 테이블의 레코드를 삭제하는 후속 작업에 의해 처리되는 중복에 대해 걱정하지 않고 'COPY'를 사용할 수 있습니다.
요약하면 다음과 같습니다.
Insights를 지원하는 데이터베이스를 확대해 보겠습니다. 우리는 "기성품" Timescale 서비스에서 Insights를 실행하고 있습니다.
Insights를 지원하는 데이터베이스는 꽤 많은 부분으로 구성되어 있지만 가장 중요한 부분을 강조해 보겠습니다.
첫째, "참조 테이블" 역할을 하는 두 개의 일반 PostgreSQL 테이블이 있습니다. 이러한 테이블에는 정보 데이터베이스 메타데이터와 쿼리 문자열 메타데이터가 포함되어 있습니다. (의사) 스키마는 다음과 같습니다.
데이터베이스 메타데이터
Table "insights.cloud_db" Column | Type | Collation | Nullable | Default ---------------+--------------------------+-----------+----------+-------------------------------------- id | bigint | | not null | nextval('cloud_db_id_seq'::regclass) service_id | text | | not null | project_id | text | | not null | created | timestamp with time zone | | not null | now() Indexes: "cloud_db_pkey" PRIMARY KEY, btree (id) "cloud_db_project_id_service_id_key" UNIQUE CONSTRAINT, btree (project_id, service_id)
메타데이터 쿼리
Table "insights.queries" Column | Type | Collation | Nullable | Default ---------------+--------------------------+-----------+----------+-------------------------------------- hash | text | | not null | normalized_query | text | | not null | created | timestamp with time zone | | not null | now() Indexes: "queries_pkey" PRIMARY KEY, btree (hash)
새 데이터베이스에서 쿼리가 실행되기 시작할 때마다 `insights.cloud_db`에 추가됩니다. 새로운 정규화된 쿼리가 실행될 때마다 `insights.queries`에 추가됩니다.
(정규화된 쿼리란 무엇입니까? 모든 상수가 자리 표시자로 대체된 쿼리입니다. 첫 번째는 $1, 두 번째는 $2 등이므로 쿼리의 값이 아닌 "모양"만 볼 수 있습니다. .)
지금까지는 Timescale 비밀 소스 없이 일반 Postgres를 사용하고 있습니다. 그러나 데이터베이스의 다른 중요한 개체는 TimescaleDB에 고유하여 PostgreSQL을 다른 수준으로 확장하는 데 도움이 됩니다. 하이퍼테이블과 연속 집계가 바로 마법이 일어나는 곳입니다.
하이퍼테이블은 Timescale의 자동으로 분할된 테이블입니다. 데이터가 수집되는 동안 데이터를 차원별로 자동으로 분할하므로 PostgreSQL 테이블을 대규모로 확장하는 것이 훨씬 더 쉬워집니다. 하이퍼테이블은 Timescale의 구성 요소입니다. 나중에 살펴보겠지만 쿼리 통계 측정항목을 거대한 하이퍼테이블에 저장하고 있습니다.
연속 집계는 PostgreSQL 구체화된 뷰의 Timescale의 향상된 버전으로, 증분 및 자동 구체화를 허용하며 Insights를 구축할 때 매우 유용한 것으로 입증되었습니다.
사용자 측에서 빠른 분석 쿼리를 가능하게 하기 위해 이러한 기능을 어떻게 사용했는지 살펴보겠습니다.
앞서 말했듯이 우리는 모든 쿼리 실행에 대한 정보를 저장하기 위해 대형 하이퍼테이블을 사용합니다. 이 하이퍼테이블은 정리된 원시 측정항목이 있는 기본 테이블입니다. 이는 다음과 유사하며 타임스탬프 열( created
)을 사용하여 데이터가 수집될 때 자동으로 분할하도록 구성됩니다.
Table "insights.records" Column | Type | Collation | Nullable | Default -----------------------------+--------------------------+-----------+----------+--------- cloud_db_id | bigint | | not null | query_hash | text | | | created | timestamp with time zone | | not null | total_time | bigint | | | rows | bigint | | | ...
이 예에서는 많은 통계를 생략했지만 아이디어를 얻으실 수 있습니다.
이제 사용자 측에서 빠른 쿼리를 허용해야 하지만 이 테이블은 엄청납니다. 작업 속도를 높이기 위해 우리는 연속 집계(다음을 사용)에 크게 의존했습니다.
지속적인 집계는 Insights와 같은 실시간 사용자 대면 분석을 제공하는 제품에서 매우 의미가 있습니다. 사용자에게 실행 가능한 정보를 제공하려면 측정항목을 집계해야 합니다. 사용자에게 실행한 모든 쿼리에 대한 로그를 옆에 통계와 함께 표시하는 것은 아닙니다. 일부 데이터베이스는 초당 수천 개의 쿼리를 수행하므로 찾기란 악몽일 것입니다. 유용한 것. 대신, 우리는 사용자 집계를 제공하고 있습니다.
따라서 원시 개인 기록을 사용자에게 표시하지 않고 결과를 유지한다는 사실을 활용하는 것이 좋습니다.
PostgreSQL 구체화된 뷰를 사용할 수도 있었지만 Timescale의 연속 집계에는 특히 우리에게 유용한 몇 가지 장점이 있습니다. 보기를 많이 새로 고치고 연속 집계에는 자동 새로 고침을 위한 기본 제공 정책이 있으며 증분식으로 새로 고쳐집니다.
5분마다 뷰를 새로 고치므로 5분마다 전체 구체화된 정보를 다시 생성하는 대신 연속 집계가 원본 테이블의 변경 사항을 추적하여 뷰를 점진적으로 업데이트합니다. 우리가 운영하고 있는 규모에서는 5분마다 기본 하이퍼테이블을 위에서 아래로 스캔할 여유가 없기 때문에 이 연속 집계 기능은 우리에게 근본적인 "잠금 해제" 기능이었습니다.
백그라운드에서 Insights를 지원하는 이러한 지속적인 집계에서 우리는 또한 대부분의 흥미로운 통계를
그러나 어느 시점에서 데이터베이스는 이러한 모든 원시 레코드를 삽입한 다음 서비스를 위해 구체화하기 위해 많은 작업을 시작했습니다. 우리는 섭취하고 유지할 수 있는 양에 대해 몇 가지 제한 사항에 직면했습니다.
수집 속도를 필요한 수준으로 더욱 높이기 위해 UDDSketch 생성을 데이터베이스에서 지역 작성자로 오프로드했습니다. 이제 우리는 여전히 일부 레코드를 "원시" 레코드로 저장하지만 나머지는 데이터베이스에 저장하는 사전 생성된 스케치에 푸시합니다.
Table "insights.sketches" Column | Type | Collation | Nullable | Default -----------------------------+--------------------------+-----------+----------+--------- cloud_db_id | bigint | | not null | query_hash | text | | | created | timestamp with time zone | | not null | total_time_dist | uddsketch | | | rows_dist | uddsketch | | | ...
UDDSketchs의 가장 좋은 부분은 더 큰 시간 범위를 지원하기 위해 스케치를 지속적으로 "롤업"하는 것이 매우 쉽다는 것입니다. 이러한 롤업을 사용하면 계층적 연속 집계를 구축할 때와 쿼리 시 모두 더 좁은 시간 범위를 포함하는 스케치를 넓은 시간 범위를 포함하는 스케치로 집계할 수 있습니다.
빠른 수집과 쿼리를 보장하기 위해 우리가 활용한 또 다른 도구는 읽기 복제본입니다. Insights가 Timescale 플랫폼의 주요 고객 대면 기능을 지원한다는 점을 고려할 때 복제를 사용하는 것은 우리의 경우 고가용성과 성능 모두에 가장 중요합니다.
우리의 기본 데이터베이스 인스턴스는 대량 작업, 데이터 쓰기, 연속 집계 구체화, 압축 실행 등으로 매우 바쁩니다. (압축에 대해서는 잠시 후에 자세히 설명합니다.) 일부 로드를 완화하기 위해 복제본 서비스 고객이 Insights 콘솔에서 요청을 읽을 수 있도록 했습니다.
마지막으로 우리는 수백 TB를 단일 Timescale 서비스에 편안하게 맞춰야 했습니다. Insights 데이터베이스는 빠르게 확장되고 있습니다. 시작했을 때는 100TB 정도였지만 지금은 350TB를 넘고 있습니다(계속 증가 중).
그만큼 많은 데이터를 효율적으로 저장하기 위해
우리는 메인 하이퍼테이블에서 20배 이상의 압축률 을 목격하고 있습니다.
매우 큰 하이퍼테이블을 관리할 때 얻을 수 있는 또 다른 큰 이점은 압축된 데이터의 스키마 변경 가능성이었습니다. 이전 섹션에서 대략적인 스키마를 설명했지만 상상할 수 있듯이 더 많은 통계 등을 추가하기 위해 스키마를 자주 변경하고 있습니다. 압축된 하이퍼테이블에서 이 작업을 직접 수행할 수 있다는 것은 매우 유용합니다.
우리는 또한 Timescale의 데이터 계층화를 많이 사용하고 있습니다. 이 기능은 올해 초 조기 액세스에 들어갔으며(곧 GA 소식을 기다리세요 🔥) 이를 통해 Timescale 데이터베이스를 통해 수백 TB에 액세스할 수 있습니다. 데이터 계층화도 매우 효율적인 것으로 입증되었습니다. 여기서도 130TB가 리소스 효율성이 매우 높은 5TB로 축소되어 놀라운 압축률을 볼 수 있습니다.
Insights를 구축하는 과정은 우리 제품이 실제로 얼마나 멀리까지 갈 수 있는지를 보여 주었지만 가장 좋은 점은 고객의 입장에서 몇 마일을 걷는 것이었습니다. 우리는 Timescale을 사용하여 PostgreSQL을 확장하는 사용자 경험에 대해 많은 것을 배웠으며 제품 뒤에 있는 엔지니어로서 해야 할 일 목록에 몇 가지 사항을 추가했습니다.
좋은 점과 그저 그런 점을 모두 살펴 보겠습니다.
우리의 겸손하지 못함을 용서하십시오. 그러나 때때로 우리는 우리 제품에 대해 꽤 자랑스러워했습니다. 이미 수백 TB에 달하는 단일 PostgreSQL 데이터베이스에 매일 수백억 개의 레코드를 수집하는 것은 전혀 비관할 일이 아닙니다 . 데이터베이스가 확장되기 시작했을 때 데이터베이스를 조정하는 데 몇 주를 소비했지만 이제는 돌보거나 지속적인 모니터링 없이도 작동합니다 . (모니터링되지 않는 것과는 다르며 확실히 모니터링됩니다!)
우리의
압축은 우리에게 매우 효과적이었습니다. 이전 섹션에서 공유한 것처럼 간단한 단일 `segmentby` 옵션을 사용하여 인상적인 압축률(20배!)을 얻었습니다. 우리에게는 정책을 설정하고 조정하는 경험이 어렵지 않았습니다. 물론 이 기능을 구축했지만… 약간의 우위가 있다고 말할 수도 있습니다. 🙂 또한 압축된 데이터에 새 열을 원활하게 추가하는 기능으로 데이터베이스의 유연성과 적응성이 더욱 향상되었습니다. 우리는 이 기능을 문제 없이 사용했습니다.
연속 집계는 다양한 기간을 구성하는 논리를 단순화하고 데이터 분석 및 처리를 간소화합니다. 우리는 수많은 계층적 연속 집계를 사용했습니다.
Timecale의 초함수에 포함된 근사 알고리즘은 구현을 단순화하고 분석을 크게 확장했습니다. 스케치를 쉽게 롤업하는 기능은 고객이 대면하는 Insights 대시보드에서 다양한 시간 범위와 시간 버킷 세분화를 효율적으로 지원하는 데에도 핵심이었습니다.
Timescale 데이터베이스가 데이터 계층화를 통해 처리할 수 있는 "무한한" 웜 스토리지는 수백 TB로 확장하고 충분한 여유 공간을 확보하는 데 매우 중요했습니다. 현재 __ 데이터 계층화 정책 __핫 스토리지에 3주간의 기록을 보관합니다.
마지막으로 관찰 가능성(예: 작업 기록 모니터링)을 향상하고 실험적인 새로 고침 전략을 구현하기 위해 사용자 정의 작업을 생성하는 기능을 사용했습니다.
좋은 점을 모두 말한 후에는 별로 좋지 않은 점을 인정할 차례입니다. Timescale을 포함하여 완벽한 것은 없습니다. 파이프라인을 구현하는 동안 몇 가지 문제에 직면했지만 이것이 불만 사항이라는 의미는 아닙니다.
특히 작업 및 연속 집계 구현 성능과 관련하여 Timescale 플랫폼에서 데이터베이스 관찰 가능성이 향상될 수 있습니다.
TimescaleDB는 대부분 스냅샷 기반 보기를 제공하므로 시간에 따른 성능과 추세를 이해하기가 어렵습니다. 예를 들어, 기본적으로 제공되는 "작업 기록" 테이블이 없습니다. 초기에 우리는 지속적인 집계의 점진적인 구체화에 시간이 점점 더 오래 걸리는 것처럼 보였고 결국 버그 발견으로 이어졌지만 범위를 확인하거나 정량화할 방법이 없었습니다.
이전에 언급했듯이 사용자 정의 작업을 정의하고 Timescale의 작업 프레임워크 내에서 실행하는 기능을 통해 "충분히 좋은" 버전을 만들 수 있었습니다. 우리는 시간이 지남에 따라 모니터링하려는 뷰를 지속적으로 쿼리하고 변경 사항을 하이퍼테이블에 삽입했습니다. 이는 현재 Insights에서 작동하지만 Timescale을 모든 것이 항상 빠르다는 시점을 넘어 확장하면 중요하다고 생각하기 때문에 이러한 기능 중 일부를 내장 기능으로 전환하기 위해 노력하고 있습니다. .
기본 데이터가 클 경우 연속 집계를 올바르게 수행하는 것이 까다로울 수 있습니다 .
연속 집계를 생성할 때 `__ WITH NO DATA` 옵션을 사용하는 것은 __생명의 은인입니다. 점진적으로 새로 고치는 데이터의 양이 실수로 너무 커지지 않도록 새로 고침 정책에 대한 오프셋을 신중하게 결정하는 것도 중요합니다.
이 조언을 따른다고 해도 구체화하려는 데이터의 양보다 새로 고치는 데 더 오랜 시간이 걸리는 연속 집계가 발생할 수 있습니다(예: 15분의 데이터를 구체화하는 데 30분이 소요됨). 이는 연속 집계 기본 작업이 너무 커서 메모리에 맞지 않고 디스크로 유출되는 경우가 있기 때문에 발생합니다.
이 문제가 발생했는데, 이는 궁극적으로 구체화에 데이터를 제공하지 않는 경우에도 추가 청크가 쿼리 계획에 포함되도록 하는 off-by-one 버그(현재 수정됨)로 인해 더욱 악화되었습니다. 이 버그를 발견한 것은 실제로 "dogfoodception"의 사례였습니다. 우리는 Insights를 구축하면서 이 성능 문제를 발견했습니다 🤯. Insights에서 본 타이밍 정보는 여기에 뭔가 잘못되었음을 시사했으며 EXPLAIN을 사용하고 계획을 살펴봄으로써 문제를 발견했습니다. 그래서 우리는 그것이 효과가 있다고 말할 수 있습니다!
구체화를 더 빠르게 하기 위해 우리는 새로 고칠 증분 크기를 제한하는 사용자 지정 증분 새로 고침 정책을 만들었습니다. 우리는 이것이 TimescaleDB로 다시 일반화할 수 있는지 알아보기 위해 노력하고 있습니다.
변화는 규모에 따라 어렵습니다 .
데이터가 특정 크기에 도달하면 TimescaleDB의 일부 DDL(스키마 수정) 작업이 이상적인 것보다 더 많은 시간이 걸릴 수 있습니다. 우리는 이미 몇 가지 방법으로 이것을 경험했습니다.
예를 들어 대규모 하이퍼테이블에 새 인덱스를 추가하는 것은 타이밍 연습이 됩니다. TimescaleDB는 현재 `CREATE INDEX`와 함께 `CONCURRENTLY` 사용을 지원하지 않기 때문에 차선책은 내장된 방법을 사용하여 한 번에 한 청크씩 인덱스를 생성하는 것입니다. 우리의 경우 새 청크가 만들어진 직후에 시작해야 하므로 "활성" 청크에 대한 잠금은 최소화됩니다. 즉, 청크가 새 것일 때 인덱스를 생성한다는 것은 해당 청크가 (거의) 비어 있으므로 빠르게 완료할 수 있고 새 삽입을 차단하지 않는다는 것을 의미합니다.
변경이 어려운 또 다른 방법은 연속 집계를 업데이트하여 새 측정항목(열)을 추가하는 경우입니다. 연속 집계는 현재 'ALTER'를 지원하지 않습니다. 따라서 사용자에게 새로운 측정항목을 노출하려는 경우 연속 집계의 완전히 새로운 "버전"을 생성합니다. 즉, 연속 집계 "foo"의 경우 "foo_v2", "foo_v3" 등을 갖게 됩니다. 이는 다음과 같습니다. 이상적이지는 않지만 현재 작동 중입니다.
마지막으로 압축 설정을 변경하는 것은 규모에 따라 상당히 어렵습니다. 실제로 현재로서는 사실상 불가능합니다. 압축된 모든 청크의 압축을 풀고 설정을 변경한 다음 다시 압축해야 하기 때문입니다. 이는 현재 규모에서는 불가능합니다.
우리는 이 모든 문제에 대한 실행 가능한 솔루션을 찾기 위해 동료들과 계속해서 브레인스토밍을 하고 있습니다. 우리뿐만 아니라 모든 Timescale 사용자를 위한 것입니다.
한 포스팅에 다 담기에는 꽤 많은 정보였습니다. 하지만 필요한 경우
Insights 구축은 우리 팀에게 심오한 경험이었습니다. 우리는 Timescale을 얼마나 멀리까지 끌어올려 인상적인 규모의 숫자로 만들 수 있는지 직접 확인했습니다. 그 과정에서 우리가 직면한 문제점은 우리에게 많은 고객 공감을 안겨주었습니다. 이것이 바로 Dogfooding의 아름다움입니다.
내년에는 우리가 훨씬 더 많은 데이터베이스를 모니터링하는 방법과 Timescale을 사용하여 대규모로 작업하는 경험을 지속적으로 개선하는 방법에 대한 또 다른 블로그 게시물을 작성하고 싶습니다.
그때 만나! 👋
여기에도 게시되었습니다 .