読者です 読者をやめる 読者になる 読者になる

aspec7's garage

エンジニア生活の中で学んだことの備忘録

MongoDB 3.0 を試してみて分かったWiredTigerの威力

MongoDB

f:id:aspec7:20150329194752j:plain

MongoDB3.0!

2月にリリースされた3.0には、ストレージエンジンが選択できるようになり、新しいストレージエンジンとして WiredTiger が選べるようになっています。

従来のエンジンは「MMAPv1」として継続利用可能です。

ということで、旧バージョンと比較してみました。

新しいエンジンの魅力

WiredTigerで、以下のようなことが実現できるらしいとのことで、容量問題に直面していた自分には、80%圧縮は魅力的すぎます。

  • 書き込み性能7〜10倍UP!
  • ファイルサイズが最大80%圧縮!
  • 多重バージョン並行処理制御(MVCC)
  • マルチドキュメントトランザクション
  • ログ構造化マージツリー(LSMツリー)のサポート

「MongoDB」アップデート迫る--新搭載DBエンジン「WiredTiger」でどう変わる? http://japan.zdnet.com/article/35059956/

魅力的なアップグレードプラン

いくら魅力的でも、メジャーバージョンを上げるのはやっぱり不安。 レプリカセットで環境構築しているのもあり、余計に不安。 が、新エンジンと従来型エンジンは、レプリカセット内で共存可能!とのことなので、セカンダリ側だけアップグレードしてみて試せることで、一気に敷居が下がりました。

気をつけること

実際に試してみてわかったことです。

  • 2.6までで使用していたデータファイルはWiredTigerでは読み込めない
  • DBアカウントデータは2.6で、データ形式をアップデート(マニュアル)しておかないと、3.0では使えない(=ログインできない)
  • 削除処理などデータ更新時のロードアベレージやCPUはかなり高め

Ver.2.x との比較

Ver.2.4、2.6と比較してみました。 比較には以下のスクリプトを実行して計測しました。

$:.unshift File.dirname(__FILE__)
require 'benchmark'
require 'securerandom'
require 'date'
require 'mongo'
require 'logger'

logger = Logger.new(STDOUT)
logger.level = Logger::Severity::INFO
Mongo::Logger.logger = logger
client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'verup', :logger => logger)
coll = client[:test]

result = Benchmark.realtime do
  1000000.times do |n|
    coll.insert_one(
      {
        "id"   => n,
        "col1" => SecureRandom.hex(8),
        "col2" => SecureRandom.hex(8),
        "col3" => SecureRandom.hex(8),
        "col4" => SecureRandom.hex(8),
        "col5" => SecureRandom.hex(8),
        "time" => Time.now
      }
    )
  end
end
puts "Insert: %.2f sec" % result

p client.command(:dbstats => 1)

size = 0
data_path = "~/mongodb/data/"
Dir.glob("#{File.expand_path(data_path)}/**/*") { |f| size += File.stat(f).size }
puts "FILE_SIZE: #{size/1024/1024} MB"

row_count = 0
result = Benchmark.realtime do
  coll.find.each { |row| row_count += 1 }
end
puts "Read: %.2f sec" % result

result = Benchmark.realtime do
  coll.find.each { |row| coll.find(:_id => row[:_id]).replace_one(:col1 => SecureRandom.hex(8)) }
end
puts "Update: %.2f sec" % result

result = Benchmark.realtime do
  coll.find.each { |row| coll.find(:_id => row[:_id]).delete_one }
end
puts "Remove: %.2f sec" % result

上記スクリプトを、下記環境にて実行しています。 MongoDBhome brewでインストールしています。

項目 バージョン
OS MacOS X 10.10.2(14C1514)
Ruby 2.2.1p85
gems bson (3.0.0), mongo (2.0.1)

MongoDBは、以下のコマンドで起動しています。

# Dataディレクトリは以下のように作成しています。
mkdir -p ~/mongodb/data{24,26}/ ~/mongodb/{data30m,data30wtn,data30wts,data30wtz}/
# テストごとにdataディレクトリをリンクで作成しています。
ln -s ~/mongodb/[対象バージョンのデータィレクトリ]/ ~/mongodb/data  

# 2.4
mongod --port 27017 --dbpath ~/mongodb/data24/ --logpath ~/mongodb/log/24.log --pidfilepath ~/mongodb/data24/24.pid --fork
# 2.6
mongod --port 27017 --dbpath ~/mongodb/data26/ --logpath ~/mongodb/log/26.log --pidfilepath ~/mongodb/data26/26.pid --fork
# 3.0(mmapv1)
mongod --port 27017 --storageEngine mmapv1 --dbpath ~/mongodb/data30m/ --logpath ~/mongodb/log/30.log --pidfilepath ~/mongodb/data/30.pid --fork
# 3.0(wiredTiger:none)
mongod --port 27017 --storageEngine wiredTiger --wiredTigerCollectionBlockCompressor none --dbpath ~/mongodb/data30wtn/ --logpath ~/mongodb/log/30wtn.log --pidfilepath ~/mongodb/data/30wtn.pid --fork
# 3.0(wiredTiger:snappy)
mongod --port 27017 --storageEngine wiredTiger --wiredTigerCollectionBlockCompressor snappy --dbpath ~/mongodb/data30wts/ --logpath ~/mongodb/log/30wts.log --pidfilepath ~/mongodb/data/30wts.pid --fork
# 3.0(wiredTiger:zlib)
mongod --port 27017 --storageEngine wiredTiger --wiredTigerCollectionBlockCompressor zlib --dbpath ~/mongodb/data30wtz/ --logpath ~/mongodb/log/30wtz.log --pidfilepath ~/mongodb/data/30wtz.pid --fork

処理時間

2.4以降、バージョン上がるたびにパフォーマンスが上がっています。 3.0.1では、wiredTiger&snappyの組み合わせが全体的に速いです。

Ver Insert Read Update Delete
2.4.12 548.64 sec 34.57 sec 576.41 sec 534.16 sec
2.6.8 510.82 sec 37.01 sec 537.28 sec 462.40 sec
3.0.1(mmapv1) 472.59 sec 33.61 sec 488.12 sec 461.44 sec
3.0.1(wiredTiger:none) 479.26 sec 38.82 sec 487.69 sec 424.85 sec
3.0.1(wiredTiger:snappy) 458.78 sec 34.59 sec 490.69 sec 426.52 sec
3.0.1(wiredTiger:zlib) 480.54 sec 35.43 sec 491.32 sec 443.02 sec

データサイズ

続いて、データサイズ比較。 ストレージエンジンを変えることで、3.02.4の差は大きく変わっているのがわかります。 2.4から2.6にアップグレードするだけでも、ファイルサイズが半減しています。 zlibオプションが、もっとも圧縮率が良いです。 パフォーマンスよりも少しでも容量節約したい場合には候補として有力ですね。

Ver avgObjSize dataSize storageSize indexSize fileSize
2.4.12 191.99 B 183.10 MB 249.96 MB 30.95 MB 1056 MB
2.6.8 239.99 B 228.88 MB 320.35 MB 30.95 MB 544 MB
3.0.1(mmapv1) 239.99 B 228.88 MB 320.35 MB 30.95 MB 544 MB
3.0.1(wiredTiger:none) 179.00 B 170.70 MB 171.32 MB 8.21 MB 372 MB
3.0.1(wiredTiger:snappy) 179.00 B 170.70 MB 110.79 MB 8.39 MB 304 MB
3.0.1(wiredTiger:zlib) 179.00 B 170.70 MB 65.81 MB 8.25 MB 265 MB

総評

ということで、旧バージョンと簡単な比較しただけですが、かなり魅力的です。 単純計算で3分の1のファイルサイズに落ちるだけでなく、パフォーマンスも上がります。 一方で、データとしては出していませんが、プログラムと絡ませた時にLoadAverageが旧バージョンよりも大きく上がっているのも確認できました。

レプリカセットの場合は、セカンダリ側をバージョンあげて、データファイルを消去して再レプリケーションしてあげれば新エンジンでもスムーズに移行できます。

全体的に大きくパワーアップした感じなので、早めにバージョンあげて、検証して新バージョンに合わせたチューニングを施して移行してしまうのが良いですね。