ある日、急にMongoDBが落ちるようになった。
ログを見る限り、「ロックファイルが残っているため立ちあげられない」という情報のみだった。
目次
ダウン原因の調査
エラーログやMuninなどの監視ツールを調査した結果、ダウンした際の共通点があった。
それは
- メモリを2GB以上喰った際に落ちている
- MongoDBのロックファイルが残っている
ということだった。
一歩前進はしたが「メモリを2GB以上使うと落ちる」といった言語仕様や症例もなく、これだけでは原因特定が困難だった。
しかし、よくよく調べていくと同一サーバで動いているMySQLもおおよそ2GBのメモリを使用している。
そして、このサーバの物理メモリは4GBだ。
MongoDBがダウンする原因の仮説
- メモリリークが起こり、MongoDBがロックファイルを残したままダウンする
- 自動復帰するために再起動するが、ロックファイルがあるため立ち上がらない
というものである。
MongoDBダウンの回避対策
MongoDBのメモリ利用量を制限することで、メモリリークを起こさないようにしてみる。
しかし、残念ながらMongoDB v2系はメモリ制限の機能が存在せず、上記のような対策をとることが出来ない。
だが諦めるのはまだ早い。
Mongo v3から新規で追加されたストレージエンジン「Wired Tiger」にはメモリを制限する機能が備わっている。
これだ!
ということで、
- MongoDBをv2からv3にアップデートし
- さらにストレージエンジンを「mmap」から「Wired Tiger」に切り替え
- 「Wired Tiger」でメモリ制限をする
ことでMongoDBのダウンが再現しないか検証する。
MongoDBがインストールされているサーバ環境
環境はさくらのVPSです。
メモリ4GBのHDDプランだったと思いますので、下記の感じですかね。
- OS: CentOS 6.5
- メモリ:4GB
どこにでもあるCentOSのVPS機です。
では、これからMongoDBアップデートの旅に出かけましょう。
MongoDBのアップデートの前準備
CentOSのビットを確認
MongoDBには32bit版と64bit版があります。
32bit版は非推奨なので、OSが64bitであれば、可能な限り64bitをインストールしたいので、OSのbitを調べます。
[root@server ~]# uname -m x86_64
上記が「x86_64」なら64bitです。
32bitだと「i686」などが返ってきます。
MongoDBをバックアップ
mongod.confの場所を調べ、mongodbのデータパスを明確にする。
ps aux | grep mongod mongod 11488 8.4 4.9 877920 192672 ? Sl Mar05 514:23 /usr/bin/mongod -f /etc/mongod.conf
dbpathを調べる
[root@server ~]# grep dbpath /etc/mongod.conf dbpath=/var/lib/mongo
mongodbを停止
[root@server ~]# service mongod stop Stopping mongod: [ OK ]
バックアップを取得
バックアップ先のディレクトリを作る
[root@server ~]# mkdir ~/mongo_dump
作成したディレクトリにバックアップのダンプを出力
[root@server ~]# mongodump -v --dbpath /var/lib/mongo --out ~/mongo_dump/
Wed Mar 9 23:40:19.786 [tools] flushing directory /var/lib/mongo
Wed Mar 9 23:40:19.794 [tools] run command admin.$cmd { isdbgrid: 1 }
Wed Mar 9 23:40:19.794 [tools] command admin.$cmd command: { isdbgrid: 1 } ntoreturn:1 keyUpdates:0 reslen:99 0ms
Wed Mar 9 23:40:19.795 [tools] all dbs
Wed Mar 9 23:40:19.795 [tools] run command admin.$cmd { listDatabases: 1 }
Wed Mar 9 23:40:19.806 [tools] opening db: local
Wed Mar 9 23:40:19.840 [tools] opening db: admin
Wed Mar 9 23:40:19.859 [tools] opening db: db1
… 中略
Wed Mar 9 23:40:21.299 dbexit:
Wed Mar 9 23:40:21.299 [tools] shutdown: going to close listening sockets...
Wed Mar 9 23:40:21.299 [tools] shutdown: going to flush diaglog...
Wed Mar 9 23:40:21.299 [tools] shutdown: going to close sockets...
Wed Mar 9 23:40:21.299 [tools] shutdown: waiting for fs preallocator...
Wed Mar 9 23:40:21.299 [tools] shutdown: closing all files...
Wed Mar 9 23:40:21.315 [tools] closeAllFiles() finished
Wed Mar 9 23:40:21.315 [tools] shutdown: removing fs lock...
Wed Mar 9 23:40:21.330 dbexit: really exiting now
MongoDBをアンインストール
バックアップの作成が完了したので、2.x系のMongoDBをアンインストールしましょう。
アンインストールはコマンド一発です。
[root@server ~]# yum remove mongo* Loaded plugins: fastestmirror, security Setting up Remove Process No Match for argument: mongo_dump Loading mirror speeds from cached hostfile Could not get metalink https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=x86_64 error was 14: problem making ssl connection * epel: ftp.kddilabs.jp * rpmforge: mirror.fairway.ne.jp 10gen | 951 B 00:00 base | 3.7 kB 00:00 extras | 3.4 kB 00:00 "> [Errno 14] PYCURL ERROR 22 - "The requested URL returned error: 404 Not Found" Trying other mirror. rpmforge | 1.9 kB 00:00 updates | 3.4 kB 00:00 updates/primary_db | 3.9 MB 00:00
無事アンインストールができたら、次にv3系のMongoDBをインストールしましょう。
公式サイトを参考にMongoDB v3.2をインストール
それではMongoDBをインストールしていきましょう。
インストールの手順は下記の公式マニュアルが非常に丁寧に説明してくれているので、見ながら順に実行していけば問題ないかと思います。
公式リポジトリを登録
vi /etc/yum.repos.d/mongodb-org-3.2.repo
[mongodb-org-3.2] name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.2/x86_64/ gpgcheck=0 enabled=1
YumでMongoDBをインストール
インストールもyumコマンド一発です。
簡単になりましたね。
[root@server ~]# sudo yum install -y mongodb-org
Loaded plugins: fastestmirror, security
Loading mirror speeds from cached hostfile
Could not get metalink https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=x86_64 error was
14: problem making ssl connection
* epel: ftp.kddilabs.jp
* rpmforge: mirror.fairway.ne.jp
http://www.hop5.in/yum/el6/repodata/repomd.xml: [Errno 14] PYCURL ERROR 22 - "The requested URL returned error: 404 Not Found"
Trying other mirror.
mongodb-org-3.2 | 2.5 kB 00:00
mongodb-org-3.2/primary_db | 26 kB 00:00
Setting up Install Process
Resolving Dependencies
--> Running transaction check
---> Package mongo-10gen.i686 0:2.4.5-mongodb_1 will be obsoleted
---> Package mongodb-org.x86_64 0:3.2.4-1.el6 will be obsoleting
--> Processing Dependency: mongodb-org-tools = 3.2.4 for package: mongodb-org-3.2.4-1.el6.x86_64
--> Processing Dependency: mongodb-org-shell = 3.2.4 for package: mongodb-org-3.2.4-1.el6.x86_64
--> Processing Dependency: mongodb-org-server = 3.2.4 for package: mongodb-org-3.2.4-1.el6.x86_64
--> Processing Dependency: mongodb-org-mongos = 3.2.4 for package: mongodb-org-3.2.4-1.el6.x86_64
--> Running transaction check
---> Package mongo-10gen-server.i686 0:2.4.5-mongodb_1 will be obsoleted
---> Package mongodb-org-mongos.x86_64 0:3.2.4-1.el6 will be installed
---> Package mongodb-org-server.x86_64 0:3.2.4-1.el6 will be obsoleting
---> Package mongodb-org-shell.x86_64 0:3.2.4-1.el6 will be installed
---> Package mongodb-org-tools.x86_64 0:3.2.4-1.el6 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
=============================================================================================================================================================================================================================================================================
Package Arch Version Repository Size
=============================================================================================================================================================================================================================================================================
Installing:
mongodb-org x86_64 3.2.4-1.el6 mongodb-org-3.2 5.8 k
replacing mongo-10gen.i686 2.4.5-mongodb_1
mongodb-org-server x86_64 3.2.4-1.el6 mongodb-org-3.2 13 M
replacing mongo-10gen-server.i686 2.4.5-mongodb_1
Installing for dependencies:
mongodb-org-mongos x86_64 3.2.4-1.el6 mongodb-org-3.2 5.6 M
mongodb-org-shell x86_64 3.2.4-1.el6 mongodb-org-3.2 6.9 M
mongodb-org-tools x86_64 3.2.4-1.el6 mongodb-org-3.2 37 M
Transaction Summary
=============================================================================================================================================================================================================================================================================
Install 5 Package(s)
Total download size: 63 M
Downloading Packages:
(1/5): mongodb-org-3.2.4-1.el6.x86_64.rpm | 5.8 kB 00:00
(2/5): mongodb-org-mongos-3.2.4-1.el6.x86_64.rpm | 5.6 MB 00:00
(3/5): mongodb-org-server-3.2.4-1.el6.x86_64.rpm | 13 MB 00:01
(4/5): mongodb-org-shell-3.2.4-1.el6.x86_64.rpm | 6.9 MB 00:00
(5/5): mongodb-org-tools-3.2.4-1.el6.x86_64.rpm | 37 MB 00:03
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total 11 MB/s | 63 MB 00:05
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
Installing : mongodb-org-tools-3.2.4-1.el6.x86_64 1/7
Installing : mongodb-org-server-3.2.4-1.el6.x86_64 2/7
Installing : mongodb-org-mongos-3.2.4-1.el6.x86_64 3/7
Installing : mongodb-org-shell-3.2.4-1.el6.x86_64 4/7
Installing : mongodb-org-3.2.4-1.el6.x86_64 5/7
Erasing : mongo-10gen-server-2.4.5-mongodb_1.i686 6/7
warning: /var/log/mongo/mongod.log saved as /var/log/mongo/mongod.log.rpmsave
Erasing : mongo-10gen-2.4.5-mongodb_1.i686 7/7
Verifying : mongodb-org-shell-3.2.4-1.el6.x86_64 1/7
Verifying : mongodb-org-mongos-3.2.4-1.el6.x86_64 2/7
Verifying : mongodb-org-server-3.2.4-1.el6.x86_64 3/7
Verifying : mongodb-org-tools-3.2.4-1.el6.x86_64 4/7
Verifying : mongodb-org-3.2.4-1.el6.x86_64 5/7
Verifying : mongo-10gen-server-2.4.5-mongodb_1.i686 6/7
Verifying : mongo-10gen-2.4.5-mongodb_1.i686 7/7
Installed:
mongodb-org.x86_64 0:3.2.4-1.el6 mongodb-org-server.x86_64 0:3.2.4-1.el6
Dependency Installed:
mongodb-org-mongos.x86_64 0:3.2.4-1.el6 mongodb-org-shell.x86_64 0:3.2.4-1.el6 mongodb-org-tools.x86_64 0:3.2.4-1.el6
Replaced:
mongo-10gen.i686 0:2.4.5-mongodb_1 mongo-10gen-server.i686 0:2.4.5-mongodb_1
Complete!
これでインストールは完了です。
続いて設定に移っていきましょう。
MongoDBが起動出来るようにSELinuxを設定する
SELinuxに対し、MongoDBを許容するように設定します。
今回は問題となっているダウン症状が再現するかどうかのテストが目的であり、面倒だったので、SELinuxを無効化します。
必要に応じて、許容か無効化かを選択してください。
SELinuxの設定ファイルを作成する
vi /etc/selinux/config
作成したファイル内に下記を書き込む
SELINUX=disabled
無効になっているかを確認
「getenforce」コマンドでDisabledになれば無効になっています。
[root@server ~]# getenforce Disabled
WiredTiger用の設定ファイルを記述する
MongoDBの新たなストレージエンジンである「WiredTiger」を利用するための設定を記述します。
設定はYAML形式で記述します。
設定ファイルを作成する。
ファイル名は何でもOKです。
vi /etc/mongod_wt.conf
設定を記述する
DBパスやその他設定は適宜変更してください。
今回、メモリを2GB以上利用して死んでいたので、サイズ制限を1GBに設定しました。
storage: dbPath: "/var/lib/mongo_wt" engine: "wiredTiger" directoryPerDB: true wiredTiger: engineConfig: cacheSizeGB: 1 directoryForIndexes: true statisticsLogDelaySecs: 0 collectionConfig: blockCompressor: "snappy" indexConfig: prefixCompression: true journal: enabled: true systemLog: destination: file path: "/var/log/mongodb/mongodb_wt.log" logAppend: true processManagement: fork: true
参考:http://qiita.com/kuwa_tw/items/0a5704e9e505cffeae34
MongoDBの起動・リストア
アンインストール、インストール、設定ファイルの記述と終われば、いよいよ起動です。
起動の前に設定ファイルで定義したデータ保存ディレクトリがなければ作っておきましょう。
mkdir /var/lib/mongo_wt
設定ファイルのパスを指定して起動する
毎回起動する際の設定がめんどうならば、
- 設定ファイルを「/etc/mongod.conf」に作成する
- 「/etc/init.d/mongod」の設定ファイルパスを書き換える
のどちらかでパス指定が不要になります。
[root@server ~]# mongod -f /etc/mongod_wt.conf about to fork child process, waiting until server is ready for connections. forked process: 32733 child process started successfully, parent exiting [root@server ~]# service mongod status mongod (pid 32733) is running...
バックアップしていたデータファイルをリストアする
無事起動したら、バックアップしていたデータをリストアしましょう。
[root@server ~]# mongorestore -v --db db1 ~/mongo_dump/db1/ 2016-03-10T00:20:41.028+0900 using write concern: w='1', j=false, fsync=false, wtimeout=0 2016-03-10T00:20:41.028+0900 building a list of collections to restore from /root/mongo_dump/db1 dir … 中略 2016-03-10T00:20:59.229+0900 finished restoring db1.items (65950 documents) 2016-03-10T00:20:59.229+0900 done
これで起動は完了です。
大きなトラブルもなく、v2系からv3系に更新出来てよかったよかった。
そんなに世の中甘くない
バージョンアップにトラブルはつきもの。
うまく行ったと思っていたが、MongoDBのデータを読み書きするPHPスクリプトにアクセスしたら…
_人人人人人人_
> 突然の死 <
 ̄Y^Y^Y^Y^Y ̄
えっ。真っ白だよ。
PHPからMongoDBにつながらない。
そう。PHPからMongoDBにつながらないのである。
原因を確認したところ、なんと現行で動かしていたドライバ「mongo」にエラーが発生した。
PeclでインストールしたドライバがMongo v2.6までしか対応していなかったのだ。
仕方ないので、mongodb1.1をインストールすることに。
peclでインストールしたドライバがダメなら新しいやつインストールしてみよう。
そう思い、mongodb1.1をインストールしてみる。
sudo pecl install mongodb
vi /etc/php.d/mongo.so
開いたファイルの内容を
extension=mongodb.so
に変更。
よしよし。問題なくPHPドライバ「mongodb」がインストールされたので、再度確認。
_人人人人人人人人人人人人人人人人人人人人人人人人_
> Fatal Error – Class ‘MongoClient’ not found <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄
つまり・・・当然プログラム全部書き換え!!
そんなのはお断りです。
…ということで
PHPドライバについて調べる
を参照。
mongo1.6ならmongodb v3.0に対応してるっぽい。
peclのmongoのバージョン確認
[root@server ~]# pecl list Installed packages, channel pecl.php.net: ========================================= Package Version State jsonc 1.3.9 stable memcache 2.2.7 stable memcached 2.2.0 stable mongo 1.6.12 stable mongodb 1.1.3 stable xdebug 2.3.3 stable xhprof 0.9.4 beta zip 1.13.1 stable
1.6だった。
ということで…。
再度DB側でv3.2をアンインストール→v3.0をインストール。
一度やった手続きなので慣れたもの。
サービスを停止し、MongoDBをアンインストールする。
やり方自体は公式ドキュメントに懇切丁寧に書いてあったので、それをなぞる。
sudo service mongod stop sudo yum erase $(rpm -qa | grep mongodb-org)
v3.0をインストール
vi /etc/yum.repos.d/mongodb-org-3.0.repo
リポジトリを登録。
この時、以前登録した3.2のファイルは消しておきましょう。
[mongodb-org-3.0] name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.0/x86_64/ gpgcheck=0 enabled=1
yumでインストール実行。
sudo yum install -y mongodb-org
設定ファイルを指定し、起動。バックアップからデータのリストアを実行。
[root@server plugins]# mongod -f /etc/mongod_wt.conf [root@server plugins]# mongorestore -v --db db1 ~/mongo_dump/db1/ 2016-03-10T01:16:24.897+0900 using write concern: w='1', j=false, fsync=false, wtimeout=0 … 中略 2016-03-10T01:16:33.330+0900 finished restoring db1.items (65950 documents) 2016-03-10T01:16:33.330+0900 done
元気に稼働し始めました。
よかったよかった。
番外編:Muninの監視から外れる
muninでメモリとか監視していたが、再インストール後監視から外れていたため、再登録を行う。
調べると、muninのmongodbプラグインはインストールされているが、稼働していない状態だった。
とりあえずMuninのプラグインを単体でテストしてみる。
[root@server plugins]# cd /etc/munin/plugins
[root@server plugins]# munin-run mongo_ops
Traceback (most recent call last):
File "/etc/munin/plugins/mongo_ops", line 56, in <module>
doData()
File "/etc/munin/plugins/mongo_ops", line 33, in doData
ss = getServerStatus()
File "/etc/munin/plugins/mongo_ops", line 28, in getServerStatus
raw = urllib2.urlopen(req).read()
File "/usr/lib64/python2.6/urllib2.py", line 126, in urlopen
return _opener.open(url, data, timeout)
File "/usr/lib64/python2.6/urllib2.py", line 391, in open
response = self._open(req, data)
File "/usr/lib64/python2.6/urllib2.py", line 409, in _open
'_open', req)
File "/usr/lib64/python2.6/urllib2.py", line 369, in _call_chain
result = func(*args)
File "/usr/lib64/python2.6/urllib2.py", line 1190, in http_open
return self.do_open(httplib.HTTPConnection, req)
File "/usr/lib64/python2.6/urllib2.py", line 1165, in do_open
raise URLError(err)
urllib2.URLError: <urlopen error [Errno 111] Connection refused>
エラーメッセージを読むと、RESTアクセス出来てないようだ。
調べたところ、セキュリティの関係上、MongoDBはデフォルトではRESTが無効になっているようだ。
設定ファイルに下記を加筆して、再度Mongoを起動
net:
http:
enabled: true
JSONPEnabled: true
RESTInterfaceEnabled: true
これでRESTを許可したので、Muninからもアクセスが行えるようになったはずである。
再度テスト
[root@server plugins]# munin-run mongo_ops getmore.value 0 insert.value 0 update.value 0 command.value 0 query.value 1 delete.value 0
いけた。
munin-nodeの再起動
[root@server plugins]# service munin-node restart Stopping Munin Node agents: [ OK ] Starting Munin Node: [ OK ]
MuninのMongoDBのトラッキングも再設定できました。
あとがき
1ヶ月以上運用した結果、いまのところ以前のようなMondoDBダウンは1度も発生していません。
仮説の通り、単純にメモリ不足によるエラーだったものと思われます。
MongoDB自体アップグレードし、性能が上がり、メモリ利用量も少なくなっているので、結果オーライだと思います。