DB tech showcase: 噂のMongoDBその用途は?

14,860 views

Published on

Published in: Technology
0 Comments
62 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
14,860
On SlideShare
0
From Embeds
0
Number of Embeds
281
Actions
Shares
0
Downloads
105
Comments
0
Likes
62
Embeds 0
No embeds

No notes for slide

DB tech showcase: 噂のMongoDBその用途は?

  1. 1. 噂のMongoDB その用途は?
  2. 2. About me
  3. 3. { 名前: 会社: 肩書: 趣味: 悩み: 窪田博昭 Cookpad.Inc   MongoDBJP代表 Golf,フットサル 30代は体が・・・ twitter:@crumbjp github: github.com/crumbjp }
  4. 4. We're hiring !!
  5. 5. -5 -
  6. 6. -6 -
  7. 7. -7 -
  8. 8. -8 -
  9. 9. -9 -
  10. 10. -10 -
  11. 11. -13 -
  12. 12. NoSQL全般  RDBMSから機能を削り  スループットや並列性を確保している  比較的低機能ではあるが一点豪華主義で  部分的にRDBMSを凌駕する機能を持つ  大抵は速度重視
  13. 13. -16 -
  14. 14. MongoDBの特徴 1. スキーマレス   2. 高機能Index   3. 高速   4. 並列性(& automatic failover)   ・耐障害性   ・スケーラビリティー   5.トランザクション無し    ・代わりのAtomic処理   6.JOIN無し
  15. 15. Index -18 -
  16. 16. MongoDBのIndex 商品名 ボールペン タグ 値段 日用品, 筆記用具 198 包丁 日用品, 刃物, キッチン 2980 バナナ 食料品, 果物 348 ほうれん草 食料品, 野菜 98 牛乳 食料品, 148     食料品で200以下の商品を取得
  17. 17. MongoDBのIndex 商品名 タグ 値段 ボールペン 日用品, 筆記用具 198 包丁 日用品, 刃物, キッチン 2980 バナナ 食料品, 果物 348 ほうれん草 食料品, 野菜 98 牛乳 食料品, 148 商品・テーブル CREATE TABLE 商品 (   id INT PRIMARY,   商品名 VARCHAR(100) ); タグ・テーブル CREATE TABLE タグ (   商品id INT,   タグ名 VARCHAR(100),   値段 INT,  KEY(タグ名,値段) ); 食料品で200以下の商品 商品投入 ■RDBMS INSERT INTO 商品 VALUES (1,'ボールペン'); INSERT INTO タグ VALUES (1,'日用品',198),    (1,'筆記用具',198);  苦手な処理      : クエリー  ・Index用のテーブルを SELECT * FROM  商品 INNER JOIN タグ   ON タグ.商品id = 商品.id   別途用意しJOIN WHERE タグ名 = '食料品' AND 値段 <= 200;  値段が重複管理で筋が悪い。。
  18. 18. MongoDBのIndex 商品名 タグ 値段 ボールペン 日用品, 筆記用具 198 包丁 日用品, 刃物, キッチン 2980 バナナ 食料品, 果物 348 ほうれん草 食料品, 野菜 98 牛乳 食料品, 148 商品投入 db.商品.save({  '商品名' : 'ボールペン',  'タグ': ['日用品', '筆記用具'],  '値段':198 } );        :        : 食料品で200以下の商品を取得 インデックス ■MongoDB db.商品.ensureIndex({  'タグ':1, '値段':1 });   データ形式、Index共に クエリー   完全にサポート! db.商品.find({   タグ構造にもってこい!!  'タグ':'食料品',  '値段': { $lte : 200 } });
  19. 19. MongoDBのIndex 商品名 ボールペン タグ 値段 日用品, 筆記用具 198 包丁 日用品, 刃物, キッチン 2980 バナナ 食料品, 果物 348 ほうれん草 食料品, 野菜 98 牛乳 食料品, 148     食料品で果物の商品を取得
  20. 20. MongoDBのIndex 商品名 タグ 値段 ボールペン 日用品, 筆記用具 198 包丁 日用品, 刃物, キッチン 2980 バナナ 食料品, 果物 348 ほうれん草 食料品, 野菜 98 牛乳 食料品, 148 食料品で果物の商品 ■RDBMS  SQLでの表現は困難   self join する? クエリー(2タグ限定版) SELECT  * FROM  タグ a  INNER JOIN  タグ b  ON   a.商品id = b.商品id   AND   a.タグ名 != b.タグ名  INNER JOIN 商品 c  ON   a.商品id = c.id WHERE  a.タグ名 = '食料品'  AND  b.タグ名 = '果物' GROUP BY  a.商品id;
  21. 21. MongoDBのIndex 商品名 タグ 値段 ボールペン 日用品, 筆記用具 198 包丁 日用品, 刃物, キッチン 2980 バナナ 食料品, 果物 348 ほうれん草 食料品, 野菜 98 牛乳 食料品, 148 食料品で果物の商品 ■MongoDB  $all が使える   今の実装では最初の   要素のみIndex scan クエリー db.商品.find({  'タグ': { $all : ['食料品', '果物']} });
  22. 22. MongoDBのIndex  主なIndex  ・配列へのIndex(tag)  ・複合Index  ・平面/球面座標Index  ・図形Index(交点,内包,近傍など各種検索)   ・円, 線, 多角形, etc  covered indexesも搭載  NoSQLの弱点を多機能なIndexで補う戦略
  23. 23. 高スループット -26 -
  24. 24. MongoDBのスループット 計測条件 ・3 core 3GB memory   ・構文解析込み(SQL, JS)   ・lo経由通信 (localhost) int(11)   ・1レコード、4kb程度 id int(11) PRI value0 value1 int(11)   ・1,000,000 レコード value2 int(11) value3 varchar(50) value4 varchar(50)     = 4GB value5 varchar(50) value6 varchar(50) value7 varchar(255)   ・11 column value8 int(11) value9 text   ・MySQLはInnoDB      
  25. 25. MongoDBのスループット Insert ・MySQL : 345 sec (5m 45s)  ・MongoDB : 123 sec (2m 03s)  ・(MyIsam ) : 240 sec (4m 00s)
  26. 26. MongoDBのスループット  Range fetch (10,000件 x 100) SELECT ・MySQL : 202 sec * FROM  ・MongoDB : 3.7 sec mytbl WHERE id BETWEEN 0 AND 9999;  Range count (10,000件 x 100) ・MySQL : 37 sec SELECT COUNT(*)  ・MongoDB : 0.4 sec FROM mytbl       WHERE id BETWEEN 0 AND 9999;
  27. 27. MongoDBのスループット  MongoDB 範囲検索は特に速い!   ・B-tree実装が良い  Countが速い!   ・カーソルの両端を先に見る Read >>> Write な WEBシステムに最適      
  28. 28. 並列性 -31 -
  29. 29. MongoDBの並列性  MongoDBは2つのスケールアウト方式   が用意されている  ・Replica-set(ミラーリング) Read系の並列化、対障害性  ・Sharding(パーティショニング)    Write系の並列化、大量データ対策
  30. 30. Replica-set -33 -
  31. 31. replica-set Primary: 書き込み可能ノード Secondary:  読み取り専用ノード 全てのノードは同じデータを持っている Primary 同期 Secondary Secondary Secondary Secondary -34 -
  32. 32. replica-set Primary: 書き込み可能ノード Secondary:  読み取り専用ノード Primaryが死んでも自動Failover Primary Primary 昇格 同期 Secondary Secondary Secondary Secondary -35 -
  33. 33. replica-set Primary: 書き込み可能ノード Secondary:  読み取り専用ノード 自動Failoverではsplit brainが怖いのでvotingで対策 (以下の例では4/5 で当選) Primary Primary 投票 Secondary Secondary Secondary Secondary -36 -
  34. 34. replica-set www.mongodb.jp httpd PHP mongo A mongo B mongod secondary mongod primary replica-set
  35. 35. replica-set www.mongodb.jp www.mongodb.jp httpd httpd PHP PHP mongo A mongo B mongo C mongod secondary mongod primary mongod secondary replica-set
  36. 36. Sharding -39 -
  37. 37. Sharding mongos:クエリーゲートウェイ       mapping情報に基づき振り分ける config: mapping情報を保持 key = 'abc' key = 'xyz' mongos config config config key => replicaset map a.. ~ hz.. => Replica-set1 ia.. ~ rc.. => Replica-set2 rd..~ z.. => Replica-set3 Replica-set1 Replica-set2 Replica-set3 -40 -
  38. 38. Sharding  RDBMSのパーティショニングと同じ発想  複数のReplica-setを束ねるイメージ  並列性や冗長性はReplica-setに任せる  Shardingキーの選択さえ適切ならば  Auto migrationでデータを適度に分散  
  39. 39.  詳細はコチラ Sharding
  40. 40. MongoDBの並列性  Read負荷が高いならReplica-set   MongoDBは元々高速なので殆どの問題は   Secondaryを増やせば解決する  Write負荷やデータ量の問題はSharding   Write負荷 :非時系列のShard-key   データ量 :時系列Shard-key         (扱いやすいから)
  41. 41. トランザクションが無い -44 -
  42. 42. MongoDBの排他  Webシステムでは、殆どの場合   トランザクションを使わない。使えない。  HTTPはstatelessなプロトコルで  statefulなトランザクションと相性が悪い。   掛けたまま帰っちゃう!   いつ戻って来るのか?   もう来ないのか?     不明!!
  43. 43. MongoDBの排他  とはいえ、ある程度の排他処理は必要  NoSQLでは楽観ロックが主流   並列化を目指すと悲観ロックは機能しない    memcached の CASが有名   (Check and Set)
  44. 44. MongoDBの排他 CAS  1. aがデータAをget A (cas=1)   memcached A (cas=1)
  45. 45. MongoDBの排他 CAS  1. aがデータAをget A (cas=1)  2. ほぼ同時にbがデータAをget   A (cas=1)   楽観ロックなので 取れて良い memcached A (cas=1)
  46. 46. MongoDBの排他 CAS  1. aがデータAをget A (cas=1)  2. ほぼ同時にbがデータAをget   A (cas=1)  3. aがデータAを更新   A' (cas=1) memcached cas値が一致する ので更新成功 A (cas=1) A' (cas=2)
  47. 47. MongoDBの排他 CAS  1. aがデータAをget  2. ほぼ同時にbがデータAをget   A (cas=1)  3. aがデータAを更新  4. bがデータAを更新 A''(cas=1) memcached A' (cas=2) cas値が不一致で 更新失敗
  48. 48. atomic操作 -51 -
  49. 49. atomic操作  MongoDBにはCASが無い   もっと強力なatomic操作がある  特に便利なatomic操作  $inc   フィールドをインクリメントする  $setOnInsert   upsertの際、insert時だけ値を設定する
  50. 50. 簡易CAS GET data1 = db.myData.findOne({ _id : 'FOO' }); PUT db.myData.update({ _id: data1._id,  cas: data1.cas },{ $inc : { cas : 1 }, $set { field1 : 'updated' } }); CASの実装は簡単  ・update時に常にcas値を1つ増加させる。  ・update時のクエリにドキュメントのcas値を使えば   衝突した際にはcas値が合わずupdateが失敗する -53 -
  51. 51. atomic操作  配列系のatomic操作  $pop / $pullAll / $pull   配列フィールドから値を削除  $pushAll / $push   配列フィールドに値を追加  capped array   配列フィールドに値を追加する際    任意の配列長に保つよう切り捨てる機能
  52. 52. findAndModify -55 -
  53. 53. atomic操作  MongoDBにはfindAndModifyがある  findAndModify   atomicにデータ取得と更新が出来る   ≒ SELECT ~ FOR UPDATE    +UPDATE    +COMMIT or ROLLBACK
  54. 54. 簡易MQ インデックス db.myMQ.ensureIndex({ tm: 1 }); 投入(アプリ)側 db.myMQ.save({  tm: 0,  Jobデータ }); ワーカー側 db.myMQ.findAndModify({ query: { tm : 0 },  update: { $set : { tm : 1 }} }); tm = 0 のドキュメントを拾うと同時にtm = 1 に更新してしまう。 他のワーカに拾われないという寸法! -57 -
  55. 55. 簡易Jobスケジューラ インデックス db.myMQ.ensureIndex({ tm:1 }); 投入(アプリ)側 db.myMQ.save({  tm: Number(ISODate())+3600,  Jobデータ }); ワーカー側 db.myMQ.findAndModify({ query: { tm : { $lte :Number(ISODate())}},  update: { $set : { tm : Number.MAX_VALUE }} }); tm に時刻(3600秒後)を入れれば、狙った時間にFireできる。 $inc : 3600の様にすれば定期的なJobにも出来る。 結構自由自在! -58 -
  56. 56. 簡易MapReduce ■単純なJobキュー ■MapReduce -59 -
  57. 57. Monmoちゃん -60 -
  58. 58. Monmoちゃん  findAndModifyを上手く使って   MapReduce環境を作ってみた。  V8 が優秀で思ったより使える!    MongoDB 以外何も要らない   (ロジックはDBの外で動作)
  59. 59. ついでに -62 -
  60. 60. MapReduce MongoDB付属のMapReduceは危険 Primaryで処理が走る ● 『DBでロジックが走る』ってどうなの? 並列化が出来ない ● NaN等で下手打つとDBが死ぬ ● 原則noscriptが基本!! -63 -
  61. 61. Joinが出来ない -64 -
  62. 62. Join あきらめよう・・・ -65 -
  63. 63. MongoDB 何に使おう? -66 -
  64. 64. まとめ  ・Readが非常に高速  ・多機能なIndex  ・高い並列性(&対障害性)  ・高い拡張性   WEBシステムのバックエンドDBに最適    DBキャッシュ層を省略し    システムを簡略化できる
  65. 65. まとめ  ・多機能なIndex    配列Index(タグそのもの)   タグ機能    DB自体に機能があるので    特別なコードが必要ない
  66. 66. まとめ  ・多機能なIndex    geohash :2次元座標Index    3dsphere :球面座標Index   地図機能 近隣の施設検索などがDBで完結
  67. 67. まとめ  ・強力なAtomic操作機能  ・対障害性   MQなど非同期系のバックエンドにも良い    システム間のセマフォ的な使い方ができる    非Javaへの親和性も貴重   
  68. 68. 最後に地雷の話 -71 -
  69. 69. 地雷の話  ■必須オプション   ・notablescan   ・noscript  ■難易度が高い機能   ・Sharding  ■地雷機能   ・MapReduce   ・Aggregate   ・Textサーチ   ・Background indexing  ■チューニングポイント   ・oplog   ・migration (Sharding)   ・コネクション数
  70. 70. 地雷の話  確かにMongoDBには幾つか地雷がある   (そして踏み易い)  巷にあるネガティブな情報は   地雷の爆発した跡     正しい使い方をすれば機能的にも性能的にも   非常に優秀なプロダクト
  71. 71. おしまい   有難う御座いました。

×