간단한 개발관련 내용

카산드라(Apache Cassandra)의 파티션 키(Partition Key)와 클러스터링 키(Clustering Key) 본문

NoSql/Casandra

카산드라(Apache Cassandra)의 파티션 키(Partition Key)와 클러스터링 키(Clustering Key)

vincenzo.dev.82 2024. 10. 3. 00:07
반응형

카산드라(Apache Cassandra)는 높은 확장성과 성능을 제공하는 분산 NoSQL 데이터베이스로, 데이터 모델링의 핵심 개념 중 하나인 파티션 키(Partition Key)클러스터링 키(Clustering Key)를 통해 데이터를 효율적으로 분산 저장하고 정렬합니다. 이 두 키는 데이터의 물리적 저장 방식과 쿼리 성능에 큰 영향을 미치므로, 이를 깊이 이해하는 것이 중요합니다. 아래에서 파티션 키와 클러스터링 키의 개념, 역할, 사용 방법, 그리고 최적화 전략에 대해 자세히 설명하겠습니다.


1. 파티션 키(Partition Key)와 클러스터링 키(Clustering Key)의 개요

1.1. 파티션 키(Partition Key)

  • 정의: 파티션 키는 테이블 내의 각 행(row)을 특정 파티션(partition)에 할당하는 데 사용되는 키입니다. 동일한 파티션 키를 가진 행들은 동일한 파티션에 저장됩니다.
  • 역할:
    • 데이터 분산: 파티션 키를 기반으로 데이터가 클러스터 내의 다양한 노드에 분산 저장됩니다.
    • 확장성: 파티션 키를 적절히 설계하면 클러스터에 노드를 추가할 때 데이터가 고르게 분산되어 확장성이 향상됩니다.
    • 쿼리 성능: 파티션 키를 사용하여 데이터를 조회하면 특정 파티션에서만 데이터를 검색하므로 조회 성능이 향상됩니다.

1.2. 클러스터링 키(Clustering Key)

  • 정의: 클러스터링 키는 파티션 내에서 데이터의 정렬 순서를 결정하는 키입니다. 동일한 파티션 키를 가진 행들 간의 정렬 기준을 제공합니다.
  • 역할:
    • 데이터 정렬: 클러스터링 키를 사용하여 파티션 내의 데이터를 특정 순서(오름차순 또는 내림차순)로 정렬합니다.
    • 범위 쿼리: 클러스터링 키를 활용한 범위 쿼리를 효율적으로 수행할 수 있습니다.
    • 데이터 그룹화: 클러스터링 키를 통해 관련 데이터를 그룹화하여 저장함으로써 관련된 데이터를 한 곳에 모을 수 있습니다.

2. 파티션 키와 클러스터링 키의 구조 및 사용 방법

2.1. 기본 키(Primary Key)의 구성

Cassandra에서 기본 키는 파티션 키와 클러스터링 키로 구성됩니다. 기본 키의 구문은 다음과 같습니다:

PRIMARY KEY (partition_key, clustering_key1, clustering_key2, ...)
  • 단일 파티션 키: 단일 컬럼을 파티션 키로 사용하는 경우.
  • PRIMARY KEY (user_id)
  • 복합 파티션 키: 여러 컬럼을 묶어 하나의 파티션 키로 사용하는 경우.
  • PRIMARY KEY ((country, city), timestamp)

2.2. 파티션 키(Partition Key)

2.2.1. 단일 파티션 키

단일 컬럼을 파티션 키로 사용하는 경우입니다. 예를 들어, 사용자 ID를 파티션 키로 사용하는 테이블을 생각해보겠습니다.

CREATE TABLE users (
  user_id UUID,
  name TEXT,
  email TEXT,
  age INT,
  PRIMARY KEY (user_id)
);
  • 특징:
    • user_id는 고유한 파티션을 형성합니다.
    • 사용자별로 데이터를 분산 저장하며, 특정 사용자의 데이터를 조회할 때 효율적입니다.

2.2.2. 복합 파티션 키

여러 컬럼을 결합하여 하나의 파티션 키로 사용하는 경우입니다. 예를 들어, 국가(country)와 도시(city)를 결합하여 파티션 키로 사용할 수 있습니다.

CREATE TABLE locations (
  country TEXT,
  city TEXT,
  place_id UUID,
  name TEXT,
  PRIMARY KEY ((country, city), place_id)
);
  • 특징:
    • countrycity의 조합이 파티션 키로 작용하여, 동일한 국가와 도시 내의 장소들이 동일한 파티션에 저장됩니다.
    • 데이터가 특정 그룹(예: 특정 도시 내의 장소)으로 논리적으로 묶입니다.

2.3. 클러스터링 키(Clustering Key)

클러스터링 키는 파티션 내에서 행의 정렬 순서를 결정합니다. 클러스터링 키는 파티션 키 이후에 지정되며, 하나 이상의 컬럼으로 구성될 수 있습니다.

2.3.1. 단일 클러스터링 키

단일 컬럼을 클러스터링 키로 사용하는 경우입니다.

CREATE TABLE user_posts (
  user_id UUID,
  post_id TIMEUUID,
  content TEXT,
  created_at TIMESTAMP,
  PRIMARY KEY (user_id, post_id)
) WITH CLUSTERING ORDER BY (post_id DESC);
  • 특징:
    • 동일한 user_id를 가진 모든 포스트가 동일한 파티션에 저장됩니다.
    • post_id를 클러스터링 키로 사용하여, 각 사용자의 포스트가 post_id의 내림차순으로 정렬됩니다.
    • 최신 포스트를 빠르게 조회할 수 있습니다.

2.3.2. 복합 클러스터링 키

여러 컬럼을 클러스터링 키로 사용하는 경우입니다.

CREATE TABLE sensor_data (
  sensor_id UUID,
  date DATE,
  time TIMEUUID,
  temperature FLOAT,
  PRIMARY KEY (sensor_id, date, time)
) WITH CLUSTERING ORDER BY (date ASC, time DESC);
  • 특징:
    • 동일한 sensor_iddate를 가진 데이터가 동일한 파티션에 저장됩니다.
    • time을 클러스터링 키로 사용하여, 같은 날짜 내에서 시간 순으로 데이터가 정렬됩니다.
    • 특정 날짜의 데이터를 시간 순으로 빠르게 조회할 수 있습니다.

3. 파티션 키와 클러스터링 키의 역할과 상호작용

3.1. 데이터 분산과 정렬

  • 파티션 키는 데이터가 클러스터 내의 어떤 노드에 저장될지를 결정합니다. 파티션 키의 해시값을 기반으로 데이터가 분산됩니다.
  • 클러스터링 키는 파티션 내에서 데이터의 정렬 순서를 정의합니다. 이를 통해 효율적인 범위 쿼리와 정렬된 데이터를 제공할 수 있습니다.

3.2. 데이터 모델링 시 고려 사항

  • 쿼리 패턴 우선 설계: 파티션 키와 클러스터링 키는 애플리케이션의 주요 쿼리 패턴에 최적화되어야 합니다. 어떤 쿼리를 자주 사용하는지에 따라 키를 설계합니다.
  • 파티션 크기 관리: 파티션 키가 너무 광범위하게 설정되면 파티션 크기가 커져 성능 저하가 발생할 수 있습니다. 반대로, 파티션 키가 너무 세분화되면 클러스터 전체에 데이터가 고르게 분산되지 않을 수 있습니다.
  • 정렬 순서 최적화: 클러스터링 키를 통해 자주 사용하는 정렬 기준을 설정하여 쿼리 성능을 향상시킵니다.

4. 예제 및 실습

4.1. 사용자와 주문 데이터 모델링

예를 들어, 전자 상거래 애플리케이션에서 사용자의 주문 데이터를 저장한다고 가정해보겠습니다.

4.1.1. 테이블 설계

CREATE TABLE user_orders (
  user_id UUID,
  order_id TIMEUUID,
  product TEXT,
  amount DECIMAL,
  order_date TIMESTAMP,
  PRIMARY KEY (user_id, order_id)
) WITH CLUSTERING ORDER BY (order_id DESC);
  • 파티션 키: user_id
    • 각 사용자의 주문이 동일한 파티션에 저장됩니다.
  • 클러스터링 키: order_id
    • 주문이 order_id의 내림차순으로 정렬됩니다. 최신 주문을 먼저 조회할 수 있습니다.

4.1.2. 데이터 삽입

INSERT INTO user_orders (user_id, order_id, product, amount, order_date)
VALUES (uuid(), now(), 'Laptop', 1200.00, toTimestamp(now()));

4.1.3. 데이터 조회

  • 특정 사용자의 모든 주문 조회:
  • SELECT * FROM user_orders WHERE user_id = <specific_user_id>;
  • 특정 사용자의 최근 10개 주문 조회:
  • SELECT * FROM user_orders WHERE user_id = <specific_user_id> LIMIT 10;
  • 특정 사용자의 특정 기간 동안의 주문 조회:
  • SELECT * FROM user_orders WHERE user_id = <specific_user_id> AND order_id >= minTimeuuid('2024-01-01') AND order_id <= maxTimeuuid('2024-12-31');

4.2. 복합 파티션 키와 복합 클러스터링 키 사용 예제

4.2.1. 테이블 설계

다중 컬럼을 파티션 키와 클러스터링 키로 사용하는 예제입니다. 예를 들어, 국가와 도시별로 센서 데이터를 저장한다고 가정해보겠습니다.

CREATE TABLE sensor_readings (
  country TEXT,
  city TEXT,
  sensor_id UUID,
  reading_time TIMESTAMP,
  temperature FLOAT,
  humidity FLOAT,
  PRIMARY KEY ((country, city), sensor_id, reading_time)
) WITH CLUSTERING ORDER BY (sensor_id ASC, reading_time DESC);
  • 파티션 키: (country, city)
    • 같은 국가와 도시에 속한 센서들의 데이터가 동일한 파티션에 저장됩니다.
  • 클러스터링 키: sensor_id, reading_time
    • 각 센서별로 데이터가 정렬되며, 동일한 센서 내에서는 읽기 시간에 따라 내림차순으로 정렬됩니다.

4.2.2. 데이터 조회 예제

  • 특정 국가와 도시의 모든 센서 데이터 조회:
  • SELECT * FROM sensor_readings WHERE country = 'USA' AND city = 'New York';
  • 특정 국가와 도시, 센서의 최근 5개 데이터 조회:
  • SELECT * FROM sensor_readings WHERE country = 'USA' AND city = 'New York' AND sensor_id = <specific_sensor_id> LIMIT 5;
  • 특정 국가와 도시, 센서의 특정 시간 이후 데이터 조회:
  • SELECT * FROM sensor_readings WHERE country = 'USA' AND city = 'New York' AND sensor_id = <specific_sensor_id> AND reading_time >= '2024-01-01 00:00:00';

5. 파티션 키와 클러스터링 키 설계 시 고려 사항

5.1. 파티션 키 설계 시 고려 사항

  1. 균등한 데이터 분포:
    • 파티션 키는 데이터가 클러스터 전체에 고르게 분산되도록 선택해야 합니다. 특정 파티션 키에 데이터가 집중되면 노드에 부하가 걸리고, "hot spot"이 발생할 수 있습니다.
    • 예: 사용자 ID, UUID, 해시값 등이 균등한 분포를 보장하는 파티션 키로 적합합니다.
  2. 파티션 크기 관리:
    • 하나의 파티션에 너무 많은 데이터가 저장되지 않도록 합니다. 파티션 크기가 커지면 읽기 및 쓰기 성능이 저하될 수 있습니다.
    • 일반적으로 파티션 크기는 수 MB에서 수십 MB 정도로 유지하는 것이 좋습니다.
  3. 쿼리 패턴 고려:
    • 주로 사용하는 쿼리에 맞춰 파티션 키를 설계해야 합니다. 예를 들어, 특정 사용자의 데이터를 자주 조회한다면 user_id를 파티션 키로 사용하는 것이 적합합니다.

5.2. 클러스터링 키 설계 시 고려 사항

  1. 쿼리 정렬 요구 사항:
    • 클러스터링 키를 사용하여 데이터를 원하는 순서로 정렬할 수 있습니다. 애플리케이션에서 자주 사용하는 정렬 순서에 맞춰 클러스터링 키를 설정합니다.
    • 예: 타임스탬프를 클러스터링 키로 사용하여 최신 데이터를 먼저 조회할 수 있도록 설정.
  2. 범위 쿼리 최적화:
    • 클러스터링 키를 활용하여 범위 쿼리를 효율적으로 수행할 수 있습니다. 예를 들어, 특정 시간 범위 내의 데이터를 조회할 때 유용합니다.
  3. 데이터 그룹화:
    • 클러스터링 키를 통해 관련된 데이터를 그룹화하여 저장함으로써, 관련 데이터를 함께 읽을 수 있도록 합니다.
  4. 복합 클러스터링 키:
    • 여러 컬럼을 클러스터링 키로 사용하면 보다 세밀한 정렬과 그룹화를 할 수 있습니다. 하지만 복잡성이 증가하므로 신중하게 설계해야 합니다.

5.3. 기본 키 설계 예제

예제 1: 블로그 포스트 테이블

사용자별 블로그 포스트를 저장하는 테이블을 설계합니다. 각 사용자의 포스트가 시간 순으로 정렬되어야 합니다.

CREATE TABLE blog_posts (
  user_id UUID,
  post_id TIMEUUID,
  title TEXT,
  content TEXT,
  created_at TIMESTAMP,
  PRIMARY KEY (user_id, post_id)
) WITH CLUSTERING ORDER BY (post_id DESC);
  • 파티션 키: user_id — 각 사용자의 모든 포스트가 동일한 파티션에 저장됩니다.
  • 클러스터링 키: post_id — 각 사용자의 포스트가 post_id의 내림차순으로 정렬됩니다.
  • 장점: 특정 사용자의 최신 포스트를 빠르게 조회할 수 있습니다.

예제 2: 상품 리뷰 테이블

각 상품에 대한 리뷰를 저장하는 테이블을 설계합니다. 리뷰는 사용자별로 정렬되어야 합니다.

CREATE TABLE product_reviews (
  product_id UUID,
  review_id TIMEUUID,
  user_id UUID,
  rating INT,
  comment TEXT,
  PRIMARY KEY (product_id, review_id)
) WITH CLUSTERING ORDER BY (review_id DESC);
  • 파티션 키: product_id — 각 상품의 모든 리뷰가 동일한 파티션에 저장됩니다.
  • 클러스터링 키: review_id — 각 상품의 리뷰가 review_id의 내림차순으로 정렬됩니다.
  • 장점: 특정 상품의 최신 리뷰를 빠르게 조회할 수 있습니다.

예제 3: 채팅 메시지 테이블

사용자 간의 채팅 메시지를 저장하는 테이블을 설계합니다. 메시지는 시간 순으로 정렬되어야 합니다.

CREATE TABLE chat_messages (
  chat_id UUID,
  message_id TIMEUUID,
  sender_id UUID,
  message TEXT,
  sent_at TIMESTAMP,
  PRIMARY KEY (chat_id, message_id)
) WITH CLUSTERING ORDER BY (message_id ASC);
  • 파티션 키: chat_id — 각 채팅 대화의 모든 메시지가 동일한 파티션에 저장됩니다.
  • 클러스터링 키: message_id — 각 채팅 대화의 메시지가 message_id의 오름차순으로 정렬됩니다.
  • 장점: 특정 채팅 대화의 모든 메시지를 시간 순으로 효율적으로 조회할 수 있습니다.

6. 파티션 키와 클러스터링 키 설계의 최적화 전략

6.1. 파티션 키 최적화 전략

  1. 고유성과 균등성 유지:
    • 파티션 키는 가능한 한 고유하고 균등하게 분포되도록 설계해야 합니다. 예를 들어, 사용자 ID나 UUID는 고유성과 균등한 분포를 보장하는 좋은 파티션 키가 될 수 있습니다.
  2. 파티션 크기 관리:
    • 하나의 파티션에 너무 많은 데이터를 저장하지 않도록 주의합니다. 필요하다면 추가적인 파티션 키 컬럼을 도입하여 파티션 크기를 분산시킬 수 있습니다.
    • 예: 시간 기반 파티션 키 (year, month)를 사용하여 파티션 크기를 관리.
  3. 쿼리 패턴 반영:
    • 주로 사용하는 쿼리에 맞춰 파티션 키를 설계합니다. 예를 들어, 특정 사용자나 특정 시간 범위의 데이터를 자주 조회한다면, 이에 맞춰 파티션 키를 설정합니다.

6.2. 클러스터링 키 최적화 전략

  1. 자주 사용하는 정렬 기준 설정:
    • 클러스터링 키는 애플리케이션에서 자주 사용하는 정렬 기준을 반영해야 합니다. 예를 들어, 시간 순서대로 데이터를 정렬해야 한다면 타임스탬프 컬럼을 클러스터링 키로 사용합니다.
  2. 범위 쿼리 최적화:
    • 클러스터링 키를 활용한 범위 쿼리를 최적화할 수 있도록 설계합니다. 예를 들어, 날짜나 시간 기반의 클러스터링 키를 사용하면 특정 기간 동안의 데이터를 효율적으로 조회할 수 있습니다.
  3. 복합 클러스터링 키 사용:
    • 여러 컬럼을 클러스터링 키로 사용하여 세밀한 정렬과 그룹화를 할 수 있습니다. 단, 복잡성이 증가하므로 신중하게 설계해야 합니다.
    • 예: PRIMARY KEY (user_id, region, timestamp)

6.3. 데이터 모델링의 일반적인 실수와 피해야 할 점

  1. 너무 큰 파티션 키 사용:
    • 너무 많은 컬럼을 파티션 키로 사용하는 것은 피해야 합니다. 이는 파티션 키의 해시값이 너무 다양해져 클러스터 전체에 데이터가 균등하게 분산되지 않을 수 있습니다.
  2. 불균형한 데이터 분포:
    • 파티션 키가 특정 값에 치우쳐 있으면, 일부 노드에 데이터가 집중되어 성능 저하 및 "hot spot" 문제가 발생할 수 있습니다.
  3. 불필요한 데이터 중복:
    • 클러스터링 키를 잘못 설계하면 동일한 데이터가 여러 파티션에 중복 저장될 수 있습니다. 데이터 중복은 저장 공간을 낭비하고 데이터 일관성 유지에 어려움을 줄 수 있습니다.
  4. 부적절한 클러스터링 키 선택:
    • 클러스터링 키가 쿼리 패턴과 맞지 않으면 범위 쿼리가 비효율적이거나, 정렬된 데이터를 활용하지 못할 수 있습니다.

7. 튜너블 일관성(Tunable Consistency)과 파티션 키, 클러스터링 키의 관계

Cassandra는 튜너블 일관성을 지원하여, 데이터 읽기 및 쓰기 작업 시 일관성 수준을 조정할 수 있습니다. 파티션 키와 클러스터링 키는 이러한 일관성 설정과 밀접한 관련이 있습니다.

7.1. 읽기 일관성(Read Consistency)

  • QUORUM: 파티션 키에 따라 데이터가 저장된 여러 노드에서 쿼럼을 만족하는 응답을 받습니다.
  • LOCAL_QUORUM: 특정 데이터 센터 내에서 쿼럼을 만족하는 응답을 받습니다.
  • ONE, TWO, THREE: 최소한의 노드에서 응답을 받습니다.

7.2. 쓰기 일관성(Write Consistency)

  • QUORUM: 파티션 키에 따라 데이터가 복제된 노드의 과반수에서 쓰기 작업이 성공해야 합니다.
  • LOCAL_QUORUM: 특정 데이터 센터 내에서 복제된 노드의 과반수에서 쓰기 작업이 성공해야 합니다.
  • ALL: 모든 복제 노드에서 쓰기 작업이 성공해야 합니다.

7.3. 일관성 설정과 데이터 분산의 관계

  • 파티션 키는 데이터를 여러 노드에 분산시킵니다. 일관성 설정은 이러한 분산된 노드에서 데이터의 일관성을 유지하는 데 중요한 역할을 합니다.
  • 클러스터링 키는 파티션 내에서 데이터의 정렬을 관리하므로, 일관성 설정과는 직접적인 관련은 없지만, 파티션 키를 통한 데이터 접근의 효율성을 높여 일관성 있는 데이터를 빠르게 조회할 수 있게 합니다.

8. 결론

카산드라의 파티션 키클러스터링 키는 데이터 모델링의 핵심 요소로, 데이터의 분산 저장과 정렬을 효율적으로 관리하는 데 중요한 역할을 합니다. 파티션 키는 데이터가 클러스터 내에서 어떻게 분산되는지를 결정하며, 클러스터링 키는 각 파티션 내에서 데이터가 어떤 순서로 정렬되고 조회되는지를 결정합니다.

효과적인 데이터 모델링을 위해서는 다음 사항을 고려해야 합니다:

  1. 쿼리 패턴을 우선으로 데이터 모델링: 애플리케이션의 주요 쿼리 패턴을 이해하고, 이에 최적화된 파티션 키와 클러스터링 키를 설계합니다.
  2. 균등한 데이터 분포: 파티션 키가 데이터가 고르게 분산되도록 선택하여 클러스터의 성능과 확장성을 극대화합니다.
  3. 적절한 클러스터링 키 선택: 데이터의 정렬과 범위 쿼리를 효율적으로 수행할 수 있도록 클러스터링 키를 설계합니다.
  4. 파티션 크기 관리: 파티션 키를 적절히 설계하여 각 파티션의 크기가 적절하게 유지되도록 합니다.

이러한 요소들을 종합적으로 고려하여 파티션 키와 클러스터링 키를 설계하면, 카산드라의 뛰어난 확장성과 성능을 최대한 활용할 수 있습니다.

반응형