Weitere ähnliche Inhalte Ähnlich wie ソーシャルゲームにおけるAWS/MongoDB利用事例 (20) Mehr von Masakazu Matsushita (20) Kürzlich hochgeladen (11) ソーシャルゲームにおけるAWS/MongoDB利用事例2. About Me
• 松下 雅和 / Masakazu Matsushita
• @matsukaz
• Cyberagent, Inc. - SocialApps Division
- Ameba Pico (2011/01∼)
• 海外向けピグ
- Animal Land (2011/03∼)
• DevLOVE Staff
5. Document-oriented
• スキーマレス
• BSON形式(Binary JSON)
> db.users.save( { name : "Alex", age : 20 } );
> db.users.save( { name : "Beth" } );
> db.users.find();
{ _id : ObjectId("..."), name : "Alex", age : 20 }
{ _id : ObjectId("..."), name : "Beth" }
> db.items.save( { id : "item01", name : "hoge", price : 1 } );
> db.items.find();
{ _id : ObjectId("..."), id : "item01", name : "hoge", price : 1 }
13. Auto-Sharding
• 指定したShard Keyで水平分割
Shard 1 Shard 2
users (shardkey=name) users (shardkey=name)
Alex Beth Chris Maria Nancy Phil
Daniel Fred George
Maria Nancy Phil
items (shardkey=id) ・データ量の偏りを元に自動で
item01 item02 item03 マイグレーション
・マイグレーションはchunkと呼
ばれるShard Keyの特定範囲
(ここではMaria∼Phil)
14. Auto-Sharding
• 指定したShard Keyで水平分割
Shard 1 Shard 2
users (shardkey=name) users (shardkey=name)
Alex Beth Chris Maria Nancy Phil
Daniel Fred George
mongosを介すことで、
クライアントはShard構
items (shardkey=id)
成を意識する必要なし
item01 item02 item03
Shard情報を保持
client mongoc
mongos mongoc
mongoc
client Shard情報
15. Querying
• field selection
> db.items.find({id : "item01"}, {"name" : 1});
• sort
> db.items.find({}).sort({"name" : 1});
• skip, limit
> db.items.find({}).skip(20).limit(10);
• cursor
> var cur = db.items.find({});
> cur.forEach(function(data){ print(data.name) });
20. 利用サービス
• Amazon Web Services
- EC2 (Amazon Linux, Instance Store)
- EBS
m1.large m2.2xlarge
Memory 7.5 GB 34.2 GB
ECU 4 13
Storage 850 GB 850 GB
I/O 高速 高速
21. 利用サービス
• Amazon Web Services
- S3
- CloudFront
- Route53
- Elastic Load Balancing
• Google Apps
• Kontagent
22. システム間のつながり
iframe 各種API呼び出し
課金
コールバック
Web
HTML
サーバ
JSON
Command
Flash
サーバ
AMF
AMF : Actionscript Message Format
24. L m1.large
サーバ構成 XX
EBS
m2.2xlarge
EBS
ELB ELB
S3
Web L 3 Command L 4 CloudFront
nginx nginx Route 53
Tomcat Tomcat
バッチ L
mongos mongos
バッチ
MySQL
Shard 5 MySQL L memcached L 2
monitor L
MongoDB XX MySQL memcached
EBS munin
mongod
MySQL L nagios
MongoDB XX MySQL
EBS admin L ビルド L
mongod
nginx redmine
MongoDB XX MongoDB XX 3 Tomcat jenkins
mongod mongoc
EBS EBS mongos Maven SVN
EBS
Secondary
28. EC2
• 環境ごとに適切なリージョンを選択
- 開発環境は効率を重視して東京
- 本番環境はCalifornia(Virginiaは障害が
多いと判断)
• 1年以上使うインスタンスはReservedに
するとかなりお得
29. EC2
• AMIを作成しておくとサーバ追加が楽
- image作成
ec2-bundle-vol -d [image出力先] --privatekey [EC2インスタン
ス作成時に利用した秘密鍵] --cert [アクセス証明書] --user
[AWSの口座番号]
- S3へアップロード
ec2-upload-bundle --bucket [S3のバケット] --manifest [作成
したimageのマニフェストファイル] --access-key [アクセスキー]
--secret-key [シークレットキー]
- 管理画面でimageを登録
31. EC2
• 注意点
- 別インスタンスで利用されていたIPアド
レスが再利用される
• 外部公開のサーバは、各種ログで異常
を確認しておいた方が良い
32. EC2
• 注意点
- 同じスペックでもI/O性能に差がある
• ストレージで利用するサーバは、ツー
ルなどで検証しておいた方が良い
連続書き込み 連続読み込み
対象 Char単位 Block単位 Rewrite Char単位 Block単位
K/sec CPU K/sec CPU K/sec CPU K/sec CPU K/sec CPU
m2.2xlarge 55484 68 71216 12 61546 7 86701 99 3034488 99
m2.2xlarge 81659 99 245211 47 133788 17 87943 99 3154005 99
ebsマウント 81476 98 186995 34 129284 16 83300 99 3090866 99
bonnie++の分析結果の一部
33. EC2
• 注意点
- サーバ再起動がスケジューリングされる
ことがある
• 大抵は1W∼2W程度の猶予があり、期
間内に自分で再起動すれば良い
- 稀にサーバ停止もスケジューリングされ
る・・・
• 代替サーバを立てて移行が必要
34. Elastic Load Balancing
• 同じEC2インスタンスは複数のELBにはつ
なげられない
• EC2インスタンスを全て切り離すと、次回
つなげた際にELBの起動時間がかかる
- メンテ時はSorryサーバをつなぐ運用
運用中 メンテ中
ELB ELB
Web Web Sorry Web Web Sorry
35. S3 + CloudFront
• CloudFrontのキャッシュクリアは難しい
• キャッシュクリアをしない運用
- S3のパスにバージョン番号を入れる
・[S3バケット]/swf/1.0.3/main.swf
・[S3バケット]/image/1.0.8/icon/xxx.png
- バージョン毎に全ファイルをUploadす
るため、並列Uploadで効率化
https://github.com/pcorliss/s3cmd-modification
39. アプリケーション開発時
• トランザクションがいらないデータ構造
- ユーザ情報などは、1ドキュメントで保
持して一括更新
ユーザ情報
{ "facebookId" : xxx,
イメージ
"status" : { "lv" : 10, "coin" : 9999, ... },
"layerInfo" : "1¦1¦0¦1¦2¦1¦1¦3¦1¦1¦4¦0...",
"structure" : {
"1¦1" : { "id" : xxx, "depth" : 3, "width" : 3, ... }, ...
},
"inventory" : [ { "id" : xxx, "size" : xxx, ... }, ... ],
"animal" : [ { "id" : xxx, "color" : 0, "pos" : "20¦20", ... } ],
...
}
40. アプリケーション開発時
• データ量を可能な限り削減
- 街のグリッド情報を1つのデータで保持
するなど (プログラム側で展開)
- 設計時の構造(500 KB)
"layerInfo" : {
"1¦1" : 0,
"1¦2" : 1,
....
}
- 現在の構造(50 KB)
"layerInfo" : "1¦1¦0¦1¦2¦1¦1¦3¦1¦1¦4¦0..."
42. アプリケーション開発時
• Shard Keyは以下の方針で決定
- カーディナリティが低い値は使わない
- よく使われるデータがメモリ上に乗る
- 使われないデータはメモリ上に乗らない
- 参照や更新が多いデータはバランスよく
各Shardに分散
- Targetedオペレーション
での利用を意識 (後述)
おすすめ書籍 →
43. アプリケーション開発時
• Globalは極力避けて、Targeted中心に
- Shard Keyでデータを操作
- Shard Key以外の操作はIndexを利用
Operation Type
db.foo.find({ShardKey : 1}) Targeted
db.foo.find({ShardKey : 1, NonShardKey : 1}) Targeted
db.foo.find({NonShardKey : 1}) Global
db.foo.find() Global
db.foo.insert(<object>) Targeted
db.foo.update({ShardKey : 1}, <object>) Targeted
db.foo.remove({ShardKey : 1})
db.foo.update({NonShardKey : 1}, <object>) Global
db.foo.remove({NonShardKey : 1})
44. アプリケーション開発時
• 更新頻度をなるべく減らす
- マスタ情報はサーバ上でキャッシュ
- ユーザ操作はまとめて処理 (5秒に1度)
• Flash側でキューの仕組みを用意
• サーバ側はキューから取り出してシーケ
ンシャルに処理
キューで保持 シーケンシャル処理
ユーザ操作
キュー
Command
Flash
サーバ
まとめて送信
45. アプリケーション開発時
• O/D(?)マッパーで開発を効率化
- Spring Data - MongoDBとラッパーク
ラスを用意して効率よく開発
@Autowired
protected MongoTemplate mongoTemplate;
public void insert(T entity) {
mongoTemplate.save(entity);
}
- オブジェクトをそのまま利用できるの
で、RDBのO/Rマッパーより扱いやすい
- Javaでも言うほど大変じゃない
47. インフラ構築時
• 従来のDBと同様に見積もり
- データ量/1ユーザ (50 KB)
- 想定ユーザ数 (DAU 70万)
- データの更新頻度
- 各サーバの最大同時接続数
- 各サーバの台数、スペック、コスト
- 想定ユーザ数を超えた場合のスケールの
ポイント整理
48. インフラ構築時
• 性能検証
- 帯域幅を確認 (350Mbps程度)
- MongoDBを検証 (MongoDB 2.0.1、
ReplicaSetのShardを2つ、ジャーナリ
ング有効)
• 参照/更新の処理性能
• マイグレーション時の性能比較
• Javaドライバー経由の性能比較
- アプリケーションを通した性能を確認
49. インフラ構築時
• 障害を想定した動作検証
- mongodが落ちた場合
• PRIMARYへ昇格するか
• 起動したらデータが同期されるか
• SECONDARYが落ちても問題ないか
- mongocが落ちた場合
• 全体の動作に影響がないか
- バックアップから戻せるか
→ 全て問題ナシ
51. インフラ構築時
• ジャーナリングを有効化
- 障害時のデータロストの危険性を軽減
- パフォーマンスは低下するので注意
• oplogsizeを10GBに設定
- デフォルトは全体の5%で大きいため
- 障害発生から復旧作業にとりかかるまで
の予定時間から算出
52. インフラ構築時
• 必要なIndexはあらかじめ作成しておく
- 通常のIndex作成中は、全てのオペレー
ションがブロックされてしまうため
- 20万件のデータ (それぞれ50KB程度)
にIndexを貼ると、2分程度かかる
- あとから追加する場合は、メンテ中に作
成するか、バックグラウンドで作成
53. インフラ構築時
• コネクションプールをチューニング
※ mongosに対するコネクションプール
項目 意味 値
connectionsPerHost コネクション数 100
threadsAllowedToBlockFor 1コネクション辺りの
4
ConnectionMultiplier 接続待ち数
- nginxのworker数、TomcatのThread数
とのバランスを考慮して設定
- プールが足りなくなったときのエラー
(Out of Semaphores) に注意
上記例では、100 + (100 * 4) = 500
56. MongoDBがダウン
• mongoc x 1 & mongod x 1
(SECONDARY) が落ちた
• 原因はEC2インスタンスの仮想サーバホス
トの障害
• プロセスを起動するだけで復旧
• サービスへの影響なし
58. 数値の型変換エラー
• アプリから数値を入れると32-bit integer
だが、コンソールから数値を入れると
doubleとして扱われ、型変換に失敗
- 入れる場合はNumberIntを利用
※ まだドキュメントには書いてない
> db.foo.save( { val : 1 } );
> db.foo.save( { val : NumberInt(2) } ); 1 : double
16 : int
> db.foo.find( { val : { $type : 16 } } );
{ _id : ObjectId("..."), val : 2 }