데이터 모델 평가 및 다듬기
데이터 모델 평가 및 다듬기 (Evaluating and refining data models)
물리적 모델을 만든 후에는 최적의 성능을 보장하기 위해 테이블 설계를 평가하고 다듬기 위한 몇 가지 단계를 수행해야 해요.
본문
파티션 크기 계산 (Calculating Partition Size)
가장 먼저 살펴봐야 할 것은 테이블에 지나치게 크거나, 다시 말해 너무 넓은 파티션이 생길지 여부예요. 파티션 크기는 파티션에 저장된 셀(값) 수로 측정돼요. Cassandra의 하드 한도는 파티션당 20억 셀이지만, 그 한도에 도달하기 전에 성능 문제를 겪을 가능성이 높아요.
파티션 크기를 계산하려면 다음 공식을 사용해요:
N_v = N_r (N_c - N_pk - N_s) + N_s
파티션의 값(또는 셀) 수(Nv)는 정적 컬럼 수(Ns)에 행 수(Nr)와 행당 값 수의 곱을 더한 것과 같아요. 행당 값 수는 컬럼 수(Nc)에서 기본 키 컬럼 수(Npk)와 정적 컬럼 수(Ns)를 뺀 값으로 정의돼요.
컬럼 수는 상대적으로 정적인 경향이 있지만, 런타임에 테이블을 변경하는 것은 가능해요. 이런 이유로 파티션 크기의 주요 원인은 파티션의 행 수예요. 이는 파티션이 너무 커질 가능성이 있는지 판단할 때 반드시 고려해야 할 주요 요소예요. 20억 개의 값은 많아 보이지만, 매 밀리초마다 수십 또는 수백 개의 값을 측정하는 센서 시스템에서는 값 수가 꽤 빨리 늘어나기 시작해요.
파티션 크기를 분석하기 위해 테이블 중 하나를 살펴볼게요. 호텔당 하나의 파티션을 가진 넓은 파티션 설계이므로 available_rooms_by_hotel_date 테이블을 살펴볼게요. 이 테이블은 총 4개의 컬럼(Nc = 4)이 있고, 3개의 기본 키 컬럼(Npk = 3)과 정적 컬럼이 없어요(Ns = 0). 이 값을 공식에 넣으면 결과는:
N_v = N_r (4 - 3 - 0) + 0 = 1N_r
따라서 이 테이블의 값 수는 행 수와 같아요. 여전히 행 수를 결정해야 해요. 이를 위해 애플리케이션 설계를 기반으로 추정해요. 이 테이블은 각 호텔, 각 객실, 매일 밤에 대한 레코드를 저장해요. 시스템이 한 번에 2년치 재고를 저장하고, 시스템에 5,000개의 호텔이 있으며 각 호텔에 평균 100개의 객실이 있다고 가정해 볼게요.
각 호텔에 대한 파티션이 있으므로 파티션당 예상 행 수는 다음과 같아요:
N_r = 100 rooms/hotel × 730 days = 73,000 rows
파티션당 이 비교적 적은 행 수는 큰 문제를 일으키지 않겠지만, 더 많은 날짜의 재고를 저장하거나 TTL로 재고 크기를 잘 관리하지 않으면 문제가 시작될 수 있어요. 이 큰 파티션을 나누는 것을 고려해 볼 수도 있는데, 곧 어떻게 하는지 보게 될 거예요.
크기 계산을 수행할 때 행 수 같은 변수에 명목 또는 평균 케이스를 가정하고 싶어지기 쉬워요. 최악의 경우도 계산하는 것을 고려해 보세요. 이런 종류의 예측은 성공적인 시스템에서 실현되는 경향이 있기 때문이에요.
디스크 크기 계산 (Calculating Size on Disk)
파티션 크기 계산 외에도 클러스터에 저장할 각 테이블에 필요한 디스크 공간을 추정하는 것도 좋은 생각이에요. 크기를 결정하려면 다음 공식을 사용해 파티션 크기 St를 결정해요:
S_t = Σᵢ sizeOf(c_ki) + Σⱼ sizeOf(c_sj) + N_r × (Σₖ sizeOf(c_rk) + Σₗ sizeOf(c_cl)) +
N_v × sizeOf(t_avg)
이것은 이전 공식보다 조금 더 복잡하지만, 한 번에 하나씩 나눠서 살펴볼게요. 먼저 표기법을 살펴볼게요.
- 이 공식에서 ck는 파티션 키 컬럼, cs는 정적 컬럼, cr은 일반 컬럼, cc는 클러스터링 컬럼을 나타내요.
- tavg 항은 타임스탬프 같은 셀당 저장되는 메타데이터의 평균 바이트 수를 나타내요. 이 값에는 보통 8바이트 추정치를 사용하는 것이 일반적이에요.
- 행 수 Nr과 값 수 Nv는 이전 계산에서 이미 본 것이에요.
- sizeOf() 함수는 참조된 각 컬럼의 CQL 데이터 타입의 크기를 바이트 단위로 나타내요.
첫 번째 항은 파티션 키 컬럼 크기의 합을 구하라고 요구해요. 이 예제에서 available_rooms_by_hotel_date 테이블은 text 타입인 단일 파티션 키 컬럼 hotel_id를 가져요. 호텔 식별자가 간단한 5자리 코드라고 가정하면 5바이트 값이므로 파티션 키 컬럼 크기의 합은 5바이트예요.
두 번째 항은 정적 컬럼 크기의 합을 구하라고 요구해요. 이 테이블에는 정적 컬럼이 없으므로 크기는 0바이트예요.
세 번째 항이 가장 복잡한데, 그럴 만한 이유가 있어요. 파티션의 셀 크기를 계산하고 있기 때문이에요. 클러스터링 컬럼과 일반 컬럼의 크기의 합을 구해요. 두 개의 클러스터링 컬럼은 4바이트인 date와 2바이트의 짧은 정수인 room_number로, 합은 6바이트예요. 단일 일반 컬럼은 1바이트 크기의 boolean is_available뿐이에요. 일반 컬럼 크기(1바이트)와 클러스터링 컬럼 크기(6바이트)를 합하면 총 7바이트예요. 항을 마무리하려면 이 값에 행 수(73,000)를 곱해 511,000바이트(0.51 MB)의 결과를 얻어요.
네 번째 항은 Cassandra가 각 셀에 대해 저장하는 메타데이터를 세는 것뿐이에요. Cassandra 3.0 이상에서 사용하는 저장 형식에서 주어진 셀의 메타데이터 양은 저장되는 데이터의 타입과 개별 셀에 대해 커스텀 타임스탬프나 TTL 값이 지정되는지 여부에 따라 다르게 달라져요. 이 테이블의 경우 이전 계산의 값 수(73,000)를 재사용하고 8을 곱해 0.58 MB를 얻어요.
이 항들을 더하면 최종 추정치를 얻어요:
Partition size = 16 bytes + 0 bytes + 0.51 MB + 0.58 MB = 1.1 MB
이 공식은 디스크에서 파티션 실제 크기의 근사치지만 정확해서 상당히 유용해요. 파티션이 단일 노드에 맞아야 한다는 점을 기억하면, 이 테이블 설계가 디스크 저장에 많은 부담을 주지 않을 것 같아요.
Cassandra의 저장 엔진은 3.0 릴리스에서 새 SSTable 파일 형식을 포함해 다시 구현됐어요. 이전 형식은 각 셀의 레코드의 일부로 클러스터링 컬럼의 별도 복사본을 저장했어요. 새로운 형식은 이 중복을 제거해, 저장 데이터의 크기를 줄이고 그 크기를 계산하는 공식을 단순화해요.
또한 이 추정치는 데이터의 단일 레플리카만 계산한다는 점을 기억하세요. 여기서 얻은 값에 파티션 수와 키스페이스의 복제 전략이 지정한 레플리카 수를 곱해 각 테이블에 필요한 총 용량을 결정해야 해요. 이는 클러스터를 계획할 때 유용할 거예요.
큰 파티션 나누기 (Breaking Up Large Partitions)
앞서 논의한 대로 테이블을 설계할 때 목표는 단일 파티션을 건드리는 쿼리, 또는 그것이 불가능하면 가능한 최소 수의 파티션으로 필요한 데이터를 제공하는 것이에요. 하지만 예제에서 보여준 것처럼 Cassandra의 내장 한도에 근접하는 넓은 파티션 스타일 테이블을 설계하는 것은 충분히 가능해요. 테이블에 크기 분석을 수행하면 값 수, 디스크 크기, 또는 둘 다에서 잠재적으로 너무 큰 파티션이 드러날 수 있어요.
큰 파티션을 나누는 기법은 간단해요. 파티션 키에 추가 컬럼을 추가하면 돼요. 대부분의 경우 기존 컬럼 중 하나를 파티션 키로 옮기는 것으로 충분해요. 또 다른 옵션은 샤딩 키 역할을 하도록 테이블에 추가 컬럼을 도입하는 것이지만, 이는 추가 애플리케이션 로직을 요구해요.
available rooms 예제를 계속 살펴보면, available_rooms_by_hotel_date 테이블의 파티션 키에 date 컬럼을 추가하면 각 파티션이 특정 호텔의 특정 날짜 객실 가용성을 나타내게 돼요. 이는 확실히 훨씬 작은, 아마도 너무 작은 파티션을 낳을 거예요. 연속된 날짜의 데이터가 별도 노드에 있을 가능성이 높기 때문이에요.
버케팅(bucketing) 이라고 알려진 또 다른 기법은 데이터를 적당한 크기의 파티션으로 나누는 데 자주 사용돼요. 예를 들어 파티션 키에 month 컬럼(아마 정수로 표현)을 추가해 available_rooms_by_hotel_date 테이블을 버케팅할 수 있어요. 원래 설계와의 비교는 아래 그림에 나와 있어요. month 컬럼은 date를 부분적으로 중복하지만, 너무 커지지 않을 파티션에 관련 데이터를 그룹화하는 좋은 방법을 제공해요.

넓은 파티션 설계를 정말로 보존하고 싶다면 대신 파티션 키에 room_id를 추가해 각 파티션이 모든 날짜에 걸친 객실 가용성을 나타내도록 할 수 있어요. 특정 객실의 가용성을 검색하는 쿼리가 식별되지 않았으므로, 첫 번째나 두 번째 설계 접근 방식이 애플리케이션 요구에 가장 적합해요.
이 자료는 Cassandra, The Definitive Guide에서 각색한 내용이에요. O'Reilly Media, Inc. 발행. Copyright © 2020 Jeff Carpenter, Eben Hewitt. All rights reserved. 허가를 받아 사용했어요.