mongo sharding

Post on 15-Jan-2015

48.145 Views

Category:

Documents

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

Sharding 詳解

〜機能と仕組みの理解〜doroykujin

自己紹介• doryokujin (25 歳 )

• 諭吉大学院 数学科 卒業できました

• MongoDB JP 主催者

• 芸者東京エンターテインメント (GTE) データマイニングエンジニア

発表の目的• Mongo Sharding への理解を深めてほしい– 1. Mongo Sharding の特徴を知ってほしい– 2. なかなか知り得ない機能詳細や意外な振る

舞いがあることを知って欲しい– 3. 使用上における問題点をきちんと把握して

おいて欲しい– 4. Mongo Sharding を試すきっかけになって

欲しい

発表の内容• 「 Scaling MongoDB」

の内容を 7 割方網羅– Mongo Sharding に焦点

を絞って書かれた本

– この本を読むこと Sharding への理解がかなり深まる

• 併せてドキュメントの内容も盛り込んでいる

アジェンダ• 1. Mongo Sharding の 3 つのコンセプ

トを紹介→ 概要の理解

• 2. Mongo Sharding の機能・振る舞いを4 つのキーワードから紹介→ 個々の機能の深い理解

最終的に言いたいこと• Shard Key の設定は非常に重要、慎重に

– Shard の偏りを極力減らす事は重要

– Shard Key によって偏り具合が大きく異なる

• Sharding 環境におけるクエリは振る舞いが怪しい部分があるので要注意(重複問題)

– 正しい count() が行われない

– unique のはずのキーが重複して存在

Mongo Sharding 3 つのコンセプト

Sharding とは?• 定義: DB 上のデータを複数のサーバーに

分割して運用すること• メリット:個々のサーバーの– 負荷の軽減– 使用領域を軽減– パフォーマンス向上– 扱えるデータサイズの向上

Mongo Sharding Concept

• MongoDB の掲げる 3 つのコンセプト

– 「 Make the cluster “invisible” 」

– 「 Make the cluster always available for reads and writes 」

– 「 Let the cluster grow easily 」

Mongo Sharding Concept 1

• Make the cluster “invisible”

– 全ての接続を mongos サーバーが仲介することによってクライアントはクラスタ全体の情報を意識することなく扱える

– クライアントは Sharding していない状況と同じようにクエリを発行し、結果を得ることができるより高速に)

Mongo Sharding Concept 2

• Make the cluster always available for reads and writes

– Auto-Failover で MongoDB のダウン時間を減らせ、常にデータにアクセスできる状態

– データの自動分割や Auto-balancing によって常に安定した状態を保ち続けられる

Mongo Sharding Concept 3

• Let the cluster grow easily

– Shard の追加・撤退が容易にできる– 新しい Shard の追加に対して自動的にデータ

の移行・均一化が図れる( Migration, Auto-Balancing )

Mongo Sharding を理解するための 4つのキーワード

Mongo Sharding を理解するための 4つのキーワード

• Shard Key:

– コレクションを分割する際のキー

• Balancing, Migration:

– Shard 間のデータの均等な分散を維持する仕組み

• mongos, config, mongod:

– Sharding を構成する 3 種類のサーバー

• Sharding クエリ :

– Sharding 環境におけるクエリの振舞と問題点

1. Shard Key

Shard Key :概略• データの分割は何らかのキーに従って行う• それを Shard Key と呼ぶ• Shard Key は Collection 内のどれか 1 つのキー

から選択• 各 Shard 内のデータは Chunk と呼ばれるデータ

単位で分割・移動・削除などが行われる• Shard 間の偏りとは、 Chunk の数が一部に偏る事• Shard が偏るのはよろしくない

Chunk に関して• Chunk は、特定のコレクションの連続した範囲

のデータ集合• データがどの Chunk に属するかは、 Shard

Key の値によって決まる• Chunk はデータサイズが 200MB (デフォル

ト)を超えると自動で等分割が行われる• 分割されるごとに Shard 内の Chunk 数が増

加• Shard Key は型の混在が可能。MongoDB は

全ての型を通して順序が決まっている

http://www.10gen.com/static/presentations/scaling-jp.pdf

データが挿入されていく度にChunk が分割されていくとしてその様子をみてみる

これが Chunk と呼ばれるデータの集合単位。連続した範囲のデータ集合。新しいデータは Shard Keyの値が Chunk の範囲内にある所に入る。 200MB を超える度に分割が起こる。(デフォルト)

Chunk に関する注意点

• 各々の Chunk の持つ範囲は絶対に重複しない。1 つのデータに対してただ 1 つの Chunk が対応。範囲は [ a, b ) で、左を含み右を含まない

• Shard Key は変更できない。やり直したい場合は対象の Collection を削除してから

• ShardKey の値を持たないドキュメントは保存できない。ただし null は可能

2. Balancing, Migration

Auto-balancing, Migration• Auto-balancing

– ある特定の Shard に Chunk が集中した場合、自動で他の Shard への移行( =Migration )

– トリガーは Shard 内における最大 Chunk 数と最小 Chunk 数の差が 10以上になったとき

• デフォルトで最大 200MB/Chunk なのでデータサイズの差が 2GB以上になったとき

– 最大 Shard からランダムに 5 つの Chunk が選ばれ、最小 Shard への Migration が行われる

Migration における問題• ※ Migration には多大なコストがかかる– config サーバーへの負担–ネットワーク帯域の圧迫– メモリ領域の圧迫( Chunk をメモリにコピーするので)

– パフォーマンスの低下– 正しいクエリの結果を返さない(後述)–低速。完了に非常に時間がかかる

1. (再) Shard Key

Shard Key 選択の重要性• Migration は極力起こらないように

• つまり Shard 間に Chunk の偏りがない

• Shard 間に偏り少なくなる Shard Key を選択

• 一度選択した ShardKey は変更できないので慎重に

Shard Key: 悪い例①• Low-Cardinality Shard Key

– 「密度」の低い Shard Key

– 主にカテゴリデータなどの”離散”データ– 例:大陸名

• (-∞, America], (America, Asia], (Asia, Australia],…

– 理由:• Chunk の分割ができない

• N 個のカテゴリ数なら N 個の Chunk しかできない

• N 個以上の Shard サーバーは意味がない

Shard Key: 悪い例②• Ascending Shard Key

– Shard Key の値が増えていくのみのデータ– Time, ObjectId, Incremental Unique Id

– 例:• [-∞, +∞ )

• → [ -∞, 12945 ), [12945, +∞ )

• → [ -∞, 12945 ), [12945, 12948 ), [ 12948, +∞ )

– 理由:• ( $CurrentMax, +∞ ] の Chunk だけがひたすら分割• 明らかに Shard 間で不均一がおこる

ShardKey: 悪い例③• Random Shard Key

– Shard Key の値が Random に決まる場合–例: MD5 hash

– 理由:• Chunk は均等分散するが非常に大きな範囲を

持った Chunk が存在する可能性

• その Chunk の Migration は RAM を圧迫する

• Random Shard Key に対する Index も非効率

Shard Key: 良い例• Coarsely Ascending Key + Search Key

– 緩く増加していくキー + 検索でよく使われるキー– 例:アクセス解析 { month:1, user: 1}

• ( (“2011-04”,”doryokujin”), (“2011-04”, “gohan”) ),

( (“2011-04”,”gohan”), (“2011-04”, “taberu”) ),…

– 理由:• 左のキーは一定期間固定で、右のキーはほぼ均等に分布し

てくれる

• 時間がたつと左のキーの値が増え、元の(解析対象としない、古い)値の Chunk は分割されなくなり、 Migration が起こりにくくなる

良い Shard Key のイメージ• 長い時間が経って Shard の偏りが起き始

める頃に、片方のキーが増加して Shard をリフレッシュしてくれる

shard1 shard2 shard3 shard4 shard5 shard6

2011/04 2011/05

name

month

3. mongos, config, mongod

Sharding を構成するサーバー群

config Servers(Shard Configration)

mongos Servers (Routers)

Shard Servers (Data)

[ a, f )

[ f, k )

[ k, n)

[ n, o )

[ o, t )

[ t, } )

shard1 shard2 shard3

Chunk

Cluster

サーバー間の関係

http://www.mongodb.org/display/DOCS/Sharding+Introduction

mongos サーバー

クライアントのアクセスは必ず mongos に対して行う

該当データのある Shard にのみクエリの送出・データの取得を行う

cinfig サーバーから Shard に関する情報を取得する

mongos サーバーの役割• クライアントは全ての読み書きを

mongos に対して行う• mongos はどの Chunk がどの Shard

にあるかを把握している• ただし永続的な情報を保存するわけでは

ない。 config サーバーがそれを持つ• [ ダウン ] : Shard にアクセス不能にな

るので、完全に機能停止することに

config サーバー

“ 特殊な” mongod サーバー

shard に関する (永続的な )メタ情報を保持

change chunkSizedisable Balancing

config サーバーの役割

• shards, mongos process, sysadmin に関するメタ情報を保持

• 複数起動可能。ただしテスト環境は 1 つ、本番環境でも 3 つで十分( 3 で最適化)

• 独自のプロトコルで同期を行う。手動でReplication の設定をしてはいけない

• [ ダウン ] : Shard の設定変更が不可能になる。読み書きは継続

config Collection> use configswitched to db config

> show collections changelog # 過去の Migration に関する詳細なログ chunks # 全ての Chunk の情報 collections # Sharding している全ての Collection の情報 databases # 全 DB に関して Sharding の有無などの情報 lockpingslocksmongos # mongos に関する情報settings # chunkSize の設定情報、 balancer 機能の切替shards # Shard に関する情報system.indexesversion

> db.settings.update({"_id" : "balancer"}, {"$set" : {"stopped" : true }}, true)

4. Sharding クエリ

mongos へのクエリタイプ• Targeted– Shard Key が指定されることによって、必要

なデータがある shard にのみアクセス。最小限。

• Global– Shard Key が指定されず、 mongos プロセ

スはシステム内の ( ほぼ ) すべての Shard にアクセス

Shard Key を用いての find()

{“name”: “inoue” }

[ k, n)

[ n, o )

shard2mongos

[ a, f )

[ f, k )

shard1

{“name”: “tanaka” }

[ o, t )

[ t, } )

shard3

指定された Shard Key (“name” key) を含む Chunk のある Shard にのみクエリの発行・データの取得を行う

db.adminCommand({"shardCollection" : ”mongo.users", key : {”name" : 1}}

db.shardCollection.find({“shardKey”: “xxx”})

targeted

db.shardCollection.find({“nonShardKey”: “xxx”})

[ k, n)

[ n, o )

shard2mongos

[ a, f )

[ f, k )

shard1

{“pref”: “Tokyo” }

[ o, t )

[ t, } )

shard3

mongos は Shard Key 以外 (“pref” key) の情報を知り得ないので全ての Shard にアクセスする。

ただしインデックスを利用できる。

db.adminCommand({"shardCollection" : ”mongo.users", key : {”name" : 1}}

Non Shard Key を用いての find()global

db.shardCollection.update({“shardKey”: “x”},{$set{key:value}})

{“name”: “inoue” }

[ k, n)

[ n, o )

shard2mongos

[ a, f )

[ f, k )

shard1

{“name”: “tanaka” }

[ o, t )

[ t, } )

shard3

指定された shard key(“name” key) を含む chunk のあるshard にのみクエリの送出・データの取得を行う

db.adminCommand({"shardCollection" : ”mongo.users", key : {”name" : 1}}

update

update

Shard Key を用いての single-update()

targeted

db.shardCollection.find().sort({“nonShardKey”: 1})

[ k, n)

[ n, o )

shard2

[ a, f )

[ f, k )

shard1

[ o, t )

[ t, } )

shard3

sort() が呼ばれた場合は、各 Shard における検索結果のドキュメント集合に対して sort を行い、さらに mongos が全 Shard で merge sort

shard1 内で sort

shard2 内で sort

shard3 内で sort

shard1,2,3 の結果を merge sort

{“pref”: “Tokyo” } mongos

Non Shard Key を用いての sort()

global

db.shardCollection.count ({“nonShardKey”: 1})

[ k, n)

[ n, o )

shard2

[ a, f )

[ f, k )

shard1

[ o, t )

[ t, } )

shard3

count() が呼ばれた場合は、各 Shard における検索結果のドキュメント集合に対して count を

行い、さらに mongos が全 Shard の結果で total

shard1 内で count

shard2 内で count

shard3 内で count

shard1,2,3 の結果で count

{“pref”: “Tokyo” } mongos

Non Shard Key を用いての count()

global

db.runCommand ({mapreduce: shardedCollection,…})

[ k, n)

[ n, o )

shard2mongos

[ a, f )

[ f, k )

shard1

[ o, t )

[ t, } )

shard3

mapreduce

mapreduce

shard1,2,3 の結果で ” re”-reduce

mapreduce

Non Shard Key を用いての mapreduce()

emit( “pref”: 1 )

mapreduce() が呼ばれた場合は、各 Shard における検索結果のドキュメント集合に対して mapreduce を行い、さらに mongos が全 Shard の結果で reduce

global

{ x : 1 } Shard Key と仮定。targeted では Shard へのアクセスは最小限global は、システム内の ( ほぼ ) すべての Shard にアクセス

Shard Key を使用しない場合に問題のあるクエリ

• Sharding 環境で Shard Key を使用しないクエリは、必ずしも正しく実行されるとは限らない– 「 Chunk Migration 中の count() 」– 「同時書き込み発生時の single-update() 」– 「同時書き込み発生時の unique index 」– 「 tmp_collection が削除されない

mapreduce() 」

Chunk Migration 中の count()

• Chunk Migration 中は処理が完了するまで、移動元・移動先に同じ Chunk が存在する

• 完全にコピーが完了し、 config サーバーが更新されて完了となる

• その間に count() コマンドが実行された場合、この Chunk のデータは重複してカウントしてしまう可能性がある。

• 結果:真値より大きくなる

mongos

shard2shard1

X

shard2shard1

X

shard2shard1

X

X

移行中…

count X

count X

Chunk Migration 中の count()

重複カウント

同時書き込み発生時のunique Index

• MongoDB は書き込みに対してロックを行わない(複数の書き込みに対してアトミックでない)

• unique な Index として設定したキー(Shard Key では無い ) が異なる Shard 間で存在する可能性がある

• “_id” でさえも重複する可能性がある• 結果: Shard Key 以外のユニーク性が保証されない

mongos

shardKey={“email”:1} とは別に unique Index={“name”:1} である Key での update が同時に行われた場合、 unique

キーなのに重複する可能性がある

shard 1

X

shard2

shard3

Y

Z

mongos

{"_id" : ObjectId("4d2a2f7c56d1bb09196fe7d0"), ”name" : ”doryokujin", "email" : “doryokujin@example.com” }

{"_id" : ObjectId("4d2a2e9f74de15b8306fe7d0"), ”name" : ”doryokujin", "email" : ”inoue@example.com"

update

update

同時書き込み発生時のunique Index

同時書き込み発生時のsingle-update

• 同様に nonShard なキーで同時に single- update を行う際にも問題が

• アトミックな操作が保証されないのでエラーとなる

• Non Shard Key に対しては必ず multi-update を行う

• 結果: single-update に対してエラー

「 tmp_collection が削除されないmapreduce() 」

• Shard の中から 1 つの「代表」が選ばれ、各Shard で mapreduce が実行された結果に対してもう一度 reduce を行う

• 計算はオプションを指定しない限り、 tmp_collection が作られる

• Sharding 環境では計算終了後に一時的に作成した tmp_collection が自動で削除されない

• 結果:不要な Collection が増えていく• v.1.8 で改善。手動で削除して対処

Sharding クエリは要注意

• このように Sharding 環境におけるクエリには十分な注意が必要

• 同時書き込みに対してアトミックでないことが影響

• Chunk Migration 中の Chunk は重複して数えられる可能性がある

Mongo Sharding を理解するための 4つのキーワード

• Shard Key:

– コレクションを分割する際のキー

• Balancing, Migration:

– Shard 間のデータの均等な分散を維持する仕組み

• mongos, config, mongod:

– Sharding を構成する 3 種類のサーバー

• Sharding クエリ :

– Sharding 環境におけるクエリの振舞と問題点

最終的に言いたいこと• Shard Key の設定は非常に重要、慎重に

– Shard の偏りを極力減らす事は重要

– Shard Key によって偏り具合が大きく異なる

• Sharding 環境におけるクエリは振る舞いが怪しい部分があるので要注意

– 正しい count() が行われない

– unique のはずのキーが重複して存在

ありがとうございました…

top related