月間10億pvを支えるmongo db

14,333 views
13,786 views

Published on

月間10億pvを支えるmongo db

  1. 1. 月間10億PVを 支えるMongoDB speaker: Yuji Isobe
  2. 2. name: Yuji Isobe attributes: [ engineer consultant security specialist startup member of ]
  3. 3. -> 2年間で月間10億PVを支える  まで成長した の 「泥臭い」負荷対策をお話します -> あるある紹介 -> 今はまだ問題点を洗い出している段階  ベストプラクティスがあれば教えて欲しい goals:
  4. 4. 大量データ
  5. 5. 大量データトラフィック急増
  6. 6. -> 合計月間PV10億 -> 秒間平均400PV -> 平均同時接続数5万 -> 月間保存データ量10TB db. .stats()
  7. 7. back_ends: [ Node.js CoffeeScript MongoDB Redis AWS ] front_ends: [ Nginx Ruby on Rails MySQL memcached AWS ] architecture:
  8. 8. back_ends: [ Node.js CoffeeScript MongoDB Redis AWS ] front_ends: [ Nginx Ruby on Rails MySQL memcached AWS ] architecture:
  9. 9. we.use( ).explain() -> スキーマレス -> 安定した書き込み -> 柔軟なクエリ -> 容易なスケールアウト -> との相性の良さ
  10. 10. 月間10億PVへの道のり -> ∼3000万PV -> 3000万∼1億PV -> 1億∼3億PV -> 3億∼10億PV -> 継続的な監視
  11. 11. ∼3000万PV い い か ら イ ン デ ッ ク ス だ !!!
  12. 12. -> メモリ上に乗れば高速 -> 1クエリにつき1インデックス -> B-Treeのバランスが重要 インデックスを理解する
  13. 13. -> メモリ上に乗れば高速 -> 1クエリにつき1インデックス -> B-Treeのバランスが重要 インデックスを理解する From 2.6.0
  14. 14. メモリ上に乗れば高速
  15. 15. user = new mongoose.Schema first: {type: String, required: true, index: true} last: {type: String, required: true, index: true} city: {type: String, required: true, index: true} ... created_at: {type: Date, default: Date.now, index: true} 書き込みが犠牲になっても読み込みが早ければいいじゃん! Before
  16. 16. user = new mongoose.Schema first: {type: String, required: true} last: {type: String, required: true} city: {type: String, required: true} ... created_at: {type: Date, default: Date.now, index: true} 書き込みが犠牲になっても読み込みが早ければいいじゃん! After
  17. 17. メモリ上に乗らなければ遅くなる
  18. 18. プログラムからフィールドを削除 したが、インデックスを消し忘れ、 無駄なインデックスが残る… スキーマレスあるある
  19. 19. 1クエリにつき1インデックス From 2.6.0
  20. 20. db.users.ensureIndex({first:1}); db.users.ensureIndex({last:1}); db.users.ensureIndex({ first:1, last:1 }); index intersection compound index vs. -> 複数の検索条件を  組み合わせたインデックス -> 2つのインデックスを使った  検索結果の共通部分を返す {first: Yuji , last: Isobe , city: Osaka } From 2.6.0
  21. 21. db.users.ensureIndex({first:1}); db.users.ensureIndex({last:1}); db.users.ensureIndex({ first:1, last:1 }); index intersection compound index vs. -> 複数の検索条件を  組み合わせたインデックス -> 2つのインデックスを使った  検索結果の共通部分を返す {first: Yuji , last: Isobe , city: Osaka } From 2.6.0 このクエリを早くしたい
  22. 22. db.users.ensureIndex({first:1}); db.users.ensureIndex({last:1}); db.users.ensureIndex({ first:1, last:1 }); index intersection compound index vs. メリット -> 同時にいくつでも デメリット -> 用途は限定的 メリット -> 柔軟な用途 デメリット -> 現在は同時に2つまで 2.6.0以降は 消してしまっても いいかも知れません From 2.6.0
  23. 23. B-Treeのバランスが重要
  24. 24. -> インデックスにB-Treeを採用 -> B-Treeは常に平衡を保っている インデックスの構造
  25. 25. 文字列のインデックス -> Hotデータが分散 -> メモリ効率が悪い
  26. 26. ObjectId・時間のインデックス -> Hotデータが集中 -> メモリ効率が良い
  27. 27. できるだけObjectIdを使いましょう 後からの変更は大変です(経験談) 教訓
  28. 28. Schema Design at Scale http://www.mongodb.com/presentations/schema-design-scale-1
  29. 29. 3000万∼1億PV 書 込 み は 一 度 だ け
  30. 30. -> にバッファする -> Bulk Inserts/Operationsを使う 書き込みの回数を減らす
  31. 31. -> にバッファする -> Bulk Inserts/Operationsを使う 書き込みの回数を減らす From 2.6.0
  32. 32. にバッファする
  33. 33. -> オンメモリ型のKVS -> データ型が豊富  -> リスト・セット・ハッシュ -> の苦手分野を補う
  34. 34. -> は肥大化するデータの  Updateは遅い -> はオンメモリ型のため  リストの操作が早い の苦手分野
  35. 35. without db.col.update({_id: 1}, {$push: {data: {x: 151, y: 100, ...}}); db.col.update({_id: 1}, {$push: {data: {x: 151, y: 179, ...}}); db.col.update({_id: 1}, {$push: {data: {x: 151, y: 266, ...}}); db.col.update({_id: 1}, {$push: {data: {x: 151, y: 295, ...}}); db.col.update({_id: 1}, {$push: {data: {x: 151, y: 322, ...}}); db.col.update({_id: 1}, {$push: {data: {x: 151, y: 333, ...}}); db.col.update({_id: 1}, {$push: {data: {x: 151, y: 340, ...}}); ...
  36. 36. db.col.insert({data: [ {x: 151, y: 100, ...}, {x: 151, y: 179, ...}, {x: 151, y: 266, ...}, {x: 151, y: 295, ...}, {x: 151, y: 322, ...}, {x: 151, y: 333, ...}, {x: 151, y: 340, ...}, ... ]}); with
  37. 37. Bulk Inserts/Operationsを使う From 2.6.0
  38. 38. db.col.insert([ {first: Yuji , last: Isobe , city: Osaka }, {first: Yuji , last: Isobe , city: Tokyo } ]); 使い方 var bulk = db.col.intializeOrderedBulkOp() bulk.find({first: Yuji }) .updateOne({$set: {city: Tokyo }}); Bulk Inserts Bulk Operations From 2.6.0
  39. 39. MongoDBは開発スピードが早く、 パフォーマンス向上機能が次々と 出るので、積極的に使いましょう 豆知識
  40. 40. 1億∼3億PV mongod mongod mongod mongod mongod mongod mongod mongod mongod mongod
  41. 41. -> 用途ごとにDBを分ける -> Hotデータ/Coldデータを分ける -> 古くなったデータを削除する DB設計
  42. 42. -> Reader-Writerロックが使われている -> 2.2.0以降はDB単位でロックする -> マシンを分ければメモリが増える なぜDBを分けるのか?
  43. 43. -> メインデータ(Hot) -> メインデータ(Cold) -> 生データ -> 統計データ -> サイトデータ におけるDBの用途
  44. 44. -> Hotデータのロックを避ける -> Hotデータ用に大容量メモリ -> Coldデータ用に大容量ストレージ Hotデータ/Coldデータを分ける
  45. 45. -> S3にバックアップ -> 統計データを保存 -> 定期的な自動削除 古いデータを削除する
  46. 46. クエリの条件をタイプミスして インデックスを使うことができず MongoDB死亡… スキーマレスあるある
  47. 47. 3億∼10億PV メ モ リ が 欲 し い で す
  48. 48. -> メモリは積めば積む程早くなる -> ディスクアクセスも早い方が良い  -> SSDを使いましょう チューニング
  49. 49. EC2インスタンスの選び方 http://blog.mongodirector.com/mongodb-on-aws-how-to-choose-the-right-ec2-instance-type-for-your-mongodb-server/
  50. 50. 一般的な目的(m3) -> 最初に選ぶインスタンス メモリの最適化(r3) -> メモリとCPUのバランスが良い ストレージの最適化(i2/hs) -> SSDを使用。高負荷に耐えられる EC2インスタンスの選び方
  51. 51. r3.2xlarge -> vCPU: 8 -> Memory: 61GiB -> SSD: 160GB -> Cost: $0.840 per Hour i2.2xlarge -> vCPU: 8 -> Memory: 61GiB -> SSD: 800GB x 2 -> Cost: $2.001 per Hour 主に使用しているインスタンス
  52. 52. 継続的な監視 監 視 を 止 め た ら そ こ で 異 常 終 了 で す よ ?
  53. 53. -> ホスティングサービスの  ダッシュボード -> 毎日の健康チェック用 -> 過去の情報は参照できない -> メリット・デメリットは下記参照 ホスティングサービスで始めるMongoDB http://www.slideshare.net/yujiosaka/starting-mongo-db-on-hosting-services
  54. 54. -> 定期的な健康診断用 -> リアルタイム監視はMongoHQ  過去の状態チェックはMMS -> アラートとバックアップもあり -> 導入が簡単なので、  とりあえず入れておくべき
  55. 55. -> explain(true) -> system.profile.find() -> MongoDB professor -> Dex -> MongoHQ Slow Queries 遅いクエリの監視
  56. 56. ObjectIdを使ったクエリの実行に 100ms以上かかったら危険信号です 豆知識
  57. 57. -> インデックスの仕組みを理解する -> 書き込みの回数を減らす -> DBを用途別に分ける -> メモリを増やす -> 継続的に監視する my.presenation.aggregate()
  58. 58. my.presentation .end thank you ;)
  59. 59. any?.questions?

×