1. ホーム
  2. データベース
  3. モンゴルディーブ

MongoDBのレンジスライスキーとハッシュスライスキーについて説明します。

2022-01-19 03:01:05

01スライスキー

    MongoDB のスライスキーは、コレクションに格納されたデータをどのように分配するかを、スライスキーの値の範囲を使って決定します。例として

スライスキーに年齢を使う場合、年齢の範囲は理論的には0~80ですが、現時点ではMongoDBは4つの年齢範囲を定義してくれます。0~20, 20~40, 40~60, 60~80, 各範囲はチャンクで、データを書き込んだ後、データチャンクの中のデータは次のようになります。

chunk1: 年齢 0~20

chunk2: 20~40歳   

chunk3: 40~60歳

chunk4:60歳〜80歳

コレクションでは、スライスキーとして選択されたこのフィールドに、スライスキーをサポートするインデックスが存在するか、このフィールドから始まるユニオンインデックスが存在しなければならないことに注意してください。

通常、フィールドに追加するインデックス、最も一般的なのはノーマルインデックスやハッシュインデックスですが

は、スライスキーとして機能する通常のインデックスフィールドで、レンジスライスキーと呼ばれるスライスキーです。

ハッシュインデックスフィールドがスライスキーとして使用される場合、このスライスキーをハッシュスライスキーと呼びます。

ここでは、両者の違いについて見ていきます。

02 レンジスライスキー(インクリメンタルスライスキー)

レンジスライスキーとは、その名の通り、スライスキーを元にデータを連続した範囲に分割し、その中で"similar"の値を持つドキュメントが同じスライスに位置することがあるモデルである。例えば、次のようなものである。

このシャーディング方法は、MongoDBのデフォルトのシャーディング方法であり、利点と欠点があります。

メリット

    対象文書を連続した範囲で効率的に読み取ることができます。範囲指定クエリを使えば、比較的早くすべての結果値を得ることができる。これは、データが配置されているデータチャンクが少ないためである。

悪いこと

    あるスライス間隔で数種類のデータを書き込むと、スライスキー分割が不均一になり、読み書きの性能が低下することがあります。(例えば、下図の場合、データ基盤のほとんどが20~maxKeyにあり、次にそのほとんどがチャンクCの場所にあり、それ自体が偏在している)、チャンクCへの書き込み圧力が増加することになるのです。

以下のシナリオでは、レンジピースキーを使用するのがより適切です。

1、データのベースが比較的大きい

2、スライスの書き込み頻度が比較的低い(簡単にチャンクを生成しない少ない処理を挿入する)。

3、非単調に変化するスライス(単調に書き込まれると、内部で同じブロックに分割され、チャンクカット条件に到達しやすく、チャンクハンドリングが発生する)。

上記の3つの条件を満たすデータであれば、書き込むデータはこのようになる可能性があります。

の方がデータブロックに均等に書き込まれます。

03 ハッシュスライスキー

    ハッシュスライスキーは、共有クラスタ内のデータを分割するためにハッシュインデックスを使用します。ハッシュインデックスは一つのフィールドのハッシュをインデックス値として計算し、それをスライスキーとして使用します(ここではフィールドの値そのものではなく、ハッシュ化後の値であることに注意してください)。

    ハッシュインデックスを使って、データを書き込むと、対応する書き込まれたデータブロックのグラフィカルな表現は次のようになります。

図から、入力したxの値はそれぞれ25、26、27と比較的近い値ですが、ハッシュ関数後、それらが入っているデータブロックの番号が離れている可能性があることがわかります。

ハッシュシャードでは、シャード化されたクラスタ内のデータをより均等に分散させることができます。コレクション内の近い値を持つ文書は異なるブロックにシャーディングされる可能性があり、mongosは与えられた範囲のクエリを完了するためにブロードキャスト処理を実行する可能性が高くなります。

ハッシュ値の計算は、アプリケーションではなくMongoDBが担当する

ハッシュスライスキーであるインデックスフィールドは、以下の特徴を持つ必要があります。

1. 多種多様な値を持つ

2、ハッシュインデックスは、自己値、時間値などの単調に変化するフィールドに適しています(単調に変化するフィールドは、ハッシュ関数を通じて別のブロックにマッピングすることができますので、書き込み圧力を広げ、例えば、次の図は、データが連続ですが、それはデータの異なるブロックに書き込まれます)。

また、ある範囲の値を問い合わせたときに、ハッシュ・インデックスがより多くのデータの断片を探し、最終的な結果を集約して出してしまうという明らかな欠点もある。

実際の生産環境では、ニーズを組み合わせて、どのタイプのスライス・キーを使用するかを決定する必要があります。繰り返しますが、あるフィールドをスライスキーとして設定する前に、現在のフィールドに対応する型のインデックスを作成するか、現在のフィールドから始まるジョイントインデックスを作成する必要があります。そうでなければ、スライス・キーを設定するステートメントがエラーを報告します。

以下は、無から有へのスライス作成処理の例である。

1. Create a table with a single field name and insert data
mongos> use aaa
switched to db aaa
mongos> db.aaa.insert({name:1})
WriteResult({ "nInserted" : 1 })
mongos> db.aaa.insert({name:2})
WriteResult({ "nInserted" : 1 })
mongos> db.aaa.insert({name:3})
WriteResult({ "nInserted" : 1 })
mongos> db.aaa.insert({name:4})
WriteResult({ "nInserted" : 1 })
mongos> 

2. View data
mongos> db.aaa.find()
{ "_id" : ObjectId("5fdb7d54d91f2f9bae3b09a1"), "name" : 1 }
{ "_id" : ObjectId("5fdb7d56d91f2f9bae3b09a2"), "name" : 2 }
{ "_id" : ObjectId("5fdb7d59d91f2f9bae3b09a3"), "name" : 3 }
{ "_id" : ObjectId("5fdb7d5cd91f2f9bae3b09a4"), "name" : 4 }

3. Allow database sharding
mongos> sh.enableSharding("aaa")
{
 "ok" : 1,
 "operationTime" : Timestamp(1608220038, 3),
 "$clusterTime" : {
  "clusterTime" : Timestamp(1608220038, 3),
  "signature" : {
   "hash" : BinData(0,"shemm3xvSYrMiy9t7gSYcVtFUuE="),
   "keyId" : NumberLong("6894922308364795934")
  }
 }
}
mongos> 

4. Create a hash index in the name field
mongos> db.aaa.createIndex({name:"hashed"},{background:true})
{
 "raw" : {
  "sharding_yeyz/127.0.0.1:27018,127.0.0.1:27019,127.0.0.1:27020" : {
   "createdCollectionAutomatically" : false,
   "numIndexesBefore" : 1,
   "numIndexesAfter" : 2,
   "ok" : 1
  }
 },
 "ok" : 1,
 "operationTime" : Timestamp(1608220115, 3),
 "$clusterTime" : {
  "clusterTime" : Timestamp(1608220115, 3),
  "signature" : {
   "hash" : BinData(0,"S3Wz9G26eJyOcwa1OLS6TVYu6SE="),
   "keyId" : NumberLong("6894922308364795934")
  }
 }
}

5. Create a hash slice with the name field as the slice key
mongos> sh.shardCollection("aaa.aaa",{name:"hashed"})
{
 "collectionsharded" : "aaa.aaa",
 "collectionUUID" : UUID("20a3895e-d821-43ae-9d28-305e6ae03bbc"),
 "ok" : 1,
 "operationTime" : Timestamp(1608220238, 10),
 "$clusterTime" : {
  "clusterTime" : Timestamp(1608220238, 10),
  "signature" : {
   "hash" : BinData(0,"qeQlD3jsSvRZkyamEa2hjbezEdM="),
   "keyId" : NumberLong("6894922308364795934")
  }
 }
}

6. View the sharding information
mongos> db.printShardingStatus()
--- Sharding Status --- 
 sharding version: {
 "_id" : 1,
 "minCompatibleVersion" : 5,
 "currentVersion" : 6,
 "clusterId" : ObjectId("5fafaf4f5785d9965548f687")
 }
 shards:
 { "_id" : "sharding_yeyz", "host" : "sharding_yeyz/127.0.0.1:27018,127.0.0.1:27019,127.0.0.1:27020& quot;, "state" : 1 }
 { "_id" : "sharding_yeyz1", "host" : "sharding_yeyz1/127.0.0.1:27024,127.0.0.1:27025,127.0.0.1:27026& quot;, "state" : 1 }
 active mongoses:
 "4.0.6" : 1
 autosplit:
 Currently enabled: yes
 balancer:
 Currently enabled: yes
 Currently running: no
 Failed balancer rounds in last 5 attempts: 2
 Last reported error: Could not find host matching read preference { mode: "primary" } for set sharding_yeyz
 Time of Reported error: Wed Nov 18 2020 17:08:14 GMT+0800 (CST)
 Migration Results for the last 24 hours: 
  No recent migrations
 databases:
 { "_id" : "aaa", "primary" : "sharding_yeyz", "partitioned" : true, "version" : { "uuid" : { "uuid" "uuid" : UUID("26e55931-d1c1-4dc5-8a03-b5b0e70f6f43"), "lastMod" : 1 } }
  aaa.aaa
   shard key: { "name" : "hashed" }
   unique: false
   balancing: true
   chunks:
    sharding_yeyz 1
   { "name" : { "$minKey" : 1 } } -->&