はじめに
本記事は、NoSQLのMongoDBについて、最速で理解することを目標に、MongoDBの導入、mongoシェルの基本的な操作、バックアップ及びログローテーション等についてまとめました。
NoSQL
Webサービスで利用されるデータベースとして、NoSQLも大分浸透してきました。
二大巨頭であるMySQLやPostgreSQLの後ろをしっかり走っています。
かつて、2011年頃まではWebサービスのアクセス数上位20サイトのうち、世界では18サイト、国内では19サイトで利用しているRDBMSとして、MySQLが挙げられていてました。(参考記事)
また、PostgreSQLについても、現在も世界中で多く使用されていると思います。
RDBMSがここまで長く使われてきた理由は、汎用的ゆえに、信頼性を要求されるOLTPや複雑な検索に特化したDWH、更新負荷の高いバッチ処理等いかなる局面において求められるパフォーマンスを発揮していたからではないでしょうか。
高速・軽量のMySQL、高機能・高可用性のPostgreSQLは、アーキテクチャをはじめ、哲学の違いもありますが、それぞれ素晴らしいソフトウェアです。
しかし、高速検索が求められるWebサービスで必要なのは、シンプルさになります。
そこで、シンプルな検索を高速化することを得意としたNoSQLが台頭してきたのは、必然でした。
以下、Wikipediaより。
NoSQL(一般に "Not only SQL" と解釈される)とは、関係データベース管理システム (RDBMS) 以外のデータベース管理システムを指すおおまかな分類語である。
NoSQLの種類
キーバリュー型データベース
キーバリュー型データベースは、キーバリューストア(KVS:Key-Value Store)とも呼ばれ、データを"キー":"バリュー"の配列(連想配列)で保持します。利点としては、このシンプルにより、パフォーマンスがいいことが挙げられます。
ドキュメント指向データベース
ドキュメント指向データベースは、1件分のデータを「ドキュメント」としてデータを格納します。また、個々のドキュメントのデータ構造は自由で、データを追加する都度変えることができます。スキーマレスになるので、リレーショナルデータベースとは違って、事前にテーブルの構造を決めておく必要がありません。また、最大の利点は、スケーラビリティを重視していることです。大量のデータを扱うシステムにおいて、リレーショナルデータベースと比べて、比較的簡単にスケールできるような仕組みを持っていることが一般的です。MongoDBは、ドキュメント指向データベースになります。
列指向データベース
列方向の操作に適したデータベースのことを、「列指向データベース」と呼びます。列方向の操作を頻繁に行う場合は、性能面で有利になります。
MongoDB概要
Webを支える技術として、AjaxやWebAPIは広く普及し、ほとんどのウェブサイトで使用されようになり、また、JavaScriptやJSON及びYAML等、多数の関連技術が脇を固めています。
昨今、WebAPIでデータ取得する場合は、JSONがデファクトスタンダードだと思います。
しかし、従来のRDBMSでは、階層的なJSONのスキーマ定義をすることは困難であり、WebAPIは仕様変更されることも多く、その度にスキーマを変更するのは大変です。
そういった背景より、MongoDBが誕生しました。
アーキテクチャ
- RDBMSのようにレコードをテーブルに格納するのではなく、「ドキュメント」と呼ばれる構造的データをJSONライクな形式で表現し、そのドキュメントの集合を「コレクション」として管理する
- コレクションはスキーマレスなドキュメントで格納され、任意のフィールドを好きなときに追加できる
- ドキュメントには複雑な階層構造を持たせることもでき、それらの構造に含まれるフィールドを指定したクエリやインデックス生成も簡単な指定によって行える
- KVSでは苦手なValueを検索の条件としたり、ソート・集計を実現できる
- 永続性を提供
MongoDBは、以下のようなシステムに適しています。
- Webサイトの操作データログの蓄積
- アドホックなフィールドを検索対象とするコンテンツ
- ソーシャルゲーム
でも、MongoDBは以下のことができません。
- NoSQLなので、SQLは使用できない。クエリはJavaScriptで行う
- RDBMSのように高度な結合操作(joinに相当する2つの関係から1つの関係を返す演算処理)
- トランザクション処理(※)
(※)MongoDB 4.0 でマルチドキュメントトランザクションがサポートされました。これにより、RDBMS likeのような一貫性のある処理を行うことができますが、以下の条件が必要です。
- レプリカセット構成あるいはシャーディング構成
- Feature Compatibility Version(FCV)4.0以降
- WiredTigerストレージエンジン(※)
(※)MongoDB2.6まではストレージエンジンがMMAPv1、MongoDB3.2からWiredTigerがデフォルト
従って、複数のトランザクションを必要としたクエリが必要になる場合、MongoDBは適していません。
端的にいうと、MongoDBは万全ではありません。
適材適所になるのでシステムに合わせてRDBMSと使い分けが必要です。
基本は、MongoDBは非正規化したドキュメント構造を扱っているので、どうしても分割されてしまうドキュメントに対しての排他処理を行いたい場合に、マルチドキュメントトランザクションを使用すればいいのではないかと考えます。
機能
- レプリカ
レプリケーションを構成することで障害耐性も高め、フェールオーバーが簡単にできる。RDBMSで言うLifeKeeperのような商用ソフトウェアは不要。 シャーディングで水平スケーリングが可能
スケールアウトが容易に可能になり、RDBMSよりも高速なレスポンスが得られることがある
(逆説的に言うと非正規形前提で設計しているので、結合演算が不要な場合はそのパフォーマンスを発揮する)GridFSと呼ばれるプロトコルを使用することで、大きなファイルをデータベースに格納・取得することができる
インメモリ機能により、高速なReadを実現するためにpageと言う単位でデータをメモリに保持している
(※)厳密に言うと、ファイルシステムに格納されているコレクションをmmapしている
(※)メモリ内に無いデータはディスクからロードすることになる、(Page Fault)
そのため、Page FaultはメモリからReadする場合と比較して時間がかかってしまう
その他
シェア
DB-Enginesによると、2019年2月の時点でOracle Database、MySQL、Microsoft SQL Server、PostgreSQL等の歴史あるRDBMSプロダクトに続き5位をキープしています。
導入コスト
- インストールのしやすさ
- 様々なプラットフォームに対応(Windows、Linux、MacOS等)
- 多くのプログラミング言語用ドライバの充実
- Javascriptライクに書けるので、フロントエンジニアでも親しみやすい
- レプリカの仕組みがRDBMSに比べて簡単
- シャーディングもRDBMDに比べて簡単(RDBMSの場合、アクセス負荷を考慮した設計は大変)
設計思想(MongoDBの開発元である10gen社CTO兼共同創業者Eliot Horowitzによる引用)
MongoDBは研究室の中で設計されたわけではありません。私たちは,大きなスケールの,高可用性を備えた,堅牢なシステムを構築した経験をもとにMongoDBを作りました。ゼロからはじめたわけではありません。何が壊れているのかを見つけ出し,それに取り組むという方法を取ってきました。
MongoDB導入
MongoDBは、CommunityとEnterpriseの 2つのエディションとしてリリースされています。コミュニティはMongoDBのオープンソースリリースです。エンタープライズは、追加の管理、認証、および監視機能を提供します。
本記事の環境は以下になります。
環境:CentOS Linux release 7.6.1810 (Core)
MongoDBのインストール(CentOS)
- /etc/yum.repos.d/mongodb-org-4.0.repoの作成
vi /etc/yum.repos.d/mongodb-org-4.0.repo
[mongodb-org-4.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc
- yumレポジトリの有効確認
yum repolist mongodb-org-4.0 -v
プラグイン「fastestmirror」を読み込んでいます
Config time: 0.006
Yum version: 3.4.3
Loading mirror speeds from cached hostfile
* base: ftp-srv2.kddilabs.jp
* extras: ftp-srv2.kddilabs.jp
* updates: ftp-srv2.kddilabs.jp
Setting up Package Sacks
pkgsack time: 0.004
リポジトリー ID : mongodb-org-4.0/7
リポジトリーの名前 : MongoDB Repository
リポジトリーの状態 : 有効
リポジトリーのリビジョン : 1545246847
リポジトリー更新日 : Thu Dec 20 04:14:08 2018
リポジトリー内パッケージ数 : 30
リポジトリー容量 : 458 M
リポジトリー基準 URL : https://repo.mongodb.org/yum/redhat/7/mongodb-org/4.0/x86_64/
リポジトリーの期限 : 21,600 秒 (最終: Wed Jan 30 01:33:13 2019)
Filter : read-only:present
Repo ファイル名: /etc/yum.repos.d/mongodb-org-4.0.repo
repolist: 30
mongodb-orgパッケージのインストール
yum install -y mongodb-org
mongodb-orgパッケージのインストール 確認
yum list installed | grep mongodb-org
mongodb-org.x86_64 4.0.5-1.el7 @mongodb-org-4.0
mongodb-org-mongos.x86_64 4.0.5-1.el7 @mongodb-org-4.0
mongodb-org-server.x86_64 4.0.5-1.el7 @mongodb-org-4.0
mongodb-org-shell.x86_64 4.0.5-1.el7 @mongodb-org-4.0
mongodb-org-tools.x86_64 4.0.5-1.el7 @mongodb-org-4.0
mongodbサービス起動
systemctl start mongod
mongodbサービス起動確認
systemctl status mongod
● mongod.service - MongoDB Database Server
Loaded: loaded (/usr/lib/systemd/system/mongod.service; enabled; vendor preset: disabled)
Active: active (running) since 水 2019-01-30 02:06:26 JST; 1s ago
Docs: https://docs.mongodb.org/manual
Process: 4222 ExecStart=/usr/bin/mongod $OPTIONS (code=exited, status=0/SUCCESS)
Process: 4220 ExecStartPre=/usr/bin/chmod 0755 /var/run/mongodb (code=exited, status=0/SUCCESS)
Process: 4218 ExecStartPre=/usr/bin/chown mongod:mongod /var/run/mongodb (code=exited, status=0/SUCCESS)
Process: 4217 ExecStartPre=/usr/bin/mkdir -p /var/run/mongodb (code=exited, status=0/SUCCESS)
Main PID: 4225 (mongod)
CGroup: /system.slice/mongod.service
└─4225 /usr/bin/mongod -f /etc/mongod.conf
1月 30 02:06:25 localhost.localdomain systemd[1]: Starting MongoDB Database Server...
1月 30 02:06:25 localhost.localdomain mongod[4222]: about to fork child process, wait....
1月 30 02:06:25 localhost.localdomain mongod[4222]: forked process: 4225
1月 30 02:06:26 localhost.localdomain systemd[1]: Started MongoDB Database Server.
Hint: Some lines were ellipsized, use -l to show in full.
設定
mongodのデータベースシステムの動作を制御する場合は、コマンドラインあるいは設定ファイルで制御します。本記事では、設定ファイルについて簡単に解説します。
mongodの設定ファイルは、YAMLフォーマットを使用して記述します。詳細は、Configuration File Optionsを参照。また、コンフィグオプションは、設定ファイルの方が優先されます。
- サンプル
systemLog:
destination: file
path: "/var/log/mongodb/mongod.log"
logAppend: true
storage:
journal:
enabled: true
processManagement:
fork: true
net:
bindIp: 127.0.0.1
port: 27017
setParameter:
enableLocalhostAuthBypass: false
...
mongoシェルでのデータベース操作
mongoシェルは、MongoDBのインタラクティブなJavaScriptのインタフェースです。mongoシェルを使用して、データを照会および更新したり、管理操作を実行したりできます。
データベース作成〜コレクションの作成
mongoシェル起動
mongo
データベースの作成
use testdb
switched to db testdb
- データベースの確認
show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
use <データベース名> 実行後、一覧表示を行っても作成したデータベースは表示されません。最低でも1件以上のデータ登録が必要です。コレクション作成後、以下のように表示されます。
admin 0.000GB
config 0.000GB
local 0.000GB
testdb 0.000GB
例として、testcollというコレクションを作成し、ドキュメントの挿入を行います。ドキュメントは、JSON形式で記述します。
- ドキュメントの挿入(コレクションの作成)
db.testcoll.insert( { "key1" : "value1", "key2" : "value2" } )
- ハッシュと配列の混ざったドキュメントの挿入
db.testcoll.insert( { "array" : [ "Windows", "Mac" , "Linux" ] } )
ドキュメントの参照
- ドキュメントの参照(コレクション全てのデータを取得)
db.testcoll.find()
{ "_id" : ObjectId("5c6198f6fb5e83ffaa3ba044"), "key1" : "value1", "key2" : "value2" }
{ "_id" : ObjectId("5c61991ffb5e83ffaa3ba045"), "array" : [ "Windows", "Mac", "Linux" ] }
"_id" : ObjectId("5c...")は、MongoDBが自動で付けます。RDBMSでいう主キーに該当します。
- ドキュメントの参照(最初の1つのドキュメントを取得)
db.testcoll.findOne()
{
"_id" : ObjectId("5c6198f6fb5e83ffaa3ba044"),
"key1" : "value1",
"key2" : "value2"
}
- ドキュメントの参照(ハッシュキーを引数に渡して値を取得)
db.testcoll.findOne()["key1"]
value1
- コレクションの確認
show collections
testcoll
Javascriptでデータベース操作
ドキュメントの挿入(forループでデータを挿入)
for (let i = 1; i <= 10; i++) db.testcoll2.insert( { x : 1 , y : i } )
検索結果に対するカーソル
var c = db.testcoll2.find()
while ( c.hasNext() ) printjson( c.next() )
{ "_id" : ObjectId("5c6199aefb5e83ffaa3ba046"), "x" : 1, "y" : 1 }
{ "_id" : ObjectId("5c6199aefb5e83ffaa3ba047"), "x" : 1, "y" : 2 }
{ "_id" : ObjectId("5c6199aefb5e83ffaa3ba048"), "x" : 1, "y" : 3 }
{ "_id" : ObjectId("5c6199aefb5e83ffaa3ba049"), "x" : 1, "y" : 4 }
{ "_id" : ObjectId("5c6199aefb5e83ffaa3ba04a"), "x" : 1, "y" : 5 }
{ "_id" : ObjectId("5c6199aefb5e83ffaa3ba04b"), "x" : 1, "y" : 6 }
{ "_id" : ObjectId("5c6199aefb5e83ffaa3ba04c"), "x" : 1, "y" : 7 }
{ "_id" : ObjectId("5c6199aefb5e83ffaa3ba04d"), "x" : 1, "y" : 8 }
{ "_id" : ObjectId("5c6199aefb5e83ffaa3ba04e"), "x" : 1, "y" : 9 }
{ "_id" : ObjectId("5c6199aefb5e83ffaa3ba04f"), "x" : 1, "y" : 10 }
- ドキュメントを変数に格納
doc=db.testcoll2.findOne()
- キー"key1"の値を表示
printjson(doc["x"])
1
MongoDBのCRUD操作の詳細は、MongoDB CRUD Operationsを参照。
データベースの終了
mongoシェルで接続時のサービス終了は、以下のコマンドを実行します。
use admin
switched to db admin
db.shutdownServer();
server should be down...
2019-02-12T00:53:59.058+0900 I NETWORK [js] trying reconnect to 127.0.0.1:27017 failed
2019-02-12T00:53:59.058+0900 I NETWORK [js] reconnect 127.0.0.1:27017 failed failed
quit();
mongodの起動失敗
mongodの起動に失敗する場合は、強制終了などをしてロックファイルが残っている場合があります。
● mongod.service - MongoDB Database Server
Loaded: loaded (/usr/lib/systemd/system/mongod.service; enabled; vendor preset: disabled)
Active: failed (Result: exit-code) since 月 2019-02-11 23:47:18 JST; 47min ago
Docs: https://docs.mongodb.org/manual
Process: 3190 ExecStart=/usr/bin/mongod $OPTIONS (code=exited, status=14)
Process: 3185 ExecStartPre=/usr/bin/chmod 0755 /var/run/mongodb (code=exited, status=0/SUCCESS)
Process: 3181 ExecStartPre=/usr/bin/chown mongod:mongod /var/run/mongodb (code=exited, status=0/SUCCESS)
Process: 3176 ExecStartPre=/usr/bin/mkdir -p /var/run/mongodb (code=exited, status=0/SUCCESS)
2月 11 23:47:06 localhost.localdomain systemd[1]: Starting MongoDB Database Server...
2月 11 23:47:10 localhost.localdomain mongod[3190]: about to fork child process, wait....
2月 11 23:47:10 localhost.localdomain mongod[3190]: forked process: 3461
2月 11 23:47:18 localhost.localdomain systemd[1]: mongod.service: control process exi...4
2月 11 23:47:18 localhost.localdomain systemd[1]: Failed to start MongoDB Database Se....
2月 11 23:47:18 localhost.localdomain systemd[1]: Unit mongod.service entered failed ....
2月 11 23:47:18 localhost.localdomain systemd[1]: mongod.service failed.
Hint: Some lines were ellipsized, use -l to show in full.
その場合は、以下のコマンドを実行し、ロックファイルを削除すると、正常に起動できます。
rm /var/lib/mongo/mongod.lock
rm /tmp/mongodb-27017.sock
あるいは、/var/log/mongodb/mongod.logを参照し、以下のような「715: /var/lib/mongo/WiredTiger.turtle: handle-open: open: Permission denied」のログが出力されるている場合は、/var/lib/mongoディレクトリの権限を見直してください。
2019-02-12T01:10:04.498+0900 E STORAGE [initandlisten] WiredTiger error (13) [1549901404:498011][3521:0x7f0ba3f22b80], wiredtiger_open: __posix_open_file, 715: /var/lib/mongo/WiredTiger.turtle: handle-open: open: Permission denied Raw: [1549901404:498011][3521:0x7f0ba3f22b80], wiredtiger_open: __posix_open_file, 715: /var/lib/mongo/WiredTiger.turtle: handle-open: open: Permission denied
MongoDBのバックアップ
MongoDBのバックアップ対象は、データそのもののバックアップと、コンフィグオプションのバックアップになります。
コンフィグオプションは、mongod起動シェルやコンフィグファイルなどのファイルをコピーすればよいでしょう。
なお、データのバックアップには一般的にフルバックアップと差分バックアップを組み合わせて使用しますが、MongoDBに差分バックアップの機能はありません。
MongoDBのバックアップ方法
MongoDBでフルバックアップを行うには,以下の2通りの方法があります。
- データファイルをコピーする方法
データベースを停止するか、ロックしておく必要がある - mongodumpを利用する方法
mongodumpデータベースの内容のバイナリエクスポートを作成するためのユーティリティ。mongodumpの場合、オンラインバックアップが可能
留意事項
インデックスはダンプされずにリストア時に再構築されるため,大きなインデックスがある場合にはリストアに時間がかかります。また、小規模なMongoDB展開をバックアップおよび復元するためのシンプルで効率的なツールですが、大規模システムのバックアップを取得するのには理想的ではありません。
mongodumpによるバックアップ
- バックアップ
mongodump
2019-02-12T01:28:20.371+0900 writing admin.system.version to
2019-02-12T01:28:20.372+0900 done dumping admin.system.version (1 document)
2019-02-12T01:28:20.372+0900 writing testdb.testcoll2 to
2019-02-12T01:28:20.372+0900 writing testdb.testcoll to
2019-02-12T01:28:20.379+0900 done dumping testdb.testcoll (2 documents)
2019-02-12T01:28:20.380+0900 done dumping testdb.testcoll2 (10 documents)
mongodumpコマンド実行後、カレントディレクトリにdumpディレクトリが作成されます。そのdumpディレクトリの中に、データベースのコレクション等データが退避されます。
[root@localhost tmp]# ll dump/
合計 0
drwxr-xr-x. 2 root root 69 2月 12 01:28 admin
drwxr-xr-x. 2 root root 110 2月 12 01:28 testdb
mongodumpによるリストア
試しに、リストア前に作成したデータを削除して、リストア後、データが復元されているかを確認してみましょう。
まずは、例としてtestcollとtestcoll2のコレクションをそれぞれ削除します。
- コレクションの削除
db.testcoll.drop();
db.testcoll2.drop();
コレクションは削除できましたが、データベースは削除できていないので、データベースも削除します。
- データベースの削除
db.dropDatabase();
{ "dropped" : "testdb", "ok" : 1 }
データベースも削除できたので、リストアします。
- リストア
mongorestore ./dump
2019-02-12T03:32:42.592+0900 preparing collections to restore from
2019-02-12T03:32:42.594+0900 reading metadata for testdb.testcoll2 from dump/testdb/testcoll2.metadata.json
2019-02-12T03:32:42.608+0900 restoring testdb.testcoll2 from dump/testdb/testcoll2.bson
2019-02-12T03:32:42.611+0900 reading metadata for testdb.testcoll from dump/testdb/testcoll.metadata.json
2019-02-12T03:32:42.611+0900 no indexes to restore
2019-02-12T03:32:42.611+0900 finished restoring testdb.testcoll2 (10 documents)
2019-02-12T03:32:42.624+0900 restoring testdb.testcoll from dump/testdb/testcoll.bson
2019-02-12T03:32:42.627+0900 no indexes to restore
2019-02-12T03:32:42.627+0900 finished restoring testdb.testcoll (2 documents)
2019-02-12T03:32:42.627+0900 done
リストア後、mongoシェルに接続して復元されていることを確認します。
show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
testdb 0.000GB
show collections
testcoll
testcoll2
db.testcoll.find()
{ "_id" : ObjectId("5c6198f6fb5e83ffaa3ba044"), "key1" : "value1", "key2" : "value2" }
{ "_id" : ObjectId("5c61991ffb5e83ffaa3ba045"), "array" : [ "Windows", "Mac", "Linux" ] }
データベース、コレクション、ドキュメントについて復元されていることが確認できました。
監視
mongodの監視に関するコマンドを以下に記載します。
- コレクションの処理時間順に表示
mongotop
2019-02-12T01:34:41.789+0900 connected to: 127.0.0.1
ns total read write 2019-02-12T01:34:42+09:00
admin.system.roles 0ms 0ms 0ms
admin.system.version 0ms 0ms 0ms
config.system.sessions 0ms 0ms 0ms
local.startup_log 0ms 0ms 0ms
local.system.replset 0ms 0ms 0ms
testdb.testcoll 0ms 0ms 0ms
testdb.testcoll2 0ms 0ms 0ms
- MongoDB全体の状態を表示
mongostat
time
*0 *0 *0 *0 0 2|0 0.0% 0.0% 0 1.06G 49.0M 0|0 1|0 158b 62.4k 1 Feb 12 01:35:25.188
*0 *0 *0 *0 0 1|0 0.0% 0.0% 0 1.06G 49.0M 0|0 1|0 157b 62.2k 1 Feb 12 01:35:26.188
*0 *0 *0 *0 0 1|0 0.0% 0.0% 0 1.06G 49.0M 0|0 1|0 157b 62.1k 1 Feb 12 01:35:27.190
*0 *0 *0 *0 0 2|0 0.0% 0.0% 0 1.06G 49.0M 0|0 1|0 158b 62.4k 1 Feb 12 01:35:28.187
*0 *0 *0 *0 0 1|0 0.0% 0.0% 0 1.06G 49.0M 0|0 1|0 157b 62.2k 1 Feb 12 01:35:29.187
*0 *0 *0 *0 0 1|0 0.0% 0.0% 0 1.06G 49.0M 0|0 1|0 157b 62.2k 1 Feb 12 01:35:30.188
*0 *0 *0 *0 0 2|0 0.0% 0.0% 0 1.06G 49.0M 0|0 1|0 158b 62.2k 1 Feb 12 01:35:31.187
- MongoDB全体の統計情報(serverStatus()メソッド)
db.serverStatus()
{
"host" : "localhost.localdomain",
"version" : "4.0.5",
"process" : "mongod",
"pid" : NumberLong(3718),
"uptime" : 5961,
"uptimeMillis" : NumberLong(5961613),
"uptimeEstimate" : NumberLong(5961),
"localTime" : ISODate("2019-02-15T18:04:20.956Z"),
"asserts" : {
"regular" : 0,
"warning" : 0,
"msg" : 0,
"user" : 2,
"rollovers" : 0
},
"connections" : {
"current" : 1,
"available" : 51199,
"totalCreated" : 4
...
ログ
バージョン3.0.0の新機能より、--logRotate reopenを付与すると、
典型的なLinux / Unixのログローテーションの動作に従ってログファイルが開かれます。
ここでは、MongoDBのログローション方法について記載します。
まずは、/etc/mongod.confファイルに「logRotate: reopen」の設定値を記述します。
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
logRotate: reopen
次に、/etc/logrotate.d/配下にmongod用のログローテーション用の設定ファイルを作成します。
vi /etc/logrotate.d/mongod
/var/log/mongodb/mongod.log {
daily
rotate 30
missingok
compress
delaycompress
notifempty
create 640 mongod mongod
sharedscripts
postrotate
/bin/kill -SIGUSR1 `cat /var/run/mongodb/mongod.pid 2>/dev/null` >/dev/null 2>&1
endscript
}
ログローテーションのテストは以下のコマンドを実行します。
logrotate -dv /etc/logrotate.d/mongod
reading config file /etc/logrotate.d/mongod
Allocating hash table for state file, size 15360 B
Handling 1 logs
rotating pattern: /var/log/mongodb/mongod.log after 1 days (30 rotations)
empty log files are not rotated, old logs are removed
considering log /var/log/mongodb/mongod.log
log does not need rotating (log has been already rotated)not running postrotate script, since no logs were rotated
エラーが出力されないことを確認したら、logrotateにより自動でログローテーションが行われます。
-rw-r-----. 1 mongod mongod 1385 2月 16 01:38 /var/log/mongodb/mongod.log
-rw-------. 1 mongod mongod 115166 2月 16 01:38 /var/log/mongodb/mongod.log.1
また、mongoシェル接続時に、以下のコマンドでも手動でログローテーションできます。
db.adminCommand( { logRotate:1 } )
{ "ok" : 1 }
ユーザ作成
認証機能を有効にして、データベースに対してユーザ毎のアクセス制御を行います。
まずは、mongoシェル接続時に、以下のコマンドを実行し、管理者用ユーザを作成します。
use admin
db.createUser(
{
user: "admin",
pwd: "password",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)
Successfully added user: {
"user" : "admin",
"roles" : [
{
"role" : "userAdminAnyDatabase",
"db" : "admin"
}
]
}
ユーザー情報は、adminデータベースに保存されています。また、admin データベースの system.users コレクションにユーザー情報が保持されています。
ユーザー管理が行えるロールは、userAdminとuserAdminAnyDatabase の2種類があり、userAdminは指定されたデータベースに対してのみユーザー管理が行える組み込みロールになります。userAdminAnyDatabaseは、adminデータベースに対してのみ指定できる特別な組み込みロールで、このロールが付与されたユーザーはすべてのデータベースに対するユーザー管理が行えます。
次に一般用ユーザを作成します。
use testdb
db.createUser(
{
user: "testuser",
pwd: "password",
roles: [ { role: "readWrite", db: "testdb" } ]
}
)
Successfully added user: {
"user" : "testuser",
"roles" : [
{
"role" : "readWrite",
"db" : "testdb"
}
]
}
ユーザが作成されたことを確認します。
use admin
db.system.users.find()
{ "_id" : "admin.admin", "user" : "admin", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "mBaj6lY+FmjRpDoXAq/9nA==", "storedKey" : "/zqpTgZEV2iUlFsXwybT7t2NeYI=", "serverKey" : "+m4wf2orLVRyntSJTLjbIsa23+Q=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "leY10lhgYGZHVm3FdcDqIKVig4ZSegW8lYBDzA==", "storedKey" : "gwSafO6sc4OqJTWJ2aJcYXQ4XnxdZFEYR4Bv4aGjyas=", "serverKey" : "n8D7GZboYIpkJf++35GXENDK8ubSWiksu23+OFNXcGE=" } }, "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }
{ "_id" : "admin.testuser", "user" : "testuser", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "EVUclTLqMCIn1jtYqNBjWQ==", "storedKey" : "HQ1HiqS4FTMuVSH4wYuFPYMHBfI=", "serverKey" : "kQZPAh6kNqRlqoglY3k7D1864n8=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "KjnGdFe2WrAb5xhXdoAL25okfrc00uU1xI7Oow==", "storedKey" : "ZRUhnJPJrQBdgq94qcrRFOglQ3SgO/o5By5mKMKHMIk=", "serverKey" : "2N9s8GJLT7Q9dVT4Q33r/QehPK9H+ThgwK4EwQTvCWE=" } }, "roles" : [ { "role" : "readWrite", "db" : "testdb" } ] }
ユーザ認証機能を有効にします。
vi /etc/mongod.conf
security:
authorization: enabled
サービス再起動を行い、設定反映後、mongoシェルに接続して以下のコマンドを実行し、認証機能が有効になっていることを確認します。
use admin
db.system.user.find()
Error: error: {
"ok" : 0,
"errmsg" : "command find requires authentication",
"code" : 13,
"codeName" : "Unauthorized"
}
認証機能が有効になっているため、エラーが出力されるので認証を行います。
db.auth("admin","password")
1
再度、コマンドを実行すると、ユーザ情報が確認できました。
db.system.users.find()
{ "_id" : "admin.admin", "user" : "admin", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "mBaj6lY+FmjRpDoXAq/9nA==", "storedKey" : "/zqpTgZEV2iUlFsXwybT7t2NeYI=", "serverKey" : "+m4wf2orLVRyntSJTLjbIsa23+Q=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "leY10lhgYGZHVm3FdcDqIKVig4ZSegW8lYBDzA==", "storedKey" : "gwSafO6sc4OqJTWJ2aJcYXQ4XnxdZFEYR4Bv4aGjyas=", "serverKey" : "n8D7GZboYIpkJf++35GXENDK8ubSWiksu23+OFNXcGE=" } }, "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }
{ "_id" : "admin.testuser", "user" : "testuser", "db" : "admin", "credentials" : { "SCRAM-SHA-1" : { "iterationCount" : 10000, "salt" : "EVUclTLqMCIn1jtYqNBjWQ==", "storedKey" : "HQ1HiqS4FTMuVSH4wYuFPYMHBfI=", "serverKey" : "kQZPAh6kNqRlqoglY3k7D1864n8=" }, "SCRAM-SHA-256" : { "iterationCount" : 15000, "salt" : "KjnGdFe2WrAb5xhXdoAL25okfrc00uU1xI7Oow==", "storedKey" : "ZRUhnJPJrQBdgq94qcrRFOglQ3SgO/o5By5mKMKHMIk=", "serverKey" : "2N9s8GJLT7Q9dVT4Q33r/QehPK9H+ThgwK4EwQTvCWE=" } }, "roles" : [ { "role" : "readWrite", "db" : "testdb" } ] }
勘所
MongoDBの設計時の勘所を以下に記載します。
- 性能
- シャーディングをしっかり組むこと
- ドキュメント肥大化によりドキュメントの再配置が起こらないように、ドキュメントに必要なフィールドをあらかじめ作っておく
- ジャーナルの書き込み回数を減らす
- オンメモリを考慮し、全データをアクセスするような処理は行わない
- 運用
- ハードウェア障害に備えて、バックアップファイルは別のサーバ上に退避させる
- ディスク使用率やメモリ使用率のしきい値監視
- クラウドの場合、DC被災時を考慮してレプリカセットを構築しておけば、DR切替が容易。
- セキュリティ
- デフォルトポートからの変更
- クエリログの出力
- データベースに対する外部からのアクセス制限及び認証
- ディスク暗号化あるいは、データベースレイヤーでの暗号化(性能とトレードオフ)
参考
- Welcome to the MongoDB Docs
- MongoDBの薄い本
- MongoDBを始めた頃に知っていたら、と思う14のこと
- Automating MongoDB Log Rotation
おわりに
NoSQL及びMongoDBの魅力は、SQLにないデータ構造の扱いやすさや、PoostgreSQL及びMySQLにはないモダンな設計に尽きると思います。ユースケースによって、性能やACID等、RDBMSと比較すると一長一短が出てくるので、引き続き見極めていきます。