CyberAgentにおける
MongoDB
株式会社サイバーエージェント
アメーバ事業本部 テクノロジーグループ Ameba Infra. Unit

                桑野 章弘

13年12月12日木曜日
アジェンダ
n Amebaのサービス
n サービス環境の変遷
n サービスを支えるMongoDB
n 困ったことなど
n 運用について
n まとめ

13年12月12日木曜日
自己紹介
n 桑野章弘
l サイバーエージェント
l Ameba を運営しています。
l ピグソーシャルゲームの運用/構築を担当

l Twitter
l @kuwa_tw

l Blog
l http://d.hatena.ne.jp/akuwano/

13年12月12日木曜日
ピグライフ

13年12月12日木曜日
ピグライフ
n サービス情報
l 2011/05/31オープン
l 自分の庭の育成ゲーム

13年12月12日木曜日
ピグアイランド

13年12月12日木曜日
ピグアイランド
n サービス情報
l 2012/05/22オープン
l 自分の島育成ゲーム

13年12月12日木曜日
ピグカフェ

13年12月12日木曜日
ピグカフェ
n サービス情報
l 2012/08/21オープン
l カフェ経営ゲーム

13年12月12日木曜日
ピグワールド

13年12月12日木曜日
ピグワールド
n サービス情報
l 2012/11/27オープン
l 自分の街をつくろうゲーム

13年12月12日木曜日
なぞってピグキッチン

13年12月12日木曜日
なぞってピグキッチン
n サービス情報
l 2013/11/19オープン
l スマートフォンのブラウザゲーム
l パズルをクリアして自分のキッチンを育てようゲーム

13年12月12日木曜日
ゲーム概要
n PC
l ユーザ数は100万ユーザ∼300万ユーザ以上
l ピーク帯同時接続数10万以上
l オンプレミス

n SPサービス
l リリースしたばかり
l AWS上で構築

13年12月12日木曜日
全ゲーム
MongoDBを使用

13年12月12日木曜日
サービス環境の変遷

13年12月12日木曜日
n まずは弊社サービスの成長の変遷について説明し
ます

13年12月12日木曜日
アーキテクチャ
n アプリケーションサーバ
l Node.js
l Nginx

n データストアサーバ
l MongoDB

13年12月12日木曜日
アーキテクチャ
BackEnd

FrontEnd

ユーザ/エリア等の状態
staticサーバ

Flashデータ

必要なデータの取得

→リクエスト/取得
HTTP
WebSocket接続

・ユーザ情報
・チャットデータ
→リクエスト/取得

ユーザ
(ブラウザ:Flash)

13年12月12日木曜日

データ

Node.jsサーバ
Socketサーバ

mongodbサーバ
[ピグライフ]の変遷

13年12月12日木曜日
ピグライフ
n リリースから現在
l βテスト時代
l リリース後
l 現在

13年12月12日木曜日
ピグライフ
n リリースから現在
l βテスト時代
l リリース後
l 現在

どんなフェーズを経たか

13年12月12日木曜日
ピグライフ:βテスト時代
n 4/26∼5/31
l テストユーザ数5000∼30000
l 毎日リリース、機能追加、インフラ構成変更
l サーバも最小限を用意

13年12月12日木曜日
ピグライフ:βテスト時代
βテスト時に実
装

6
mongos
Staticサーバ

Node.jsサーバ

MongoDB

13年12月12日木曜日

行動ログの保存
MongoDB Log
ピグライフ:リリース後
n 問題点洗い出しのフェーズ
l Node.jsのサーバや、mongodbも、パフォーマン
スが出ていなかったため増設
l Swfファイルをnode.jsのサーバから静的ファイル専
用のサーバへと切り出す

13年12月12日木曜日
ピグライフ:リリース後
n 5/31 ∼
l ピグライフ、正式リリース
l 人気が爆発、予想以上の伸び
l 開始3週間(6/22)で100万人突破
l とにかく増設の時期

13年12月12日木曜日
リリース時構成
大量追加

44

3
mongos
Staticサーバ

Node.jsサーバ

行動ログの保存
サーバにも取得
MongoDB Log

1シャード追加
(合計4シャー
ド)

MongoDB

13年12月12日木曜日
ピグライフ:リリース後
n パフォーマンス確保のフェーズ
l ボトルネック調査
l 状況を見つつサーバ台数、リソースの確保

13年12月12日木曜日
ピグライフ:現在
n 9/1 ∼
l 順調な成長
l 開始3ヶ月弱(8/22)で200万人突破

13年12月12日木曜日
現在時構成
リリース時切替
高スペックサー
バにリプレイス

5

5

10
mongos

Staticサーバ_A系 Staticサーバ_B系 Node.jsサーバ_A系

・・・・・

MongoDB

13年12月12日木曜日

10
Node.jsサーバ_B系
mongos
行動ログの保存
DB統合

23シャード追
加(合計27シャ
ード=81台)
ピグライフ:現在
n 運用改善のフェーズ
l メンテ時間短縮のため稼働グループを分割
l A系、B系での切替

l 構成はシンプルにしていく
l CDNなどの導入検討
(CDNを入れられるように仕様変更)

13年12月12日木曜日
ピグライフ:成長速度
n 成長速度
l リリースから3ヶ月程度で、サーバ規模としては8倍
に。それにともなって、トラフィック(1.3Gbps)、
総コネクション数(18万)も増加。
l その期間は3ヶ月余り。3週間の伸びは単位にすれば
30倍

サービスの予想以上の成長

13年12月12日木曜日
サービスを支える
MongoDB

13年12月12日木曜日
この成長速度を支えた
MongoDBの基本的
な機能
13年12月12日木曜日
MongoDBの構成
アプリケーションサー
バ

mongos

Mongod[ShardA]

Mongod[ShardB]

mongoc
Mongod[ShardC]

13年12月12日木曜日
アーキテクチャについて
n システムアーキテクチャ
l スキーマレス
l 冗長化
l ReplicaSets

l スケーラビリティ
l Sharding

13年12月12日木曜日
アーキテクチャの課題
n スキーマレスなデータ構造による柔軟なデータ管
理
l ユーザ情報なども柔軟に持つことができるので、機能
追加時等が比較的楽
l 次ページ例

13年12月12日木曜日
アーキテクチャの課題
n スキーマレスなデータ構造
l ユーザーコレクションに趣味を追加したい場合
{
"_id" : "1234567889",
"userid" : "akuwano",
"username" : "Akihiro Kuwano"
}

{
"_id" : "1234567889",
"userid" : "akuwano",
"hobby" : Movie ,
"username" : "Akihiro Kuwano"
}

13年12月12日木曜日
アーキテクチャの課題
n ReplicaSets
l 相互死活監視&投票により冗長性を保つ。最小単位は
3台。
プライマリ

セカンダリ

13年12月12日木曜日

セカンダリ
アーキテクチャの課題
n ReplicaSets
l 相互死活監視&投票により冗長性を保つ。最小単位は
3台。
生きているサー
バで投票が行わ
れ新しいプライ
マリが選ばれる

セカンダリ

13年12月12日木曜日

プライマリ

セカンダリ → プライマリ
アーキテクチャの課題
n Sharding
l データをChunkの細かい粒度に分割する。
各mongodに分散して渡すことで各サーバの負荷を
分散します

13年12月12日木曜日
MongoDBの構成
アプリケーションサー
バ

Sharding
データをChunk
の単位に分ける

ReplicaSetsに
よりサーバの冗長
性を確保

DATA
mongos
Mongod[ShardA]

Mongod[ShardB]
mongoc

Mongod[ShardC]

13年12月12日木曜日
MongoDBの構成
アプリケーションサー
バ

Sharding
データをChunk
の単位に分ける

ReplicaSetsに
よりサーバの冗長
性を確保

ChunkA ChunkB ChunkC

mongos
mongocはシャ
ーディング情報を
持つ

Mongod[ShardA]

Mongod[ShardB]
mongoc
ChunkA -> ShardA
ChunkB -> ShardB
ChunkC -> ShardC

13年12月12日木曜日

Mongod[ShardC]
MongoDBの構成
アプリケーションサー
バ

ReplicaSetsに
よりサーバの冗長
性を確保

Sharding
データをChunk
の単位に分ける

mongos
mongocはシャ
ーディング情報を
持つ

ChunkA

Mongod[ShardA]

ChunkB

Mongod[ShardB]

mongoc
ChunkA -> ShardA
ChunkB -> ShardB
ChunkC -> ShardC

13年12月12日木曜日

ChunkC

Mongod[ShardC]
アーキテクチャの課題
n MongoDBのこれらの基本機能により、アプリ
側の実装コストは軽くなります。
n 前述した、9台→100台への変更においても、ア
プリ側のDB接続部分の変更点は殆どありませ
ん。
n スケーラビリティを保ったまま、シンプルなサー
ビス構築を行うことができています。

13年12月12日木曜日
ユースケース

13年12月12日木曜日
ユースケース
n MongoDBにかぎらず、NoSQLはできる、で
きない、がハッキリしています
n NoSQL使うならできる部分を伸ばす必要があり
ます。もし、できない部分を突き詰めると
RDBMSとなります

13年12月12日木曜日
ユースケース:得意なもの
n データ量が大き過ぎない
n 書き込みが多過ぎない
n 単位時間あたりの処理データが各シャードのメモ
リ量を超えない処理は得意
n 得意なユースケース
l ゲーム系Webアプリケーション
l 一時的ログ解析基盤

13年12月12日木曜日
ユースケース:苦手なもの
n ホットデータが無い様なデータの使い方は苦手
l データ量が爆発的に増える
l 常に全データへのアクセスを行うような

n 苦手なユースケース
l ソーシャル系等のWebアプリケーション
l 継続的 or 統合的 ログ解析基盤

13年12月12日木曜日
なぜか?

13年12月12日木曜日
ユースケース
n MongoDBのメモリ管理
l アクセスしたデータファイルはmmapとしてキャッ
シュ
l メモリからあふれた場合はアクセスされた物を入れ
て、使われてないものを削除
l LRU的な仕組みはなく、OS任せ

13年12月12日木曜日
ユースケース
mongodb

mmap

datafile.0

13年12月12日木曜日

datafile.1

datafile.2
mmap
ユースケース
mongodb

mmap

datafile.0

13年12月12日木曜日

datafile.1

datafile.2
mmap

datafile.3
ユースケース

mongodb

メモリ量以上のデ
ータアクセス毎に
メモリ<ー>ディスク
へのアクセスが頻
発

mmap

datafile.0

13年12月12日木曜日

datafile.1
mmap

datafile.2
困ったことについて

13年12月12日木曜日
運用中に困ったことに
ついて

13年12月12日木曜日
n クラスターのスローダウン
l 必要なデータを一気にデータをインポートした場合
l oplogデータ量範囲を超えてレプリケーションが停止
l 一度に入れたため、PrimaryShardにChunkが溜
まってしまいI/Oバウンドに
l 負荷が高いのでBalancerは動かないためクラスタの
スローダウン
→Oplogの容量を増やすことができるのでそれらで対
応

13年12月12日木曜日
n シャード設定のスローダウン
l ほんとに突然パフォーマンスダウンする
「10分前は動いてたけど、、、」
l PrimaryShardはリソースを潤沢な状態にする
l 各シャードのmmapの容量が実メモリを超えてきた
ら注意する

→シャード設定は定期的に確認&シャードの設定を自
動化

13年12月12日木曜日
n データ肥大
l 運用していくに連れてデータの肥大化する
l 定期的なデータのコンパクションが必要です
l repairコマンドは、データ容量と同容量のスペース
を利用するので注意
l データ容量が小容量かつ、一時的にMongoDBを止
められる場合、データdrop→データresoreの方が
簡単です。
l RS組んでいるならローリングコンパクション

13年12月12日木曜日
日々の運用

13年12月12日木曜日
ここからは実際の運用
でやっていること

13年12月12日木曜日
n MongoDBに使用するハードウェア
l CPU
l (現在は)CPUはあまり負荷が来ないためそれほど良い物で
なくて良い
l そのかわりノードを増やすことになるのであればラックの効
率を上げるため消費電力の少ないものを選択する

13年12月12日木曜日
n MongoDBに使用するハードウェア
l メモリ
l 積めば積むほどキャッシュが効くのでできるだけ積む
l 現在は1ノード32GBのサーバを用意

13年12月12日木曜日
n MongoDBに使用するハードウェア
l DISK
l こちらも書き込み、読み込みが早いに越したことは無い
l 今までは、SAS * 4 RAID10 -> SSD * 2 RAID0
l 現在はSSDはSASの3倍のiops
l FileSystemはxfs or ext4
- 高速なfallocate()がサポートが必要

13年12月12日木曜日
n MongoDBに使用するハードウェア
l DISK
l ioDriveでの検証は、現状では8000opsを超えた位で
ReplicaSetsのoplogの転送が止まる事を確認していた
l が バージョン2.4ではこの現象はない=ioDrive 等を上手く
活用することでサーバ台数を減らすことができる

13年12月12日木曜日
n バックアップ
l mongodump
l mongos経由の実行
l ポイントイン・タイムバックアップ

l ReplicaSetsのDelay

13年12月12日木曜日
n バックアップ
l mongodump
l mongosに対してmongodump実行するのはバックアッ
プとしては一番簡単
- 稼働中ではポイントイン・タイムバックアップではない
l mongodumpはmongodが起動していなくてもデータフ
ァイルに直接かけてBSONファイルを取得できるので、これ
を利用してポイントイン・タイムのバックアップを実装して
います

13年12月12日木曜日
n バックアップ
l 稼働中にスナップショットバックアップを取得
l RSメンバとしてarbiterとnovoteのプロセスを起動
l 1,mongos経由でAutoBalancingをOff
l 2,各レプリカセットのnovoteプロセスをダウン
l 3,各mongodからmongodumpでデータ取得
l 4 , mongos経由でAutoBalancingをOn
l 5 ,各Dumpデータの収集
l

13年12月12日木曜日
バックアップの構成
アプリケーションサーバ

1、Chunkがバ
ックアップ中に移
動させない

バックアップサーバ

5,各シャードか
らデータを取得

3,各シャードで
Dumpデータを
生成

mongos
Arbiter
Mongod[ShardA]

✕

no vote

Dump

Arbiter
Mongod[ShardB]
no vote

mongoc

Arbiter
Mongod[ShardC]
no vote

13年12月12日木曜日

2,no vote
プロセスダウン
n バックアップ
l ReplicasetsのDelay
l バックアップと言うよりはオペミスの防止
l 常に最新の状態よりも一定期間古い状態となる、
Replicasetsを追加します

13年12月12日木曜日
MMS
n MongoDB Management Service(MMS)
l 監視
l Muninプラグインとして提供

l バックアップ
l シャード環境でのポイントイン・タイムバックアップを提供
-

13年12月12日木曜日
MMS
n MongoDB Management Service(MMS)
l 監視
l Muninプラグインとして提供

l バックアップ
l シャード環境でのポイントイン・タイムバックアップを提供
-

13年12月12日木曜日
RS Delayの構成
アプリケーションサー
バ

この Replica
Sets のみ、他の
RSよりも3時間
前のデータを持つ

mongos
Mongod[ShardA]

Mongod[ShardB]
mongoc

Mongod[ShardC]

13年12月12日木曜日
n Index
l indexが効いているかはexplain()で確認
l できるだけPK=_id で検索する実装にする
replSetTest1001:PRIMARY> db.User.find({'Field01': 'test'}).explain()
{
"cursor" : "BtreeCursor testIndex_1",
"nscanned" : 1,
"nscannedObjects" : 1,
"n" : 1,
"millis" : 7,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,

13年12月12日木曜日
n Index
l 詳しいオプティマイザの実行結果が欲しい場合
は .explain(true)
replSetTest1001:PRIMARY> db.User.find({'_id': 'test'}).explain(true)
"allPlans" : [
{
"cursor" : "BtreeCursor _id_",
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"indexBounds" : {
"start" : {
"_id" : "test"
},

13年12月12日木曜日
n ロック
l 同じサーバ上に異常に書き込みの多いコレクションが
あるとクラスタ全体のアクセスに影響するため、コレ
クションを分ける
l アプリ実装はコレクション間をできるだけ疎結合に
l 2.2以降DBレベルロックなのでDB分割

13年12月12日木曜日
n ロック

Collection A

13年12月12日木曜日

Collection B

Collection C
n ロック

Collection A

13年12月12日木曜日

Collection C

Collection B
n 運用効率化
l どうしても台数が多くなる傾向にあります。
l そのため「標準のコマンドだと表示が多すぎて見づら
い」「今のマスターの一覧が簡単に出したい」等の不
満がでます。
l これらはスクリプト作成等で対応しています、このあ
たりもJSONで各種データを取ってこれるために管理
ツールなどは作りやすいです。

13年12月12日木曜日
n 運用効率化 :運用スクリプトの内容
l ロックタイムの取得
l シャードに入っているmongod一覧のリスト出力
l レプリカセットのマスター検索
l レプリカセットのpriority検索
l printShardingStatusの整形
l レプリカセット一括作成/設定変更(現在のRSに
Delayホスト追加するなど)

13年12月12日木曜日
n 各種コマンド、ステータスなど
l トレンドが見たい
l 現状が把握したい

13年12月12日木曜日
n 各種コマンド、ステータスなど
l mongostat
l mongotop
l mongosniff

13年12月12日木曜日
n mongostat
l クエリや、プロセスの現状を確認するコマンド

$ ./mongostat --host 192.168.8.41:27018,192.168.8.62:27018
insert query update delete getmore command flushes mapped
vsize res faults locked % idx miss %
qr¦qw ar¦aw netIn netOut conn
set repl
time
192.168.8.41:27018
0 361 132
0
209
437
0 36.1g 76.2g
14.3g
1
2.2
0
0¦0
2¦0 85k 698k 3056 RSTest1001 M
11:16:57
192.168.8.62:27018
0 384 164
0
245
480
0 30.1g 63.9g
15.6g
0
2
0
0¦0
2¦0 96k 652k 2587 RSTest1002 M
11:16:57

13年12月12日木曜日
n mongostat - 見るべき項目
l faults - 1秒当りのページフォールト数
l Locked % - グローバルライトロックの時間割合
l idx miss % - indexのヒット率の時間割合
l qr¦qw - 読み込みキュー¦書き込みキュー の大きさ

13年12月12日木曜日
n mongostat - 見るべき項目
l faults が多い場合
キャッシュメモリ溢れの可能性があるので、メモリ、
もしくはサーバを増設
l Locked % が高い場合
書き込みのクエリを見直す or クラスタ分割。
l qr¦qw が高い場合
サーバ負荷が低ければ、ロックの可能性を疑う。負荷
が高ければ単純なクエリ増による高負荷を疑う。

13年12月12日木曜日
n mongotop
l 現在重いmongodのどのcollectionへアクセスがか
かっているかを確認したりとかできまする。
l 障害の時がメイン
$ /usr/local/mongodb2_1/bin/mongotop --host
mongos_ip --port 27018
connected to: mongos_ip
ns total
read
write
2012-05-23T02:14:12
local.oplog.rs 1929ms 1929ms 0ms
life_prd_main.TestOnline 0ms 500ms
10ms
life_prd_main.Test2Soil 8ms
0ms
8ms

13年12月12日木曜日

writeに時間
がかかってい
n mongosniff
l 最後はパケットキャプチャですので、何か会った際の
アクセス状況の確認が可能
l mongosのアクセス状況とか、複雑なクエリを見た
い場合はこれで見るのが良い
# mongosniff --source NET eth0 27017
# 以下にパケットがズラズラっと並ぶ
127.0.0.1:55858 -->> 127.0.0.1:27017 testdatabase.TestCol1 89 bytes
id:kjkjkjkj
14086840
query: { _id: "1234567891234567" } ntoreturn: -1 ntoskip: 0
127.0.0.1:27017 <<-- 127.0.0.1:55858 205 bytes id:77383268
2000171624 - 14086840

13年12月12日木曜日
n ステータス確認・変更
l profiling
l loglevel変更
l Working Set Analyzer
l db.adminCommand("connPoolStats")
l db.serverStatus()
l db.currentOp()
l db.collection.stat()
l db.stats()

13年12月12日木曜日
まとめ

13年12月12日木曜日
まとめ
n MongoDBを上手く使用することで、以下の様
なことが実現できています
l 運用の安定
l 構成を変えずスケーラビリティを確保
l JSONを直接扱える事で開発スピードを早く

13年12月12日木曜日
まとめ
n ですが、運用するにあたって気をつけなければな
らない点などがあり、上手い運用にはある程度の
ノウハウが必要とも考えています
n その辺りは私達もこのような場で適宜露出してい
ますし、サポートしていただける所も今後増えて
いくのではないでしょうか。

13年12月12日木曜日
まとめ

n ですがNoSQLは適材適所、という言葉もあり、
徐々に使って慣れていくのが大事だと思います。
スモールスタートでまずは使ってみてはどうでし
ょうか。

13年12月12日木曜日
ご清聴ありがとう
ございました

13年12月12日木曜日
質疑応答
13年12月12日木曜日

CyberAgentにおけるMongoDB