🐱 うさねこ教室 Python と可観測性の教室

パーティショニング

🐱 この章の目次

なぜパーティショニングが必要か

パーティショニング(シャーディング) とは、データを複数のノードに分割して格納することです。 1 台のノードに収まらないデータ量や、1 台では処理しきれないスループットに対応するために使います。 『データ指向アプリケーションデザイン』第 6 章では、分割の戦略とその落とし穴を詳しく解説しています。

キーレンジパーティショニング

キーレンジパーティショニングは、キーの値の範囲でデータを分割する方式です。 たとえばタイムスタンプで分割すれば、ある期間のデータは 1 つのパーティションにまとまるため範囲クエリが効率的です。 一方で、直近のデータにアクセスが集中するホットスポットが発生しやすいという欠点があります。

ハッシュパーティショニング

ハッシュパーティショニングは、キーのハッシュ値に基づいてパーティションを決定する方式です。 ハッシュ関数がキーを均等に分散させるため、ホットスポットが起きにくくなります。 ただし、範囲クエリを実行すると全パーティションにリクエストを送る必要があり、効率が落ちます。

# ハッシュパーティショニングの概念例
import hashlib

def get_partition(key: str, num_partitions: int) -> int:
    """キーのハッシュ値からパーティション番号を決定する"""
    h = hashlib.md5(key.encode()).hexdigest()
    return int(h, 16) % num_partitions

# user_id に基づいてパーティションを選択
partition = get_partition("user_12345", num_partitions=8)
print(f"Partition: {partition}")

セカンダリインデックスとパーティション

セカンダリインデックスをパーティション環境で扱う方法は 2 つあります。

方式特徴読み取りコスト
ローカルインデックス(ドキュメントベース)各パーティションが自分のデータだけをインデックス化全パーティションに scatter/gather
グローバルインデックス(タームベース)インデックス自体を別のパーティション分割対象パーティションのみ読み取り

ローカルインデックスは書き込みが速い反面、読み取り時にファンアウトが発生します。 グローバルインデックスは読み取りが速い反面、書き込み時に分散トランザクションが必要になります。

リバランシング

ノードの追加・削除時にデータを再配置する操作をリバランシングと呼びます。 固定数パーティション方式では、パーティション数をノード数より十分多く設定し、ノード追加時にパーティション単位で移動します。 コンシステントハッシングを用いると、ノード変更時に移動するデータ量を最小限に抑えられます。