中年engineerの独り言 - crumbjp

LinuxとApacheの憂鬱

MongoDB3.2 readConcernの挙動について

実装

mongosの場合はもうちょっと複雑になるが、レプリカセットの場合はこの辺に実装があるようだ

=== /db/repl/replication_coordinator_impl.cpp ===
    auto loopCondition = [this, isMajorityReadConcern, targetOpTime] {
        return isMajorityReadConcern
            ? !_currentCommittedSnapshot || targetOpTime > _currentCommittedSnapshot->opTime
            : targetOpTime > _getMyLastOptime_inlock();
    };

    while (loopCondition()) {
        Status interruptedStatus = txn->checkForInterruptNoAssert();
        if (!interruptedStatus.isOK()) {
            return ReadConcernResponse(interruptedStatus, Milliseconds(timer.millis()));
        }

        if (_inShutdown) {
            return ReadConcernResponse(Status(ErrorCodes::ShutdownInProgress, "shutting down"),
                                       Milliseconds(timer.millis()));
        }

        stdx::condition_variable condVar;
        WriteConcernOptions writeConcern;
        writeConcern.wMode = WriteConcernOptions::kMajority;

        WaiterInfo waitInfo(isMajorityReadConcern ? &_replicationWaiterList : &_opTimeWaiterList,
                            txn->getOpID(),
                            &targetOpTime,
                            isMajorityReadConcern ? &writeConcern : nullptr,
                            &condVar);

        if (CurOp::get(txn)->isMaxTimeSet()) {
            condVar.wait_for(lock, Microseconds(txn->getRemainingMaxTimeMicros()));
        } else {
            condVar.wait(lock);
        }
    }

どうもmajorityになるまで単純にwhile ループで待ってるようだが
こんな乱暴な事をすると、簡単にDOSになりそうだが、どうなんだろう?

仮に 1秒位遅延が起きた時に、5000 queryも readConcern: majority でクエリーすると何が起きるか?
余裕でリクエストを処理するスレッドを潰されてしまいそうな気がする。

だれか一緒に検証してくれる人いませんかね??

MongoDB3.2 ReleaseNote所感

そろそろ3.2も手を付けようと思うので、検証がてらつらつらと。。

リリースノート

https://docs.mongodb.org/manual/release-notes/3.2/

非常に丁寧な日本語訳があるので、こちらもどうぞ
http://qiita.com/fetaro/items/cd570d70623b58b5deef

WiredTiger as Default

まあ規定路線なので、特に気にする必要なし。

Replication Election Enhancements

Primaryが落ちた時の検知が早くなった。
どういうシチュエーションでどの位早くなるのかはまだ検証してない。
少なくとも今迄の落ち認定10秒をカスタマイズ可能になった。
その他色々timeout値が弄れるようになった様だが、これはまだ実験段階なんだろう。と読む事もできる。
要注目

Sharded Cluster Enhancements

configサーバが独自2-phase-commit ではなく、普通のReplicaSet で組めるようになった。
今迄は3ノード限定。1ノードでも落ちたら(shard周りの)更新不能だったが、可用性が格段に上がったということだ。

readConcern

書き込み時の保証であるwriteConcernだけでなく、読み込み時の保証が取れるようになった。
ただ、こんな事をしてどうやって性能を上げるつもりなのか解らない
これはコードを読む必要がありそう。

Partial Indexes

全ドキュメントにインデックスを張らない随分とチャレンジングな機能。
正にドキュメントベース独特の悩みの具現化だな。
これは機能としては素晴らしいがアプリ側がかなり大変そうな気がする。
限定した使い方なら非常によさそう。

例えば、{ active: true } のドキュメントだけ indexに含める。
といった使い方が良い。
この様なケースならば、Oracleのbitmap indexより効率的かもしれない。

Document Validation

謎機能!!
ドキュメントベースのDBでこれをやるか!!
只でさえフィールドがnull、undefinedで、クエリー周りの混乱があるのにこういう事すると更に拍車をかけそう。
沢山失敗例がネットに溢れると思われる

Aggregation Framework Enhancements

色々足されているが、 まずは$lookupだけ気にしていれば良い。
他は細々しているが

  • 演算系のオペレータは嬉しい。
  • $unwind が配列以外を受け付けなくなったのがちょっと痛い
  • covered indexが有効になったので軽くなるケースも若干ある。(むしろ$lookupで有効ならば非常に嬉しい機能)
MongoDB Tools Enhancements

mongodump / mongorestore が圧縮転送可能になったので、ありがちな、mongodump & s3 に放り込む。といったバックアップが早くなるのが嬉しい。

Text Search Enhancements

例によって無視

New Storage Engines

気にする必要なし

General Enhancements

ビット演算オペレータは使えるケースがあるかな?無いよな・・・
ドキュメントベース使っててフィールド分けない理由が無いんだけど・・・

SpiderMonkey JavaScript Engine

なぜだ!!

WiredTiger and fsyncLock

以前にも触れたが、やっとまともにバックアップが取れるようになる。


あとは良いや。

3.2は新バージョンというより3.0 系の決定版のような位置づけっぽいですね。

AWS上にハイパフォーマンスMongoDBを構築する方法

AWSインスタンスの選定

AWSインスタンスタイプ一覧

以下のインスタンスボリュームが付随しているプロダクトラインが候補になる。
個人的にはi2.xxx が好みである。

r3.xxx
メモリ最適化インスタンス
i2.xxx
SSD容量最適化インスタンス

ただし、インスタンスボリュームはスナップショットが取れず、揮発性なので取り回しが悪い。
Provisioned IOPS (SSD) ボリュームも検討候補になるが、高くつく事になるのでお金持ちの人用。。

バックアップ戦略

流石にバックアップを全く取らずに運用する事は出来ないので
以下様にレプリカセット構成を組み、バックアップを取る。

最後のノードはバックアップ専用なので、SSD以外は非力出よい。
ただしあまり小さいインスタンスを選択するとネットワーク容量が足りなくなるのでそこを考慮して選定する。

構成例

  • i2.4xlarge
  • i2.4xlarge
  • r3.large + 2400GiB EBS Magnet

もちろん負荷に依るが、この様な構成でも成立する。

AWS 周りの必要知識

//docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/i2-instances.html">i2インスタンス:基本使用ボリュームが大きいほどIOPSが高くなる

SSDオーバープロビジョニングの為に、10%ほど未使用領域を残す。激しく使うならi2.2xlarge以上。そうじゃないとネットワークが負ける。

//docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/InstanceStorage.html#InstanceStoreTrimSupport">TRIMサポート:i2 と r3 のインスタンスボリュームは TRIM がサポートされてる。
//docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/storage_expand_partition.html">パーティションファイルシステム設定関連:

手順

1. 普通に AWS console から作る場合


OS領域はマグネットで十分。インスタンスストアを全部追加すること。

2. デバイスを確認
# lsblk
NAME    MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
xvda    202:0    0    40G  0 disk
└─xvda1 202:1    0    40G  0 part /
xvdb    202:16   0 745.2G  0 disk

`xvdb` がインスタンスボリューム

3a. インスタンスボリュームが1つの場合はオーバープロビジョニング用の未使用領域を10%確保

インスタンスボリュームのサイズは800GiB単位で、インスタンスの大きさによって複数のインスタンスボリュームが付随する。
1つだった場合はそのまま使えば良いがSSDの性能を生かす為にオーバープロビジョニングの設定をする。

# gdisk /dev/xvdb

* パーティション(/dev/xvdb1)作成
Command : n
Partition number : 1
FirstSector: 2048
LastSector: XXXX ※ 最後のセクタから10%程余らせた部分を指定する
GUID: 8300

* 名前変更
Command : c
Enter name: Linux

* GUID生成
Command : x
Expert command : g
unique GUID: R

* 確認
Expert command: p
Disk /dev/xvdb: 1562822320 sectors, 745.2 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): 4E2273AF-9E75-401A-8D3E-365A4D9674AC
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 1562822286
Partitions will be aligned on 2048-sector boundaries
Total free space is 156284525 sectors (74.5 GiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048      1406539775   670.7 GiB   8300  Linux

* 反映
Command : w
3b. インスタンスボリュームは2つの場合はRAID0を設定する

本来は各SSDにオーバープロビジョニングを指定した方が良いと思うが、そもそも大容量のストレージを常に使い切りそうな使い方自体がマズいので、運用上、常にある程度の未使用領域が残っている状態が保たれるはず。
そうなると、ある程度TRIMだけで対処できるのではないか?という想像の元にこうしている。
※ 誰か詳しい人が居たら教えてください

`mdadm` が無ければ apt-get install mdadm

インスタンスボリュームが4個の場合

# mdadm --create /dev/md0 --level=0 --raid-devices=4 /dev/xvdb /dev/xvdc /dev/xvdd /dev/xvde

以降、/dev/xvdb1 は /dev/md0 に読み替えてください。

4. ファイルシステムXFSを作る

`mkfs.xfs` が無ければ `apt-get install xfsprogs`

# mkfs.xfs -K /dev/xvdb1
5. マウント

TRIMを有効にする為にdiscardを指定する

# mkdir -p /data
# mount -o discard /dev/xvdb1 /data
== /etc/fstab ==

/dev/xvdb1 /data auto defaults,nobootwait,discard 0 2

# raidしている場合は `blkid /dev/md0`で取得できるuuidを指定する
UUID="**uuid**" /data auto defaults,nobootwait,discard 0 2
6. TRIM が効いてるか確認
# fstrim -v /data/
/data/: 3199094800384 bytes were trimmed
7. ここで一回リブートする
8. MongoDBディレクトリを作る
# mkdir /usr/local/mongodb
# mkdir -p /data/mongo
# ln -sfT /data/mongo /usr/local/mongodb/data
9. limits のnofileを多めに変更

https://docs.mongodb.org/manual/reference/ulimit/

後は普通にMongoDBを構築してください。
リンク先の設定がそのまま使えるはずです。

あまり頻発するような問題ではないようだ

http://d.hatena.ne.jp/hiroppon/20151216/1450251504
以前、MongoDB3.0系のバックアップを取り上げた。

色々検証したが、データファイル自体が破壊されるような事は起きなかった。
中のデータがある程度おかしいのかもしれないし、極稀にファイル破壊が起きるのかもしれないが
あまり大きな問題では無い様な気がする。

バックアップができない!?

ご存知の様にMongoDBのバックアップは

  1. fsyncLock
  2. Snapshot
  3. fsyncUnlock

の流れなのだが、、
最近、MongoDB3.2 系のドキュメントにこんな事が書かれていた

Compatibility with WiredTiger
Changed in version 3.2: Starting in MongoDB 3.2, db.fsyncLock() can ensure that the data files do not change for MongoDB instances using either the MMAPv1 or the WiredTiger storage engine, thus providing consistency for the purposes of creating backups.

In previous MongoDB version, db.fsyncLock() cannot guarantee a consistent set of files for low-level backups (e.g. via file copy cp, scp, tar) for WiredTiger.

まじか・・・ありえん!!
3.0 系に移行したばっかなのに、3.2系にまた移れってのか!?
データのコンシステンシーが多少失われてもまあ許容するが、データファイルが破壊されると厄介だ。
検証中だが、まだ問題は発生してない。。
うーむ。。。

MongoDB3.0.xの設定ファイルテンプレ

Advent Calendar にも投稿した内容ですが、MongoDB3系の設定周り。
僕はこんな感じで運用してますよ。という位の内容。

/usr/local/mongodb/ 以下に構築する場合の設定周り

1. ディレクトリ構成

バイナリをDLして適当に配置してください。

# mkdir -p /usr/local/mongodb/conf
# mkdir -p /usr/local/mongodb/logs
# mkdir -p /usr/local/mongodb/tmp
# ln -s <path to data path> /usr/local/mongodb/data
# ln -s <path to bin path> /usr/local/mongodb/bin

2. Keyfileを作る

MongoDB3系からセキュリティ周りが厳しくなり、replica-setへJOINさせる際にkeyfileによる認証が必要になりました。
StandAloneの場合は不要です。

openssl rand -base64 741 > /usr/local/mongodb/conf/mongod.key

設定ファイルテンプレ

しっかり設定しなければならないのは以下の2点くらい

storage.wiredTiger.engineConfig.cacheSizeGB: 100

インデックス構築や、cursor処理、メモリリーク(orz...)でも消費されるので
現状ではメインメモリの80% 程度に調整しておいた方が良さそうです。

replication.oplogSizeMB: 102400

これは用途によって適当に。。

processManagement:
  fork: true
  pidFilePath: /usr/local/mongodb/logs/mongod.pid

net:
  port: 27017
  maxIncomingConnections: 1000000
  unixDomainSocket:
    enabled: true
    pathPrefix: /usr/local/mongodb/tmp/
  http:
    enabled: false
    JSONPEnabled: false
    RESTInterfaceEnabled: false

security:
  authorization: enabled
  javascriptEnabled: true
  keyFile: /usr/local/mongodb/conf/mongod.key

operationProfiling:
  slowOpThresholdMs: 1000
  mode: slowOp

storage:
  engine: wiredTiger
  dbPath: /usr/local/mongodb/data
  directoryPerDB: true
  indexBuildRetry: true
  syncPeriodSecs: 60
  wiredTiger:
    engineConfig:
      cacheSizeGB: 100
      statisticsLogDelaySecs: 0
      journalCompressor: snappy
      directoryForIndexes: true
    collectionConfig:
      blockCompressor: snappy
    indexConfig:
      prefixCompression: true
  journal:
    enabled: true

replication:
  oplogSizeMB: 102400
  replSetName: MyRS
  secondaryIndexPrefetch: all

MongoDB3系(WiredTiger)の現状

ご無沙汰してます。

最近全然更新出来てない訳ですが、MongoDBに愛想が尽きて、離れていた訳ではありません。
むしろガッツリ嵌ってます。。

最近は MongoDB3 系 WiredTiger を使いながら頑張っている訳ですが・・・
キリの良い所で書こうと思っていたのに、メドが立たないので近況だけでも書いておこうかと思った次第。。

で、、mongo3... コイツすぐ落ちる!!

まあ、普通にメモリーリークですが、、ちょっと目を離すと

Tasks: 169 total,   1 running, 168 sleeping,   0 stopped,   0 zombie
%Cpu(s): 12.4 us,  0.7 sy,  0.0 ni, 86.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:  62916396 total, 62567524 used,   348872 free,    13332 buffers
KiB Swap:        0 total,        0 used,        0 free.    60212 cached Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
16865 zenclerk  20   0 60.906g 0.058t   2744 S   0.0 98.3  12323:54 mongod
  859 syslog    20   0  322440   6900    216 S   0.0  0.0   0:02.80 rsyslogd

おい!舐めんな!!!
60GB使い切るか..


で、、最近 3.0.7が出ました。release note

なかでもこの2つは注目です

//jira.mongodb.org/browse/SERVER-20159">SERVER-20159 Out of memory on index build during initial sync even with low cacheSize parameter: そう。index張るとメモリー使い切って死ぬ・・・(メモリー足りてもリークしてたっぽい)
//jira.mongodb.org/browse/SERVER-20091">SERVER-20091 Poor query throughput and erratic behavior at high connection counts under WiredTiger: コネクションが多いとクエリーが重くなる・・・

早速試してますが、まあ改善した感じがします。
そろそろマトモになって来た感がありますね。
本番に使い始めてもよいかも〜


ただ、この大物が控えているのでまだ安心出来ません。。

//jira.mongodb.org/browse/SERVER-20306">SERVER-20306 75% excess memory usage under WiredTiger during stress test: 多分、僕の環境で起きてるのはコレなんだよなぁ・・

でも、逆にあとコレだけ解決してくれれば、いい感じになるはず!