Amazon Timestream for LiveAnalytics와 유사한 기능을 원하는 경우 Amazon Timestream for InfluxDB를 고려해 보세요. 간소화된 데이터 수집과 실시간 분석을 위한 10밀리초 미만의 쿼리 응답 시간을 제공합니다. 여기에서 자세히 알아보세요.
기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.
데이터 모델링
Amazon Timestream for LiveAnalytics는 타임스탬프가 포함된 일련의 데이터를 내보내는 애플리케이션과 디바이스에서 시계열 데이터를 수집, 저장 및 분석하도록 설계되었습니다. 최적의 성능을 위해 Timestream for LiveAnalytics로 전송되는 데이터는 시간적 특성을 가져야 하며 시간은 데이터의 핵심 구성 요소여야 합니다.
Timestream for LiveAnalytics는 애플리케이션의 요구 사항에 맞게 데이터를 다양한 방식으로 모델링할 수 있는 유연성을 제공합니다. 이 섹션에서는 이러한 패턴 중 몇 가지를 다루고 비용과 성능을 최적화할 수 있는 지침을 제공합니다. 차원과 측정 등의 주요 Amazon Timestream for LiveAnalytics 개념을 숙지하세요. 이 섹션에서는 데이터를 저장하기 위해 단일 테이블을 생성할지 아니면 여러 테이블을 생성할지 결정할 때 다음 사항에 대해 자세히 알아봅니다.
-
동일한 테이블에 넣을 데이터와 여러 테이블 및 데이터베이스에 걸쳐 데이터를 분리하려는 경우 비교
-
Timestream for LiveAnalytics 다중 측정 레코드와 단일 측정 레코드 중 선택하는 방법 및 특히 애플리케이션에서 여러 측정값을 동시에 추적할 때 다중 측정 레코드를 사용한 모델링의 이점
-
어떤 속성을 차원 또는 측정으로 모델링할지
-
측정 이름 속성을 효과적으로 사용하여 쿼리 지연 시간을 최적화하는 방법
단일 테이블과 여러 테이블 비교
애플리케이션에서 데이터를 모델링할 때 또 다른 중요한 측면은 데이터를 테이블과 데이터베이스로 모델링하는 방법입니다. Timestream for LiveAnalytics의 데이터베이스와 테이블은 액세스 제어를 위한 추상화 개념으로서, KMS 키, 보존 기간 등을 지정합니다. Timestream for LiveAnalytics는 데이터를 자동으로 파티셔닝하며 애플리케이션의 수집, 스토리지 및 쿼리 로드와 요구 사항에 맞게 리소스를 규모를 조정하도록 설계되었습니다.
Timestream for LiveAnalytics의 테이블은 저장된 수 페타바이트의 데이터와 초당 수십 기가바이트의 데이터 쓰기로 규모를 조정할 수 있습니다. 쿼리는 시간당 수백 테라바이트를 처리할 수 있습니다. Timestream for LiveAnalytics의 쿼리는 여러 테이블과 데이터베이스를 아우를 수 있으며, 조인과 통합을 통해 여러 테이블과 데이터베이스의 데이터에 원활하게 액세스할 수 있도록 지원합니다. 따라서 데이터 규모나 요청량은 일반적으로 Timestream for LiveAnalytics에서 데이터를 구성하는 방법을 결정할 때 주요 고려 사항이 아닙니다. 다음은 서로 다른 테이블 또는 서로 다른 데이터베이스의 테이블과 비교하여 동일한 테이블에 배치할 데이터를 결정할 때 몇 가지 중요한 고려 사항입니다.
-
데이터 보존 정책(메모리 스토어 보존, 마그네틱 스토어 보존 등)은 테이블의 세부 수준에서 지원됩니다. 따라서 서로 다른 보존 정책이 필요한 데이터는 서로 다른 테이블에 있어야 합니다.
-
데이터를 암호화하는 데 사용되는 AWS KMS 키는 데이터베이스 수준에서 구성됩니다. 따라서 서로 다른 암호화 키 요구 사항은 데이터가 서로 다른 데이터베이스에 저장되어야 함을 의미합니다.
-
Timestream for LiveAnalytics는 테이블과 데이터베이스의 세부 수준에서 리소스 기반 액세스 제어를 지원합니다. 동일한 테이블에 쓸 데이터와 다른 테이블에 쓸 데이터를 결정할 때 액세스 제어 요구 사항을 고려하세요.
-
어느 데이터가 어느 테이블에 저장되는지 결정할 때는 차원 수, 측정 이름 및 다중 측정 속성 이름에 대한 제한 사항에 유의하세요.
-
데이터를 구성하는 방식을 결정할 때는 쿼리 워크로드와 액세스 패턴을 고려해야 합니다. 쿼리 지연 시간과 쿼리 작성 용이성은 이러한 요소에 따라 달라지기 때문입니다.
-
자주 조회하는 데이터를 같은 테이블에 저장하면 일반적으로 쿼리 작성 방식이 간소화되어 조인, 통합 또는 일반 테이블 표현식을 사용하지 않고도 쿼리를 작성할 수 있는 경우가 많습니다. 이는 또한 일반적으로 쿼리 지연 시간을 줄여줍니다. 차원과 측정 이름에 조건자를 사용하여 쿼리와 관련된 데이터를 필터링할 수 있습니다.
예를 들어, 6개 대륙에 위치한 디바이스의 데이터를 저장하는 경우를 생각해 보세요. 쿼리가 글로벌 집계 보기를 얻기 위해 여러 대륙의 데이터에 자주 액세스하는 경우 이러한 대륙의 데이터를 동일한 테이블에 저장하면 쿼리를 더 쉽게 작성할 수 있습니다. 반면에 데이터를 서로 다른 테이블에 저장하더라도 동일한 쿼리에서 데이터를 결합할 수 있습니다. 다만 여러 테이블의 데이터를 통합하는 쿼리를 작성해야 합니다.
-
Timestream for LiveAnalytics는 데이터에 적응형 파티셔닝과 인덱싱을 사용하므로 쿼리와 관련된 데이터에 대해서만 요금이 부과됩니다. 예를 들어, 6개 대륙에 걸쳐 백만 대의 기기에서 수집한 데이터를 저장하는 테이블이 있고, 쿼리에
WHERE device_id = 'abcdef'또는WHERE continent = 'North America'형식의 조건자가 포함되어 있다면 해당 쿼리는 디바이스 또는 대륙의 데이터에 대해서만 요금이 부과됩니다. -
가능한 경우 동일한 테이블 내에서 동시에 내보내지 않거나 자주 쿼리되지 않는 데이터를 측정 이름으로 분리하는 경우 쿼리에서
WHERE measure_name = 'cpu'와 같은 조건자를 사용하면 측정 이점을 얻을 수 있을 뿐만 아니라, Timestream for LiveAnalytics는 쿼리 조건자에 사용된 측정 이름이 없는 파티션을 효과적으로 제거할 수 있습니다. 이렇게 하면 쿼리 지연 시간이나 비용에 영향을 주지 않고 동일한 테이블에 서로 다른 측정 이름으로 관련 데이터를 저장할 수 있으며 데이터를 여러 테이블로 분산시키는 것을 방지할 수 있습니다. 측정 이름은 기본적으로 데이터를 파티셔닝하고 쿼리와 관련 없는 파티션을 제거하는 데 사용됩니다.
-
다중 측정 레코드와 단일 측정 레코드 비교
Timestream for LiveAnalytics를 사용하면 레코드당 여러 측정(다중 측정) 또는 레코드당 단일 측정(단일 측정값)으로 데이터를 쓸 수 있습니다.
다중 측정 레코드
많은 사용 사례에서 추적 중인 디바이스 또는 애플리케이션이 동일한 타임스탬프에서 여러 지표 또는 이벤트를 내보낼 수 있습니다. 이러한 경우 동일한 타임스탬프에서 내보낸 모든 지표를 동일한 다중 측정 레코드에 저장할 수 있습니다. 즉, 동일한 다중 측정 레코드에 저장된 모든 측정은 동일한 데이터 행에서 서로 다른 열로 나타납니다.
예를 들어, 애플리케이션이 동일한 시간에 측정된 디바이스에서 CPU, 메모리, disk_iops 등의 지표를 내보내고 있다고 가정해 보세요. 다음은 동일한 시점에 내보낸 여러 지표가 동일한 행에 저장되는 테이블의 예입니다. 두 호스트가 매초마다 한 번씩 지표를 전송하는 것을 확인할 수 있습니다.
| Hostname | measure_name | 시간 | cpu | 메모리 | disk_iops |
|---|---|---|---|---|---|
| host-24Gju | 지표 | 2021-12-01 19:00:00 | 35 | 54.9 | 38.2 |
| host-24Gju | 지표 | 2021-12-01 19:00:01 | 36 | 58 | 39 |
| host-28Gju | 지표 | 2021-12-01 19:00:00 | 15 | 55 | 92 |
| host-28Gju | 지표 | 2021-12-01 19:00:01 | 16 | 50 | 40 |
단일 측정 레코드
단일 측정 레코드는 디바이스가 서로 다른 기간에 서로 다른 지표를 내보내거나, 사용자 지정 처리 로직을 사용하여 서로 다른 기간에 지표/이벤트를 내보내는 경우(예: 디바이스의 읽기/상태가 변경될 때)에 적합합니다. 모든 측정에는 고유한 타임스탬프가 있으므로 Timestream for LiveAnalytics의 자체 레코드에 측정을 저장할 수 있습니다. 예를 들어, 토양 온도(temperature)와 습도(moisture)를 추적하는 IoT 센서는 이전에 보고된 항목의 변화를 탐지하는 경우에만 레코드를 내보냅니다. 다음 예제에서는 단일 측정 레코드를 사용하여 내보내는 이러한 데이터의 예를 제공합니다.
| device_id | measure_name | 시간 | measure_value::double | measure_value::bigint |
|---|---|---|---|---|
| sensor-sea478 | temperature | 2021-12-01 19:22:32 | 35 | NULL |
| sensor-sea478 | temperature | 2021-12-01 18:07:51 | 36 | NULL |
| sensor-sea478 | moisture | 2021-12-01 19:05:30 | NULL | 21 |
| sensor-sea478 | moisture | 2021-12-01 19:00:01 | NULL | 23 |
단일 측정 레코드와 및 다중 측정 레코드 비교
Timestream for LiveAnalytics는 애플리케이션의 요구 사항 및 특성에 따라 데이터를 단일 측정 레코드나 다중 측정 레코드로 모델링할 수 있는 유연성을 제공합니다. 애플리케이션 요구 사항에 따라 단일 테이블에 단일 측정 레코드와 다중 측정 레코드를 모두 저장할 수 있습니다. 일반적으로 애플리케이션이 동시에 여러 측정/이벤트를 내보내는 경우 성능이 우수한 데이터 액세스와 비용 효율적인 데이터 스토리지를 위해 데이터를 다중 측정 레코드로 모델링하는 것이 좋습니다.
예를 들어, 수십만 대의 서버에서 발생하는 지표와 이벤트를 추적하는 DevOps 사용 사례
-
수집 측정 - 다중 측정 레코드를 사용하면 작성되는 수집 바이트 수가 약 40% 감소합니다.
-
수집 배치 처리 - 다중 측정 레코드를 사용하면 전송되는 데이터의 배치가 더 커지므로 클라이언트가 수집을 처리하는 데 필요한 스레드 수와 CPU 사용량이 줄어듭니다.
-
스토리지 측정 - 다중 측정 레코드를 사용하면 스토리지가 약 8배 감소하여 메모리와 마그네틱 스토어 모두에서 상당한 스토리지 절감 효과를 얻을 수 있습니다.
-
쿼리 지연 시간 - 다중 측정 레코드를 사용하면 단일 측정 레코드에 비해 대부분의 쿼리 유형에 대한 쿼리 지연 시간이 줄어듭니다.
-
쿼리 측정 바이트 - 10MB 미만의 데이터를 스캔하는 쿼리의 경우 단일 측정 레코드와 다중 측정 레코드 모두 동등한 성능을 보입니다. 단일 측정에 액세스하고 10MB 이상의 데이터를 스캔하는 쿼리의 경우 단일 측정 레코드를 사용하면 일반적으로 측정되는 바이트 수가 줄어듭니다. 세 개 이상의 측정을 참조하는 쿼리의 경우 다중 측정 레코드를 사용하면 측정되는 바이트 수가 줄어듭니다.
-
다중 측정 쿼리 표현의 용이성 - 쿼리가 여러 측정을 참조할 때 다중 측정 레코드로 데이터를 모델링하면 쿼리를 더 쉽게 작성하고 더 간결하게 만들 수 있습니다.
앞서 언급한 요소들은 추적하는 지표의 수, 데이터의 차원 수 등에 따라 달라집니다. 앞의 예제에서는 하나의 사례에 대한 구체적인 데이터를 제공하지만, 다양한 애플리케이션 시나리오와 사용 사례를 살펴보면 애플리케이션이 동시에 여러 측정을 내보내는 경우 데이터를 다중 측정 레코드로 저장하는 것이 더 효과적임을 알 수 있습니다. 또한 다중 측정 레코드는 데이터 유형의 유연성을 제공하며, 컨텍스트로 다른 여러 값을 저장할 수 있도록 합니다(예: 요청 ID 저장 및 추가 타임스탬프 저장, 이에 대해서는 나중에 설명).
참고로, 다중 측정 레코드는 이전 단일 측정 레코드 예제와 같이 희소 측정을 모델링할 수도 있습니다. measure_name을 사용하여 측정 이름을 저장하고 value_double(DOUBLE 측정 저장), value_bigint(BIGINT 측정 저장), value_timestamp(추가 TIMESTAMP 값 저장) 등의 일반적인 다중 측정 속성 이름을 사용할 수 있습니다.
차원 및 치수
Timestream for LiveAnalytics의 테이블을 사용하면 차원(저장 중인 디바이스/데이터의 식별 속성)과 측정(추적 중인 지표/값)을 저장할 수 있습니다. 자세한 내용은 Amazon Timestream for LiveAnalytics 개념 섹션을 참조하세요. Timestream for LiveAnalytics에서 애플리케이션을 모델링할 때 데이터를 차원과 측정으로 매핑하는 방법은 수집 및 쿼리 지연 시간에 영향을 미칩니다. 다음은 데이터를 사용 사례에 적용할 수 있는 차원과 측정으로 모델링하는 방법에 대한 지침입니다.
차원 선택
시계열 데이터를 전송하는 소스를 식별하는 데이터는 시간이 지나도 변하지 않는 속성인 차원에 자연스럽게 부합합니다. 예를 들어 지표를 내보내는 서버가 있는 경우 해당 서버를 식별하는 속성들(예: 호스트명, 리전, 랙, 가용 영역)은 차원의 후보가 됩니다. 마찬가지로 시계열 데이터를 보고하는 센서가 여러 개인 IoT 디바이스의 경우 디바이스 ID, 센서 ID 등의 속성이 차원에 적합합니다.
데이터를 다중 측정 레코드로 작성하는 경우, 테이블에 대해 DESCRIBE 문을 실행하거나 SELECT 문을 실행하면 차원과 다중 측정 속성이 테이블의 열로 나타납니다. 따라서 쿼리를 작성할 때 동일한 쿼리 내에서 차원과 측정을 자유롭게 사용할 수 있습니다. 그러나 데이터를 수집하기 위한 쓰기 레코드 구성 시 어떤 속성을 차원으로 지정하고 어떤 속성을 측정값으로 지정할지 선택할 때 다음 사항에 유의하세요.
-
차원 이름, 차원 값, 측정 이름 및 타임스탬프는 시계열 데이터를 고유하게 식별합니다. Timestream for LiveAnalytics는 이 고유 식별자를 사용하여 자동으로 데이터 중복을 제거합니다. 즉, Timestream for LiveAnalytics가 차원 이름, 차원 값, 측정 이름 및 타임스탬프 값이 동일하고 버전 번호도 동일한 두 데이터 포인트를 수신하면 중복 제거를 수행합니다. Timestream for LiveAnalytics에 이미 존재하는 데이터보다 버전이 낮은 새 쓰기 요청은 거부됩니다. 새 쓰기 요청의 버전이 더 높으면 새 값이 이전 값을 덮어씁니다. 따라서 차원 값을 선택하는 방식이 중복 제거 동작에 영향을 미칩니다.
-
차원 이름과 값은 업데이트할 수 없지만 측정값은 업데이트할 수 있습니다. 따라서 업데이트가 필요할 수 있는 데이터는 측정값으로 모델링하는 것이 더 좋습니다. 예를 들어, 공장 현장에 색상이 변할 수 있는 기계가 있는 경우 중복 제거에 필요한 식별 속성으로도 색상을 사용하려는 경우가 아니라면 색상을 측정값으로 모델링할 수 있습니다. 즉, 측정값은 시간 경과에 따라 서서히 변하는 속성을 저장하는 데 사용할 수 있습니다.
Timestream for LiveAnalytics의 테이블은 차원 이름과 값의 고유한 조합 수를 제한하지 않습니다. 예를 들어 테이블에 수십억 개의 고유 값 조합이 저장될 수 있습니다. 그러나 다음 예제와 같이 차원과 측정을 신중하게 선택하면 특히 쿼리의 경우 요청 지연 시간을 크게 최적화할 수 있습니다.
차원의 고유 ID
애플리케이션 시나리오에서 모든 데이터 포인트에 대한 고유 식별자(예: 요청 ID, 트랜잭션 ID 또는 상관관계 ID)를 저장해야 하는 경우 ID 속성을 측정값으로 모델링하면 쿼리 지연 시간이 크게 개선됩니다. 다중 측정 레코드로 데이터를 모델링할 때 ID는 다른 차원 및 시계열 데이터와 컨텍스트상 동일한 행에 표시되므로 쿼리가 계속해서 이를 효과적으로 사용할 수 있습니다. 예를 들어 서버에서 내보내는 모든 데이터 포인트에 고유한 요청 ID 속성이 있는 DevOps 사용 사례
모든 데이터 포인트에 대해 완전히 고유하지는 않지만 수십만 또는 수백만 개의 고유 값을 갖는 속성에도 유사한 비유를 사용할 수 있습니다. 이러한 속성을 차원 또는 측정값으로 모두 모델링할 수 있습니다. 앞서 설명한 대로 쓰기 경로에서 중복 제거를 위해 값이 필요하거나 쿼리에서 값을 조건자로 사용하는 경우(예: 애플리케이션이 수백만 대의 디바이스를 추적하는 상황에서 device_id = 'abcde'와 같이 해당 속성 값에 대한 같음 조건자를 WHERE 절에 사용) 차원으로 모델링하는 것이 좋습니다.
다중 측정 레코드를 통한 풍부한 데이터 유형
다중 측정 레코드는 데이터를 효과적으로 모델링할 수 있는 유연성을 제공합니다. 다중 측정 레코드에 저장하는 데이터는 테이블에서 차원과 유사한 열로 표시되므로 차원 값과 측정값 모두에 대해 동일한 수준의 쿼리 편의성을 제공합니다. 앞에서 설명한 예제에서 이러한 패턴 중 일부를 보셨을 것입니다. 아래에서는 애플리케이션의 사용 사례에 맞춰 다중 측정 레코드를 효과적으로 활용하는 추가 패턴을 확인할 수 있습니다.
다중 측정 레코드는 DOUBLE, BIGINT, VARCHAR, BOOLEAN 및 TIMESTAMP 데이터 유형의 속성을 지원합니다. 따라서 다양한 유형의 속성에 자연스럽게 맞습니다.
-
위치 정보: 예를 들어 위도 및 경도로 표현된 위치를 추적하려는 경우 이를 다중 측정 속성으로 모델링하면
VARCHAR차원으로 저장할 때보다 쿼리 지연 시간이 줄어듭니다. 특히 위도와 경도에 대한 조건자가 있는 경우 더욱 그렇습니다. -
레코드의 여러 타임스탬프: 애플리케이션 시나리오에서 시계열 레코드에 대해 여러 타임스탬프를 추적해야 하는 경우 해당 타임스탬프를 다중 측정 레코드 내 추가 속성으로 모델링할 수 있습니다. 이 패턴은 미래 타임스탬프 또는 과거 타임스탬프가 있는 데이터를 저장하는 데 사용할 수 있습니다. 모든 레코드는 여전히 time 열의 타임스탬프를 사용하여 레코드를 파티셔닝, 인덱싱 및 고유하게 식별합니다.
특히 쿼리에 조건자가 있는 숫자 데이터나 타임스탬프가 있는 경우 해당 속성을 차원이 아닌 다중 측정 속성으로 모델링하면 쿼리 지연 시간이 줄어듭니다. 이는 다중 측정 레코드에서 지원하는 풍부한 데이터 유형을 사용하여 이러한 데이터를 모델링할 때, 해당 데이터를 차원으로 모델링한 경우 VARCHAR 값을 다른 데이터 유형으로 캐스팅하는 대신 기본 데이터 유형을 사용하여 조건자를 표현할 수 있기 때문입니다.
다중 측정 레코드에서 측정 이름 사용
Timestream for LiveAnalytics의 테이블은 측정 이름이라는 특수 속성이나 열을 지원합니다. Timestream for LiveAnalytics에 쓰는 모든 레코드에 대해 이 속성의 값을 지정합니다. 단일 측정 레코드의 경우 지표 이름(예: 서버 지표의 경우 CPU 또는 메모리, 센서 지표의 경우 온도 또는 압력)을 사용하는 것이 자연스럽습니다. 다중 측정 레코드를 사용할 때 다중 측정 레코드의 속성에 이름이 지정되고 이러한 이름은 테이블의 열 이름이 됩니다. 따라서 cpu, 메모리, 온도 및 압력은 다중 측정 속성 이름이 될 수 있습니다. 자연스럽게 드는 질문은 측정 이름을 어떻게 효과적으로 사용할 것인가 하는 것입니다.
Timestream for LiveAnalytics는 측정 이름 속성의 값을 사용하여 데이터를 파티셔닝하고 인덱싱합니다. 따라서 테이블에 서로 다른 측정 이름이 여러 개 있고 쿼리가 이러한 값을 쿼리 조건자로 사용하는 경우 Timestream for LiveAnalytics는 사용자 지정 파티셔닝 및 인덱싱을 사용하여 쿼리와 관련이 없는 데이터를 정리할 수 있습니다. 예를 들어, 테이블에 cpu 및 memory 측정 이름이 있고 쿼리에 WHERE
measure_name = 'cpu' 조건자가 있는 경우 Timestream for LiveAnalytics는 쿼리와 관련이 없는 측정 이름(예: 이 예에서 memory라는 측정 이름을 가진 행)에 대한 데이터를 효과적으로 정리할 수 있습니다. 이 정리는 다중 측정 레코드에 측정 이름을 사용하는 경우에도 적용됩니다. 측정 이름 속성을 테이블의 파티셔닝 속성으로 효과적으로 사용할 수 있습니다. 측정 이름과 차원 이름 및 값, 시간은 Timestream for LiveAnalytics 테이블에서 데이터를 파티셔닝하는 데 사용됩니다. Timestream for LiveAnalytics 테이블에서 허용되는 고유 측정 이름 수에 대한 제한에 유의하세요. 또한 측정 이름은 측정값 데이터 유형과도 연결되어 있다는 점에 유의하세요. 예를 들어 단일 측정 이름은 하나의 측정값 유형과만 연결될 수 있습니다. 해당 유형은 DOUBLE, BIGINT, BOOLEAN, VARCHAR 또는 MULTI 중 하나일 수 있습니다. 측정 이름과 함께 저장된 다중 측정 레코드는 MULTI 데이터 유형을 가집니다. 단일 다중 측정 레코드에 서로 다른 데이터 유형(DOUBLE, , BIGINT, VARCHAR, BOOLEAN 및 TIMESTAMP)의 여러 지표를 저장할 수 있으므로 다중 측정 레코드에서 서로 다른 유형의 데이터를 연결할 수 있습니다.
다음 섹션에서는 측정 이름 속성을 효과적으로 사용하여 동일한 테이블에서 서로 다른 유형의 데이터를 그룹화하는 방법에 대한 몇 가지 예를 설명합니다.
품질 및 가치를 보고하는 IoT 센서
IoT 센서에서 데이터를 모니터링하는 애플리케이션이 있다고 가정해 보겠습니다. 각 센서는 온도, 압력 등의 서로 다른 측정을 추적합니다. 센서는 실제 값 외에도 측정값 품질(판독값의 정확도를 나타내는 척도)과 측정 단위를 보고합니다. 품질, 단위 및 값은 함께 내보내지므로 아래 예시 데이터와 같이 다중 측정 레코드로 모델링할 수 있습니다. 여기서 device_id는 차원이고, quality, value, unit은 다중 측정 속성입니다.
| device_id | measure_name | 시간 | 화질 | 값 | 단위 |
|---|---|---|---|---|---|
| sensor-sea478 | temperature | 2021-12-01 19:22:32 | 92 | 35 | c |
| sensor-sea478 | temperature | 2021-12-01 18:07:51 | 93 | 34 | c |
| sensor-sea478 | pressure | 2021-12-01 19:05:30 | 98 | 31 | psi |
| sensor-sea478 | pressure | 2021-12-01 19:00:01 | 24 | 132 | psi |
이 접근 방식을 사용하면 다중 측정 레코드의 이점과 측정 이름 값을 사용한 데이터 파티셔닝 및 정리를 결합할 수 있습니다. 쿼리가 온도 등의 단일 측정을 참조하는 경우 쿼리에 measure_name 조건자를 포함할 수 있습니다. 다음은 그러한 쿼리의 예이며, 품질이 90 이상인 측정을 위해 단위를 프로젝션합니다.
SELECT device_id, time, value AS temperature, unit FROM db.table WHERE time > ago(1h) AND measure_name = 'temperature' AND quality > 90
쿼리에 measure_name 조건자를 사용하면 Timestream for LiveAnalytics가 쿼리와 관련이 없는 파티션과 데이터를 효과적으로 정리하여 쿼리 지연 시간을 개선할 수 있습니다.
또한 모든 지표가 동일한 타임스탬프에서 내보내지거나 동일한 쿼리에서 여러 지표가 함께 쿼리되는 경우 모든 지표가 동일한 다중 측정 레코드에 저장되도록 할 수 있습니다. 예를 들어, temperature_quality, temperature_value, temperature_unit, pressure_quality, pressure_value, pressure_unit 등의 속성을 사용하여 다중 측정 레코드를 구성할 수 있습니다. 단일 측정 레코드와 다중 측정 레코드를 사용한 데이터 모델링에 대해 앞서 설명한 많은 사항이 데이터 모델링 방법을 결정할 때 적용됩니다. 쿼리 액세스 패턴과 데이터 생성 방법을 고려하여 비용, 수집 및 쿼리 지연 시간, 쿼리 작성 용이성을 최적화하는 모델을 선택합니다.
동일한 테이블에 있는 다양한 유형의 지표
다중 측정 레코드와 측정 이름 값을 결합할 수 있는 또 다른 사용 사례는 동일한 디바이스에서 독립적으로 전송되는 서로 다른 유형의 데이터를 모델링하는 것입니다. 서버가 정기적으로 내보내는 지표와 불규칙한 이벤트라는 두 가지 유형의 데이터를 내보내는 DevOps 모니터링 사용 사례를 고려해 보세요. 이 접근 방식의 예는 DevOps 사용 사례를 모델링하는 데이터 생성기SHOW MEASURES 쿼리의 출력)는 다음과 같습니다.
| measure_name | data_type | 차원 |
|---|---|---|
| 이벤트 | 다중 | [{"data_type":"varchar","dimension_name":"availability_zone"},{"data_type":"varchar","dimension_name":"microservice_name"},{"data_type":"varchar","dimension_name":"instance_name"},{"data_type":"varchar","dimension_name":"process_name"},{"data_type":"varchar","dimension_name":"jdk_version"},{"data_type":"varchar","dimension_name":"cell"},{"data_type":"varchar","dimension_name":"region"},{"data_type":"varchar","dimension_name":"silo"}] |
| 지표 | 다중 | [{"data_type":"varchar","dimension_name":"availability_zone"},{"data_type":"varchar","dimension_name":"microservice_name"},{"data_type":"varchar","dimension_name":"instance_name"},{"data_type":"varchar","dimension_name":"os_version"},{"data_type":"varchar","dimension_name":"cell"},{"data_type":"varchar","dimension_name":"region"},{"data_type":"varchar","dimension_name":"silo"},{"data_type":"varchar","dimension_name":"instance_type"}] |
이 경우 이벤트와 지표가 서로 다른 차원 집합을 가지고 있음을 확인할 수 있습니다. 이벤트는 jdk_version 및 process_name 차원을 가지는 반면, 지표는 instance_type 및 os_version 차원을 가집니다.
서로 다른 측정 이름을 사용하면 WHERE measure_name = 'metrics' 등의 조건자로 쿼리를 작성하여 지표만 가져올 수 있습니다. 또한 동일한 테이블에 동일한 인스턴스에서 내보낸 모든 데이터가 있다는 것은 instance_name 조건자로 더 간단한 쿼리를 작성하여 해당 인스턴스의 모든 데이터를 가져올 수 있음을 의미합니다. 예를 들어 measure_name 조건자 없이 WHERE instance_name =
'instance-1234' 형식의 조건자를 사용하면 특정 서버 인스턴스에 대한 모든 데이터가 반환됩니다.
다중 측정 레코드 파티셔닝에 대한 권장 사항
중요
이 섹션은 더 이상 사용되지 않습니다.
이러한 권장 사항은 오래된 것입니다. 이제 고객 정의 파티션 키를 사용하여 파티셔닝을 더 잘 제어할 수 있습니다.
시계열 생태계에서 점점 더 많은 워크로드가 대량의 데이터를 수집하고 저장해야 하는 동시에, 높은 카드널리티 차원 값 집합으로 데이터에 액세스할때 짧은 지연 시간 쿼리 응답이 필요하다는 점을 확인했습니다.
이러한 특성으로 인해 이 섹션의 권장 사항은 다음과 같은 고객 워크로드에 유용합니다.
-
다중 측정 레코드를 채택했거나 채택하려는 경우
-
시스템에 대량의 데이터가 유입되어 장기간 저장될 것으로 예상되는 경우
-
기본 액세스(쿼리) 패턴에 짧은 지연 시간 응답 시간이 필요한 경우
-
가장 중요한 쿼리 패턴이 조건자에 일종의 필터링 조건을 포함한다는 점을 인지하는 경우. 이 필터링 조건은 카디널리티가 높은 차원을 중심으로 합니다. 예를 들어 UserId, DeviceId, ServerID, host-name 등에 따른 이벤트 또는 집계를 고려해 보세요.
이러한 경우 모든 다중 측정에 대해 단일 이름을 사용하는 것은 도움이 되지 않습니다. 엔진이 다중 측정 이름을 사용하여 데이터를 파티셔닝하기 때문에 단일 값을 사용하면 얻을 수 있는 파티셔닝의 이점이 제한되기 때문입니다. 이러한 레코드의 파티셔닝은 주로 두 가지 차원을 기반으로 합니다. 시간이 x축에 있고 차원 이름의 해시와 measure_name이 y축에 있다고 가정해 보겠습니다. 이 경우 measure_name은 파티셔닝 키와 거의 같은 역할을 합니다.
권장 사항은 다음과 같습니다.
-
앞서 언급한 사용 사례와 같은 용도에 맞게 데이터를 모델링할 때는 기본 쿼리 접근 패턴액세스 패턴의 직접 미분인
measure_name을 사용하세요. 예:-
사용 사례에서는 최종 사용자 관점에서 애플리케이션 성능과 QoE를 추적해야 합니다. 이는 단일 서버나 IoT 디바이스에 대한 측정값 추적일 수도 있습니다.
-
UserId로 쿼리하고 필터링하는 경우 데이터 수집 시점에
measure_name을 UserId에 연결하는 가장 좋은 방법을 찾아야 합니다. -
다중 측정 테이블은 최대 8,192개의 서로 다른 측정 이름만 저장할 수 있으므로 채택된 공식은 8,192개 이상의 서로 다른 값을 생성해서는 안 됩니다.
-
-
문자열 값에 대해 성공적으로 적용한 한 가지 접근 방식은 문자열 값에 해싱 알고리즘을 적용하는 것입니다. 그런 다음 해시 결과의 절댓값과 8,192를 사용하여 나머지 연산을 수행합니다.
measure_name = getMeasureName(UserId) int getMeasureName(value) { hash_value = abs(hash(value)) return hash_value % 8192 } -
또한 부호를 제거하는
abs()를 추가하여 값이 -8,192~8,192 범위일 가능성을 없앴습니다. 이 작업은 나머지 연산 전에 수행해야 합니다. -
이 방법을 사용하면 파티셔닝되지 않은 데이터 모델에서 쿼리를 실행하는 데 걸리는 시간보다 훨씬 짧은 시간 내에 쿼리를 실행할 수 있습니다.
-
데이터를 쿼리할 때
measure_name의 새로 파생된 값을 사용하는 필터링 조건을 조건자에 포함시켜야 합니다. 예:-
SELECT * FROMyour_database.your_tableWHERE host_name = 'Host-1235' time BETWEEN '2022-09-01' AND '2022-09-18' AND measure_name = (SELECT cast(abs(from_big_endian_64(xxhash64(CAST('HOST-1235' AS varbinary))))%8192 AS varchar)) -
이렇게 하면 스캔하는 파티션 수를 최소화하여 장기적으로 더 빠른 쿼리 속도를 얻을 수 있습니다.
-
이 파티션 스키마의 이점을 얻으려면 해시 값을 클라이언트 측에서 계산하여 Timestream for LiveAnalytics의 쿼리 엔진에 정적 값으로 전달해야 한다는 점을 유념하세요. 위의 예시는 생성된 해시가 필요할 때 엔진에 의해 해석될 수 있는지 검증하는 방법을 제공합니다.
| 시간 | host_name | location | server_type | cpu_usage | available_memory | cpu_temp |
|---|---|---|---|---|---|---|
|
2022-09-07 21:48:44 .000000000 |
host-1235 |
us-east1 |
5.8xl |
55 |
16.2 |
78 |
|
R2022-09-07 21:48:44 .000000000 |
host-3587 |
us-west1 |
5.8xl |
62 |
18.1 |
81 |
|
2022-09-07 21:48:45.000000000 |
host-258743 |
eu-central |
5.8xl |
88 |
9.4 |
91 |
|
2022-09-07 21:48:45 .000000000 |
host-35654 |
us-east2 |
5.8xl |
29 |
24 |
54 |
|
R2022-09-07 21:48:45 .000000000 |
host-254 |
us-west1 |
5.8xl |
44 |
32 |
48 |
권장 사항에 따라 관련 measure_name을 생성하는 방법은 데이터 수집 패턴에 따라 두 가지가 있습니다.
-
기록 데이터의 배치 수집의 경우 - 배치 처리에 자체 코드를 사용할 경우 변환을 쓰기 코드에 추가할 수 있습니다.
앞선 예시를 바탕으로 구축합니다.
List<String> hosts = new ArrayList<>(); hosts.add("host-1235"); hosts.add("host-3587"); hosts.add("host-258743"); hosts.add("host-35654"); hosts.add("host-254"); for (String h: hosts){ ByteBuffer buf2 = ByteBuffer.wrap(h.getBytes()); partition = abs(hasher.hash(buf2, 0L)) % 8192; System.out.println(h + " - " + partition); }Output
host-1235 - 6445 host-3587 - 6399 host-258743 - 640 host-35654 - 2093 host-254 - 7051
결과 데이터세트:
시간 host_name location measure_name server_type cpu_usage available_memory cpu_temp 2022-09-07 21:48:44 .000000000
host-1235
us-east1
6445
5.8xl
55
16.2
78
R2022-09-07 21:48:44 .000000000
host-3587
us-west1
6399
5.8xl
62
18.1
81
2022-09-07 21:48:45.000000000
host-258743
eu-central
640
5.8xl
88
9.4
91
2022-09-07 21:48:45 .000000000
host-35654
us-east2
2093
5.8xl
29
24
54
R2022-09-07 21:48:45 .000000000
host-254
us-west1
7051
5.8xl
44
32
48
-
실시간 수집의 경우 - 데이터가 들어오는 동안 실시간으로
measure_name을 생성해야 합니다.
두 경우 모두 해시 생성 알고리즘이 양쪽 끝(데이터 수집 및 쿼리)에서 모두 동일한 결과를 얻는지 확인하기 위해 테스트해 볼 것을 권장합니다.
다음은 host_name을 기반으로 해시 값을 생성하는 코드 예제입니다.
예 Python
>>> import xxhash >>> from bitstring import BitArray >>> b=xxhash.xxh64('HOST-ID-1235').digest() >>> BitArray(b).int % 8192 ### 3195
예 Go
package main import ( "bytes" "fmt" "github.com/cespare/xxhash" ) func main() { buf := bytes.NewBufferString("HOST-ID-1235") x := xxhash.New() x.Write(buf.Bytes()) // convert unsigned integer to signed integer before taking mod fmt.Printf("%f\n", abs(int64(x.Sum64())) % 8192) } func abs(x int64) int64 { if (x < 0) { return -x } return x }
예 Java
import java.nio.ByteBuffer; import net.jpountz.xxhash.XXHash64; public class test { public static void main(String[] args) { XXHash64 hasher = net.jpountz.xxhash.XXHashFactory.fastestInstance().hash64(); String host = "HOST-ID-1235"; ByteBuffer buf = ByteBuffer.wrap(host.getBytes()); Long result = Math.abs(hasher.hash(buf, 0L)); Long partition = result % 8192; System.out.println(result); System.out.println(partition); } }
예 Maven의 종속성
<dependency> <groupId>net.jpountz.lz4</groupId> <artifactId>lz4</artifactId> <version>1.3.0</version> </dependency>