ベアメタル環境とDockerコンテナ環境の性能比較

2015年3月27日(金)
佐藤 司森元 敏雄

コンテナ環境とベアメタル環境の差異

前回は、Docker向け軽量Linux OSの主要3製品の比較を行った。Dockerを利用した環境の構築は、構築済みコンテナなどの利用により、比較的容易に行える。これは便利ではあるが、一方でコンテナ型仮想化環境には既存のベアメタル環境との差異がある。

コンテナ型の仮想化は軽量でリソース消費量が少ないが、コンテナ型仮想化環境にも管理レイヤは存在し、その上でコンテナが稼働している以上、どうしてもベアメタル環境に比べて性能劣化が発生することが予測される(図1)。

Dockerコンテナ管理レイヤ

図1:Dockerのコンテナ管理レイヤ

今回は、同一スペックおよび同一プロダクトを利用し、構築したDocker環境とベアメタル環境上で負荷テストを実施することで、両者の性能差を比較検証する。処理性能やリソース負荷状況などの観点で比較し、その差異を表やグラフにまとめているので、ご一読いただきたい。

まずは環境をご紹介する。今回は、図2のようなテスト環境を用意した。

Dockerコンテナとベアメタルを比較するテスト環境

図2:Dockerコンテナとベアメタルを比較するテスト環境

検証環境

ベアメタル環境、Docker環境の検証の性能を同一にするため、1台の物理サーバを使用し、起動(ブート)するHDDを選択することで両環境を切り替えるようにした。

単一のサーバを用いて、起動するHDDの選択で環境を切り替える

図3:単一のサーバを用いて、起動するHDDの選択で環境を切り替える

用意したサーバのスペックを、表1に示した。

表1:検証に用いた物理サーバのスペック

CPUIntel(R) Core(TM) i7 870 @ 2.93GHz
Memory4GB
Swap8GB
HDD1Western Digital 1TB (SATA3 7200rpm)
HDD2Western Digital 1TB (SATA3 7200rpm)
NIC1インターネットへ接続可能なネットワーク
NIC2負荷発生端末(JMeter)とのみ接続可能なクローズドなネットワーク

ベアメタル環境、Docker環境の構成も、合わせて表2に示した。

表2:ベアメタル、Docker環境のソフトウェア構成

環境ベアメタル環境Docker環境
OSCentOS 6.6(64bit)CentOS 6.6(64bit)
Docker-Docker 1.4.1
アプリケーションRedmine 3.0.0Redmine 3.0.0(コンテナで配置)
RDBMySQL 5.5.41MySQL 5.5.41(コンテナで配置)

この環境に負荷発生端末上のJMeterから検証環境上のRedmineへのアクセス負荷を発生させ、処理性能と負荷状況を測定した。

テストシナリオ

今回は以下の条件で負荷テストを実施した。

JMeter上から実行したオペレーションは以下となる。

1.参照オペレーション

  1. Redmineのログイン画面へアクセス
  2. ユーザ名とパスワードを用いてRedmineにログイン

本オペレーションでは、原則、DBやディスクには参照の処理が行われる。CPU、ネットワーク、ディスクに平均的に負荷を発生させることを目的としている。

2.更新オペレーション

  1. Redmineのプロジェクトに対して新しいチケットを1件作成
  2. 表題と内容を記載し登録

本オペレーションでは、チケットの登録が行われるため、ディスクの更新が発生する。データ量は小さいがDB、ディスクへの負荷を発生させることを目的としている。

JMeter上から発生させる負荷量は以下となる。

  1. 低負荷
    参照、更新のオペレーションを100件/60秒の間隔で実行する
    テスト時間は60秒間で行い、それを複数回繰り返して平均を取得する
  2. 高負荷
    参照、更新のオペレーションを1000件/60秒の間隔で実行する
    テスト時間は60秒間で行い、それを複数回繰り返して平均を取得する

検証

上記の負荷テストを実施し、測定された結果は以下のとおりだ。

低負荷時の測定結果

まず低負荷時の状態として、参照、更新のオペレーションを100件/60秒の間隔で実行した結果は以下となる。

表3:ベアメタル環境 – 低負荷時

作業1分間のオペレーション平均
(ミリ秒)
中央値
(ミリ秒)
90%Line
(ミリ秒)
最小値
(ミリ秒)
最大値
(ミリ秒)
Error%スループットKB/sec
アクセス1001010118140.00%1.7/sec7.2
ログイン実行1009391107672000.00%1.7/sec13.7
Projectへ遷移10018182016280.00%1.7/sec8.5
チケット作成10020192317320.00%1.7/sec9.1
平均10035.2534.540.252768.50.00%1.7/sec9.63

表4:Docker環境 – 低負荷時

作業1分間のオペレーション平均
(ミリ秒)
中央値
(ミリ秒)
90%Line
(ミリ秒)
Min
(ミリ秒)
Max
(ミリ秒)
Error%ThroughputKB/sec
アクセス10011111210200.00%1.7/sec7.0
ログイン実行1009792110761990.00%1.7/sec13.1
Projectへ遷移10022222418340.00%1.7/sec8.4
チケット作成10018192018280.00%1.7/sec9.0
平均100373641.530.570.250.00%1.7/sec9.38

表3、表4で特に注目すべきは「90%Line」と「KB/sec」の箇所だ。「90%Line」は、発行したリクエストの90%が、何ミリ秒で応答するかを示す値であり、実際にユーザが体験するレスポンスタイムに最も近い。また「KB/sec」は、サーバからJMeter端末への通信速度を表しており、1秒あたりの転送量が何KB(キロバイト)だったのかを表している。両者の結果をグラフ化したものが、図4、5だ。

低負荷時の「90%Line」を比較(低いほうが高性能)

図4:低負荷時の「90%Line」を比較(低いほうが高性能)

低負荷時のデータ転送量を比較(高いほうが高性能)

図5:低負荷時のデータ転送量を比較(高いほうが高性能)

2つのグラフから明らかなように、ベアメタル環境、Docker環境の差異はそれほど大きくなく、軽い処理であれば、性能面での影響は少ないと考えられる。

高負荷時の測定結果

続いて、高負荷時の状態として参照、更新のオペレーションを1000件/60秒の間隔で実行した結果を、表5、表6に示す。

表5:ベアメタル環境 – 高負荷時

作業1分間のオペレーション平均
(ミリ秒)
中央値
(ミリ秒)
90%Line
(ミリ秒)
最小値
(ミリ秒)
最大値
(ミリ秒)
Error%スループットKB/sec
アクセス100015102082930.00%16.6/sec70.9
ログイン実行100011994191756750.00%16.6/sec135.2
Projectへ遷移1000281944154040.00%16.5/sec83.5
チケット作成1000292041174380.00%16.5/sec89.4
平均100047.7535.757428.75452.50.00%16.55/sec94.75

表6:Docker環境 – 高負荷時

作業1分間のオペレーション平均
(ミリ秒)
中央値
(ミリ秒)
90%Line
(ミリ秒)
最小値
(ミリ秒)
最大値
(ミリ秒)
Error%スループットKB/sec
アクセス10005807409991131626.40%16.4/sec51.6
ログイン実行10001193156219880236631.50%16.1/sec90.4
Projectへ遷移10001065145018831229531.60%16.2/sec56.8
チケット作成10001031145018751229834.40%16.2/sec59.4
平均1000967.251300.51686.250.752068.7530.98%16.23/sec64.55

高負荷状態では、大きく差が生じる結果となった。レスポンスタイムの指標である「90%Line」で見ると、Docker環境はベアメタル環境と比較してなんと20倍以上の劣化が起きていた。

さらにレスポンスのタイムアウトの発生率(Error%)も、ベアメタル環境が0%であったのに対し、Docker環境は平均30%とかなり高い値を示した。これは、実際に運用していた場合、60秒間にアクセスした1000人のうち300人にアクセスエラーを返しているということになる。

1000件/60秒というアクセス頻度は、通常のWebサーバでCore i7程度のCPU性能があればそれほど高負荷とは言えない状況である。この結果からは、Docker環境を本番環境として利用することは厳しく、何らかの対策が必要だと考えられる。

高負荷時のデータも同様にグラフにしたので、確認していただきたい。

高負荷時の「90%Line」を比較(低いほうが高性能)

図6:高負荷時の「90%Line」を比較(低いほうが高性能)

高負荷時のデータ転送量を比較(高いほうが高性能)

図7:高負荷時のデータ転送量を比較(高いほうが高性能)

低負荷の状態では、ベアメタルと大きな性能差は発生しないDockerコンテナ環境であるが、高負荷状態となると、著しく性能劣化することが見て取れる。

Diskの負荷を検証する

ここまではJMeterを利用して主にレスポンスやネットワークについて見てきたが、Diskの状況についても測定を行っている。今回は、測定にMuninを用意してDisk負荷状況を監視した。

ベアメタル環境でのDisk負荷状況

MuninによるDisk負荷の監視(ベアメタル環境)

図8:MuninによるDisk負荷の監視(ベアメタル環境)

図8の青枠で囲まれている部分が低負荷のテストシナリオを、赤枠で囲まれているところが高負荷のテストシナリオを実施した部分だ。

どちらも負荷をかけた時にはRead I/O Wait timeが跳ね上がっている、筆者はこのテストを実施するまではRead I/O Wait timeが性能のボトルネックになり得ると予想していたが、実際にはベアメタル環境であれば1000アクセス+1000書き込み/60秒程度までなら、そこまでの劣化は発生しないようだ。

Docker環境でのDisk負荷状況

MuninによるDisk負荷の監視(Docker環境)

図9:MuninによるDisk負荷の監視(Docker環境)

図9はDocker環境での結果で、同じく青枠が低負荷、赤枠が高負荷のテストシナリオを実施した結果だ。図8とは縦軸のスケールが異なる点に注意しよう。

測定結果のグラフを見ると、ベアメタルより負荷が少ない状況となっている。その一方でHTTPレスポンスはリクエストの30%がエラーとなっており、「422:Unprocessable Entity」や「502:Bad Gateway」などが発生している。

今回のDiskの負荷状況の測定だが、Dockerを稼働させたベースのCentOS上で測定している。そのため、Disk I/Oの負荷は標準設定時に利用されるDockerコンテナのファイルシステム(CentOS6.6はdevice-mapper)部分がボトルネックとなるであろうと予想したが、実際にはベースOS側には波及することがなかったため図9のように負荷が少なかったと推察される。

まとめ

今回の検証結果から、低負荷時やピーク負荷が予想できる場合であれば、Dockerコンテナを利用したシステムでもベアメタル環境と遜色ないパフォーマンスが発揮されることがわかった。しかし高負荷時になると、やはりベアメタル環境の安定性に分がある。とはいえ、Docker環境でも対策がないわけではない。挙げられる対策といえば、IO負荷が高いファイル等はコンテナの外のファイルを使う手法や、負荷分散のために分散システムとする手法、障害対応力を上げるためのコンテナのクラスタリングなど、できることはたくさんある。また、このようなDockerの弱点をカバーするために、各社こぞってDockerのツールを作成、改善しているところだ。

次回以降では、今回の性能劣化の原因と推察されるDockerのファイルシステムについて検証を行い、原因の分析を行うとともに、性能改善の対策と効果についても検証し、理解を深めていきたい。

追記

CentOS 6.6環境でのDockerがデフォルトで利用するファイルシステムを「AUFS」と記載しておりましたが「device-mapper」の誤りでした。ご指摘くださった皆様ありがとうございました。お詫びして訂正いたします。

次々回の連載では、CentOS 6系でDockerコンテナを標準で利用されるdevice-mapperで発生する問題点とその対策について公開を予定しております。

<編集部より>記事内容に誤りがあったため修正しました。(2015.03.30)

株式会社アーベルソフト

インフラ基盤の設計・構築・運用までの全ての工程を担当。最近は、OSS製品を活用したインフラ基盤の提供を行っている。利用するOSS製品の調査・研究も行っており、現在は、DockerとTerraformに注目している。
>株式会社アーベルソフト

TIS株式会社

R&D部門である戦略技術センター所属。
金融系の大規模システム開発やプライベートクラウド開発環境の構築・運用の経験を生かし、OSS製品を中心としたの技術調査・検証を担当。
> TIS株式会社

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています