LoginSignup
42
39

More than 5 years have passed since last update.

mongoDBでシャーディング+レプリカセットしてみる

Posted at

mongoDBのシャーディング+レプリカセット

前提

  • AWS EC2 AmazonLinux
  • mongoDB 2.6

以前、mongoDBのレプリカセットを試したので今度はシャーディングを試してみました。これでデータ量やクエリが増えたとしてもスケールアウトすることで負荷分散が可能になります。

構成図

mongodb_sharding.png

mongoDBのシャーディングには、mongosのRouterと呼ばれるサーバと、config serverという設定サーバが存在しています。

mongos Router

シャードとクライアントを連携させるルーティングプロセスです。このサーバ自体はデータや状態は持たないただのインターフェイスになっています。Railsなどのアプリケーションは、このmongosに接続をしていくことになります。mongodではなく、mongosという点に注意してください。

configサーバ

シャーディングのメタ情報を保持している設定サーバです。1台もしくは3台で稼働させられますが、本番環境化においては3台のconfigサーバが望ましいです。負荷はさほどないので、スペックが低くても大丈夫です。もしくは、他のサーバと同居させるような形でもいいです。ただし、configサーバ同士が同居するのはNGです。

シャード

データを分散して持つDB群です。今回は、Primary + Secondary + Arbiterの3台構成を1つのシャードとして作ることにしています。

シャーディングの設定

シャード1(repl_1)

Primary + Secondary + Arbiter全て同じ設定です。

/etc/mongod.conf
logpath=/var/log/mongodb/mongod.log
logappend=true
fork=true
dbpath=/var/lib/mongo
pidfilepath=/var/run/mongodb/mongod.pid
#bind_ip=127.0.0.1 ←コメントアウト
port=27017

shardsvr=true
replSet=repl_1

レプリカセットの設定を行います。

> config = {_id: 'repl_1',
    members: [
      {_id: 0, host: '172.31.100.10:27017'},
      {_id: 1, host: '172.31.100.11:27017'},
      {_id: 2, host: '172.31.100.12:27017', arbiterOnly: true},
    ]
  }

> rs.initiate(config)

シャード2(repl_2)

Primary + Secondary + Arbiter全て同じ設定です。

/etc/mongod.conf
logpath=/var/log/mongodb/mongod.log
logappend=true
fork=true
dbpath=/var/lib/mongo
pidfilepath=/var/run/mongodb/mongod.pid
#bind_ip=127.0.0.1 ←コメントアウト
port=27017

shardsvr=true
replSet=repl_2

レプリカセットの設定を行います。

> config = {_id: 'repl_2',
    members: [
      {_id: 0, host: '172.31.100.20:27017'},
      {_id: 1, host: '172.31.100.21:27017'},
      {_id: 2, host: '172.31.100.22:27017', arbiterOnly: true},
    ]
  }

> rs.initiate(config)

configサーバ

/etc/mongod.conf
logpath=/var/log/mongodb/mongod.log
logappend=true
fork=true
dbpath=/var/lib/mongo
pidfilepath=/var/run/mongodb/mongod.pid
#bind_ip=127.0.0.1 ←コメントアウト
port=27017

configsvr=true

mongos

configサーバのホストとポートを指定します。この時、IPアドレスよりもホスト名などのほうがサーバ障害が起きた時など、楽なのでそうしましょう。

また、mongod.confではなくmongos.confとして設定ファイルを作ります。

/etc/mongos.conf
logpath=/var/log/mongodb/mongod.log
logappend=true
fork=true
pidfilepath=/var/run/mongodb/mongod.pid
#bind_ip=127.0.0.1 ←コメントアウト
port=27017
configdb=mongo-config.example.com:27017

# configサーバが複数台の場合はカンマ区切り
# configdb=mongo-config1.example.com:27017,mongo-config2.example.com:27017,mongo-config3.example.com:27017

mongosを起動します。

$ sudo mongos -f /etc/mongos.conf

シャーディング設定

> db.adminCommand({addshard: "repl_1/172.31.10.155:27017,172.31.100.11:27017", name: "repl_1", allowLocal: true})
> db.adminCommand({addshard: "repl_2/172.31.20.155:27017,172.31.100.21:27017", name: "repl_2", allowLocal: true})

確認します。

> sh.status()

これでシャーディングの設定は完了です。

シャーディング対象を決める

sampleデータベースのhogesコレクションをシャーディング対象にしてみます。

> use admin
> sh.enableSharding("sample")
> sh.shardCollection("sample.hoges" , { uid : 1 })

> use sample
> db.logs.ensureIndex( { uid : 1 } );

実際にデータを投入してみます。

> use sample

> for(var i=1; i<=10000; i++) db.hoges.insert({"uid":i, "value":Math.floor(Math.random()*100000+1)})

実際に分散しているかを確認します。

> db.hoges.count()
10000
> db.hoges.count()
4800
> db.hoges.count()
5200

ちゃんと各シャードに分散してデータが登録されていることが確認できました。

シャードキーの選定

データを分割させるルール、シャードキーをどのように設定するかが重要であり難しい所ですね。

サンプルでは単純なuidをシャードキーとして指定していましたが、これはあまり効率的ではない指定方法のようです。なぜなら、単純に増加していくだけの値をシャードキーとして指定すると、1つのシャードに負荷が集中してしまうから。

単純に増加するだけの値がダメなら、単純にランダムな値をシャードキーとして指定すればいいのかというと、必ずしもそうでもないみたいです。書き込み(挿入)が分散されるという点では効率的なのですが、参照時に全てのシャードにアクセスをしなくてはならなくなる事があります。例えば、ユーザが投稿した最新の10件を取得するときなどです。参照時には、なるべく同じシャードにデータが固まっている方が効率的です。

じゃあ、どうすればいいの?って感じですね。データやアプリケーションの仕様にもよるんですが、基本的には複合キーで対応するとよくなるかもしれないです。例えばユーザIDと投稿IDという複合とか。

まとめ

mongoDBのシャーディング構築自体は超楽ちんですね。でも、実際に大量データとトラフィックを安定的にさばくには、それなりの運用ノウハウが必要だと感じました。ここらへんは地道に貯めていくしかないか…。

mongoDBインフラの面倒を見るコストが厳しい場合、モノは結構違うけど、DynamoDBとかを検討するのもいいかなと思います。グローバルセカンダリインデックスが変更できるようになったり、AWS Lambdaと連携したりと便利になってきているので。

42
39
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
42
39