はじめに
Necoプロジェクトのsatです。
cybozu.comの次世代インフラ基盤Necoにおいてはストレージデバイスが紛失や盗難にあったときでもお客様のデータの漏洩を防ぐために、ストレージデバイスの暗号化をしています*1。ストレージデバイスの暗号化にはLinuxのdm-cryptを使っています。本記事では、この機能を使うにあたって、どの暗号スイートを使うかを処理速度という観点で決めた際の評価結果、それをもとにした判断基準、および評価の流れについて説明します。
dm-cryptに使える暗号スイートはたくさんありますが、まずは以下の要件を満たすものを選びました。
- 世間でよく使われている
- Necoで使用するにあたって十分な強度を持つ
- 暗号化/復号においてCPUに専用命令がある
この観点に絞ったところ、下記4つが候補に残りました。
- AES-128-CBC-ESSIV:SHA256
- AES-256-CBC-ESSIV:SHA256
- AES-128-XTS-PLAIN64
- AES-256-XTS-PLAIN64
ここから上記4つの性能比較によって、Necoにおいてどの暗号スイートを使うかを決めました。
ここでXTSについて一点補足しておきます。XTSには一度に暗号化するデータ長が長くなると問題になるケースがあります。
The length of the data unit for an instance of an implementation of XTSAES SHALL NOT exceed 220 blocks
しかしdm-cryptにおいては一度に暗号化するデータ長が220を超えることはないため、この問題はありません。
判断基準
前節において述べた4つの暗号スイートからどれを選ぶかについて、おおまかな判断基準を次のように定めました。
- CBC-ESSIV:SHA256とXTS-PLAIN64という2つのモードのうち高速なものを選ぶ
- 2つの鍵長128bitと256bitについては前者のほうが明らかに高速であれば前者を、それ以外はより強度が高い後者を選ぶ
測定環境
- サーバ: Dell EMC Power Edge R640
- CPU: Xeon Gold 5120 (2.2GHz, 14コア, 19MB キャッシュ, TDP 105W) * 2
- メモリ: 512 GB
- ストレージデバイス: Intel SSD DC P4500 4TB
- OS: Core OS Container Linux 1967.6.0
- カーネル: 4.14.96-coreos-r1
- ファイルシステム: ext4
- ベンチマークプログラム: fio 3.7
なぜこの環境にしたのかについては後述します。
測定条件
以下の総当たりです。
- 暗号化方式: AES-128-CBC-ESSIV:SHA256, AES-256-CBC-ESSIV:SHA256, AES-128-XTS-PLAIN64, AES-256-XTS-PLAIN64
- I/Oサイズ: 4k, 128k
- I/Oパターン: seqread, seqwrite, randread, randwrite
- 並列数: 1, 2, 4, 8, 16, 32, 64, 128
なぜこれらの組み合わせにしたのかについては後述します。
測定プログラム
# echo 0 >/sys/block/nvme1n1/read_ahead_kb # ブロックデバイス層によるデータの先読みを防ぐ # cryptsetup --cipher=<暗号スイート> \ --key-size=<キー長(XTS-PLAIN64の場合はキー長が128なら256,256ならば512を指定する必要がある。詳細については割愛)> \ --key-file=key open --type plain <device(/dev/nvme1n1 or /dev/ram0> enc # mkfs.ext4 crypt /dev/mapper/enc # mount /dev/mapper/enc /data # fio -direct=1 -readwrite=<I/Oパターン> -group_reporting \ -filename=/data/testfile -size=20G -runtime=60 \ -bs=<I/Oサイズ> -numjobs=<並列度> -name=file1 # echo 3 > /proc/sys/vm/drop_caches
結論
AES-256-XTS-PLAIN64を採用することに決めました。理由はXTS-PLAIN64のほうがCBC-ESSIV:SHA256よりも顕著に高速であり、かつ、鍵長の差による性能差が顕著ではなかったためです。
細かい評価基準については後述します。
評価の流れ
ここからは前述の結論に至るまでの評価の流れを記載します。
何を測ればいいのか
性能測定は目的を定めずに既存のベンチマークテストを適当に流すだけでは意味がありません。最も望ましいのは実際のワークロードを流してみて、そのときの性能を見ることです。しかし、現在のところNecoは開発中なので、実際のワークロードはわかりません。今回は次のような基礎的な性能データをとることにしました。
- sequential read
- sequential write
- random read
- random write
性能と言っても色々ありますが、ここではIOPSとbandwidthを測定することにしました。
測定環境は、すでに手元にあるNecoにおいて使う予定のサーバ、およびストレージデバイスとしました。
ストレージデバイスはNVMe SSDとHDDの二種類があります。後者については暗号化/復号処理の速度に対してストレージデバイスそのものの処理速度が遅すぎるため、データをとってもさほど意味はない、もし仮に採取するとしても今やらなくてもいい、という判断でデータ採取をしませんでした。ストレージデバイスそのものの処理速度に依存しない、生の暗号化/復号処理にかかる時間も採取したかったので、メモリに作成するブロックデバイスであるbrd(デバイス名は/dev/ram*)上でも性能測定をすることにしました。
NVMe SSDないしbrdという2つのブロックデバイス上のデータはdm-cryptを用いて暗号化しました。そのときに使った暗号スイートは前述の4つです。
性能測定対象のファイルシステムはNecoで使用予定のext4としました。
I/Oサイズについては以下の2パターンとしました。
- 4KB: ストレージデバイスをローカルストレージとして使う場合を想定。ファイルシステムから見るとこれ未満のサイズのI/Oはあまり出ないのでこの値を採用した
- 128KB: ストレージデバイスをCephのブロックデバイスの一部として使う場合を想定。Cephのブロックデバイスでは通常4MB単位でI/Oが出るが、今回使用するデバイスにおける一回のI/Oあたりの最大データ量が128KB*2なのでこの値を採用した
I/Oは複数のスレッドから同時に発生することがある、むしろそのほうが普通なので、並列にI/Oが出るパターンも測定しました。マシンのコア数が28だったので、その4倍程度の最大128並列I/Oまでのデータをとることにしました。
ベンチマークプログラムには上記のような測定をするのに便利なfioを使いました。
測定結果と考察
本節では性能データの測定結果をグラフ化するとともに、暗号スイートによってどのような違いが出るのかを考察しました。グラフが大量にあるので、細かいデータに興味の無い人は考察だけ見てください。
brd
まずはストレージI/Oを除いた暗号スイートの速度差がそのまま性能差にあらわれるbrdについてのデータです。
測定結果
- 4k-seqread
- 4k-seqwrite
- 4k-randread
- 4k-randwrite
- 128k-seqread
- 128k-seqwrite
- 128k-randread
- 128k-randwrite
考察
- 暗号スイート同士の差はある。読み出し(復号)よりも書き込み(暗号化)のほうが顕著
- 書き込みについては暗号スイート間の速度は降順に並べると次のようになる
AES-128-XTS-PLAIN64 > AES-256-XTS-PLAIN64 > AES-128-CBC-ESSIV:SHA256 > AES-256-CBC-ESSIV:SHA256
- 読み出しについてはおおよそ次のようになる。
AES-128-CBC-ESSIV:SHA256, AES-256-CBC-ESSIV:SHA256 > AES-128-XTS-PLAIN64 > AES-256-XTS-PLAIN64
この理由には次のようなことが考えられます。
- CBCモードは暗号化が並列化できないものの、復号は並列化可能
- XTSモードは暗号化/復号共に並列化可能
- XTSモードが復号においてCBCモードより遅いのは、XTSモードは2個のAESと特別な演算を行うから
- XTSモードは暗号化においては並列化・専用命令により、現代のCPUにおいてはCBCモードよりも有利だから
NVMe SSD
測定結果
- 4k-seqread
- 4k-seqwrite
- 4k-randread
- 4k-randwrite
- 128k-seqread
- 128k-seqwrite
- 128k-randread
- 128k-randwrite
考察
- 暗号スイートの速度を降順に並べるとおおよそ次の通りになる
AES-128-XTS-PLAIN64 > AES-256-XTS-PLAIN64 > AES-128-CBC-ESSIV:SHA256, AES-256-CBC-ESSIV:SHA256
- 読み出しについては暗号スイートによる差はせいぜい数%程度
- 書き込みは読み出しよりも暗号スイートによる差が大きい傾向にある。4kのほうが128kよりも差が大きい。前者は数%程度だが、後者は数十%ほど。
その他気になったところは次の通りです。
- 128k-seqread, 128k-randreadが高並列度においてIOPSが横ばいになっている理由はSSDのIOPSの限界と考えられる
- 4k-seqwrite, 4k-randwriteが低並列度からIOPSが横ばいになっている理由はSSDのIOPSの限界と考えられる
- 128k-seqwrite, 128k-randwriteにおいてIOPSが横ばいになっている理由はSSDのbandwidthの限界と考えられる
最終判断
前節における考察をもとに、次の理由からAES-256-XTS-PLAIN64を採用することにしました。
- XTSモードのほうが性能的には有利。並列読み出しにおいてはCBCモードのほうが高速であるが、それ以外はおおよそXTSモードのほうが高速。前者についてはNVMe SSDにおいて全体の性能への寄与が小さい
- XTSモードの鍵長については全体的に128bitのほうが高性能だが、ほとんどの場合は数%以内の差におさまる。特定のケースでは大きな差が出ることもあるが、その場合も20%程度におさまる
おわりに
いかがでしたでしょうか。本記事では4つの暗号スイートを使ったストレージデバイスの暗号化の性能差、および、暗号スイートに依存しない一般的な性能測定の流れの一例を書き綴ってみました。これらが読者のみなさまの参考になれば幸いです。
Necoプロジェクトでは一緒に働いてくれるかたを絶賛募集中です。興味があればご応募願います。