🗄️

シャーディングとは

2024/04/03に公開

データベースを複数のシャードと呼ばれる小さなデータベースに分割する技術

シャードはそれぞれ独立したサーバーでホストされ、データは複数のシャードに分散される

利点

  • スケーラビリティ: データ量が増加しても、シャードを追加することで簡単にスケールアウトできる
  • パフォーマンス: データが複数のサーバーに分散されるため、クエリ処理のパフォーマンスが向上する
  • 可用性: 一つのシャードが故障しても、他のシャードが存続するため、可用性を向上できる

種類

キーベースシャーディング

データのキーに基づいてシャードに割り当てる

Python

# キーベースシャーディングの例

def get_shard_id(key):
    # ハッシュ関数を使用してキーに基づいてシャードIDを計算
    return hash(key) % num_shards

# データベースへのアクセス
def get_data(key):
    shard_id = get_shard_id(key)
    shard = shards[shard_id]
    # シャードからデータを取得
    return shard.get(key)

# データベースへの書き込み
def set_data(key, value):
    shard_id = get_shard_id(key)
    shard = shards[shard_id]
    # シャードにデータを設定
    shard.set(key, value)

# シャードのリスト
shards = [
    # シャード1
    ...,
    # シャード2
    ...,
    # シャードN
    ...,
]

# 使用例
key = "user_123"
value = {"name": "John Doe", "age": 30}

get_data(key)
set_data(key, value)

レンジベースシャーディング

データの値の範囲に基づいてシャードに割り当てる

Python

# レンジベースシャーディングの例

def get_shard_id(value):
    # 値の範囲に基づいてシャードIDを計算
    if value < 1000:
        return 0
    elif value < 10000:
        return 1
    else:
        return 2

# データベースへのアクセス
def get_data(value):
    shard_id = get_shard_id(value)
    shard = shards[shard_id]
    # シャードからデータを取得
    return shard.get(value)

# データベースへの書き込み
def set_data(key, value):
    shard_id = get_shard_id(value)
    shard = shards[shard_id]
    # シャードにデータを設定
    shard.set(key, value)

# シャードのリスト
shards = [
    # シャード1 (値 < 1000)
    ...,
    # シャード2 (1000 <= 値 < 10000)
    ...,
    # シャード3 (値 >= 10000)
    ...,
]

# 使用例
key = "product_123"
value = 5000

get_data(value)
set_data(key, value)

ディレクトリベースシャーディング

データの属性に基づいてシャードに割り当てる

Python

# ディレクトリベースシャーディングの例

def get_shard_id(country):
    # 国名に基づいてシャードIDを計算
    if country == "日本":
        return 0
    elif country == "アメリカ":
        return 1
    else:
        return 2

# データベースへのアクセス
def get_data(key, country):
    shard_id = get_shard_id(country)
    shard = shards[shard_id]
    # シャードからデータを取得
    return shard.get(key)

# データベースへの書き込み
def set_data(key, value, country):
    shard_id = get_shard_id(country)
    shard = shards[shard_id]
    # シャードにデータを設定
    shard.set(key, value)

# シャードのリスト
shards = [
    # シャード1 (日本)
    ...,
    # シャード2 (アメリカ)
    ...,
    # シャード3 (その他)
    ...,
]

# 使用例
key = "user_123"
value = {"name": "John Doe", "age": 30}
country = "日本"

get_data(key, country)
set_data(key, value, country)

課題

  • 複雑性: シャーディングの設計と運用は複雑な場合が多い
  • データの整合性: 複数のシャードに分散されたデータの整合性を保つ必要がある
  • トランザクション: シャードにまたがるトランザクション処理は複雑な場合が多い

  1. 1億人の顧客情報を持つデータベースをシャーディングする
    • 顧客IDに基づいて100個のシャードに分割する
    • 各シャードは1000万人の顧客情報を格納する
    • クエリ処理は、顧客IDに基づいて特定のシャードに送信される
  2. 商品情報を扱うECサイトのデータベースをシャーディングする
    • 商品カテゴリに基づいてシャードに分割する
    • 例えば、家電、衣類、食品などのカテゴリごとにシャードを作成する
    • ユーザーは、特定のカテゴリの商品のみを検索する場合、そのカテゴリのシャードにのみクエリを送信する

関連記事

SQLとNoSQLの違い

https://zenn.dev/btc/articles/240402_mysql_nosql

Discussion