Will using a compressed filesystem over an encrypted volume improve performance

btrfscompressiondm-cryptencryptionfilesystems

Encryption/decryption is often the main bottleneck when accessing an encrypted volume. Would using a filesystem with a fast transparent compression (such as BTRFS + LZO) help? The idea is that there would be less data to encrypt, and if the compression is significantly faster than the encryption algorithm, the overall processing time would be less.

Update: As Mat pointed out, it depends on the compressibility of the actual data. Of course, I assume that its compressible, like source code or documents. Of course it has no meaning using it for media files (but I guess it won't hurt too much, as BTRFS tries to detect incompressible files.)

Since testing this idea is a very time consuming process, I'm asking if somebody has already some experience with this. I tested just a very simple setup, and it seems to show a difference:

$ touch BIG_EMPTY
$ chattr +c BIG_EMPTY
$ sync ; time ( dd if=/dev/zero of=BIG_EMPTY bs=$(( 1024*1024 )) count=1024 ; sync )
...
real    0m26.748s
user    0m0.008s
sys 0m2.632s

$ touch BIG_EMPTY-n
$ sync ; time ( dd if=/dev/zero of=BIG_EMPTY-n bs=$(( 1024*1024 )) count=1024 ; sync )
...
real    1m31.882s
user    0m0.004s
sys 0m2.916s

Best Answer

I did a small benchmark. It only tests writes though.

Test data is a Linux kernel source tree (linux-3.8), already unpacked into memory (/dev/shm/ tmpfs), so there should be as little influence as possible from the data source. I used compressible data for this test since compression with non-compressible files is nonsense regardless of encryption.

Using btrfs filesystem on a 4GiB LVM volume, on LUKS [aes, xts-plain, sha256], on RAID-5 over 3 disks with 64kb chunksize. CPU is a Intel E8400 2x3Ghz without AES-NI. Kernel is 3.8.2 x86_64.

The script:

#!/bin/bash

PARTITION="/dev/lvm/btrfs"
MOUNTPOINT="/mnt/btrfs"

umount "$MOUNTPOINT" >& /dev/null

for method in no lzo zlib
do
    for iter in {1..3}
    do
        echo Prepare compress="$method", iter "$iter"
        mkfs.btrfs "$PARTITION" >& /dev/null
        mount -o compress="$method",compress-force="$method" "$PARTITION" "$MOUNTPOINT"
        sync
        time (cp -a /dev/shm/linux-3.8 "$MOUNTPOINT"/linux-3.8 ; umount "$MOUNTPOINT")
        echo Done compress="$method", iter "$iter"
    done
done

So in each iteration, it makes a fresh filesystem, and measures the time it takes to copy the linux kernel source from memory and umount. So it's a pure write-test, zero reads.

The results:

Prepare compress=no, iter 1

real 0m12.790s
user 0m0.127s
sys 0m2.033s
Done compress=no, iter 1
Prepare compress=no, iter 2

real 0m15.314s
user 0m0.132s
sys 0m2.027s
Done compress=no, iter 2
Prepare compress=no, iter 3

real 0m14.764s
user 0m0.130s
sys 0m2.039s
Done compress=no, iter 3
Prepare compress=lzo, iter 1

real 0m11.611s
user 0m0.146s
sys 0m1.890s
Done compress=lzo, iter 1
Prepare compress=lzo, iter 2

real 0m11.764s
user 0m0.127s
sys 0m1.928s
Done compress=lzo, iter 2
Prepare compress=lzo, iter 3

real 0m12.065s
user 0m0.132s
sys 0m1.897s
Done compress=lzo, iter 3
Prepare compress=zlib, iter 1

real 0m16.492s
user 0m0.116s
sys 0m1.886s
Done compress=zlib, iter 1
Prepare compress=zlib, iter 2

real 0m16.937s
user 0m0.144s
sys 0m1.871s
Done compress=zlib, iter 2
Prepare compress=zlib, iter 3

real 0m15.954s
user 0m0.124s
sys 0m1.889s
Done compress=zlib, iter 3

With zlib it's a lot slower, with lzo a bit faster, and in general, not worth the bother (difference is too small for my taste, considering I used easy-to-compress data for this test).

I'd make a read test also but it's more complicated as you have to deal with caching.

Related Question