Hateburo: kazeburo hatenablog

SRE / 運用系小姑 / Goを書くPerl Monger

libeatmydataを使ってpostfixを劇速にする [用法用量要確認]

libeatmydataというLD_PRELOADを使って、起動したプロセスのfsyncを無効化するライブラリがあったので試してみています。

libeatmydata - disable fsync and SAVE!

fsyncがないと何が嬉しいかというとクラウドのようなIOまわりの環境が弱いところで、安全性は若干犠牲になりますが、パフォーマンスを稼ぐことができるようになります。

まず perlでfsyncを発行してどうなるかstraceをつかって確認してみます。

libeatmydataなし

$ strace perl -MIO::Handle -e 'open(my $fh,">:unix","test.txt"); print $fh "test"; IO::Handle::sync($fh);'
open("test.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fstat(3, {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
write(3, "test", 4)                     = 4
fsync(3)                                = 0
close(3)  

libeatmydataあり

$ strace  eatmydata perl -MIO::Handle -e 'open(my $fh,">:unix","test.txt"); print $fh "test"; IO::Handle::sync($fh);'
open("test.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fstat(3, {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
write(3, "test", 4)                     = 4
close(3)   

IO::Handle::syncやってるはずなのに、fsyncが表示されていません。

postfixのパフォーマンス改善

某所でPostfixを経由して外部の配信サービスにメールを転送しているサーバがあり、このIO負荷が高いのが課題となってました。

f:id:kazeburo:20161111142853p:plain

一斉メール送信のタイミングでかなりIO-waitが上がっています。

postfixの構成

www.wakhok.ac.jp

がわかりやすい。

postfixはいくつかのプロセスに分かれて動作します。メールを受けるときは、smtpdのプロセスが送信者からデータを受け取り、cleanupというプロセスに渡し、cleanupプロセスが実際にdiskに書き込む流れになっています。このcleanupプロセスがメールをdiskに書き込む時にfsyncを行うので、ここだけlibeatmydataを入れ込めば良いはず。

そこで /usr/libexec/postfix に cleanup_nosync というファイルを用意

#!/bin/sh
exec /usr/bin/eatmydata /usr/libexec/postfix/cleanup $*

master.cfを変更する

cleanup   unix  n       -       n       -       0       cleanup_nosync #最後だけ変更

postfixをreloadすれば設定が反映されます。

効果の確認

以上の設定をいれたサーバにて、受け取ったメールをすべて捨てるサーバ宛に大量にメールを送信して確認しました。

まず libeatmydata 適用前

$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 2420292 249248 1677904    0    0     0    41    2    0  4  0 95  1  0
 1  0      0 2420284 249248 1677904    0    0     0     0 1264  325 23  2 74  0  0
 1  3      0 2387640 249248 1677904    0    0     0  1180 2660 3530 21  3 64 11  0
 0  0      0 2386628 249248 1677916    0    0     0  4356 5434 11669  9  4 77 10  0
 0  5      0 2385868 249248 1677956    0    0     0  3620 4632 10255 13  3 75  9  0
 0  0      0 2385844 249248 1678004    0    0     0  2792 4294 12083  4  4 88  4  0
 0  0      0 2385596 249248 1678052    0    0     0  3724 4772 13095  3  4 88  4  0
 0  0      0 2386200 249248 1678116    0    0     0  3408 4452 11660  4  4 86  6  0
 0  0      0 2387968 249248 1678136    0    0     0  2908 4327 10611  4  3 82 11  0
 0  0      0 2390704 249248 1678200    0    0     0  4724 5314 13459  4  5 86  6  0
 0  0      0 2388580 249248 1678240    0    0     0  5212 5520 13300  4  5 85  6  0
 3  1      0 2388208 249248 1678292    0    0     0  4716 5934 13486  4  5 86  6  0
 0  1      0 2387960 249248 1678344    0    0     0  4608 5947 13964  4  4 85  7  0
 0  1      0 2386720 249248 1678392    0    0     0  3164 4561 10527  3  4 81 11  0
 0  0      0 2386464 249248 1678424    0    0     0  4544 5555 13150  4  4 86  6  0
 0  0      0 2386092 249248 1678472    0    0     0  5052 6135 13801  4  4 85  7  0
 0  1      0 2387456 249248 1678524    0    0     0  5232 5905 13530  5  5 84  7  0
 0  0      0 2402424 249248 1678560    0    0     0   920 1203 2561  1  1 97  2  0
 0  0      0 2402424 249248 1678560    0    0     0     8  160  300  0  0 100  0  0

iowaitが5-10%前後でています。

libeatmydata 適用後

$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 2421320 249256 1678660    0    0     0     8  266  474  0  0 100  0  0
 0  0      0 2391500 249256 1678660    0    0     0     0 2248 4025  5  2 93  0  0
 0  0      0 2391212 249256 1678652    0    0     0     0 6185 13856  4  4 92  0  0
 0  0      0 2390824 249256 1678976    0    0     0     0 6106 13950  4  4 92  0  0
 0  0      0 2391552 249256 1678804    0    0     0     0 5932 13648  4  4 92  0  0
 0  0      0 2388644 249256 1678868    0    0     0   104 5901 13003  5  5 91  0  0
 0  0      0 2389644 249256 1678896    0    0     0     0 5552 13448  4  4 92  0  0
 4  0      0 2389280 249256 1678936    0    0     0     0 5912 13921  4  4 93  0  0
 5  0      0 2391024 249256 1679004    0    0     0     0 6185 13774  4  4 93  0  0
 1  0      0 2390528 249256 1679056    0    0     0     0 5848 13187  4  4 92  0  0
 0  0      0 2390404 249256 1679108    0    0     0   116 6250 12982  5  4 91  0  0
 0  0      0 2387496 249256 1679156    0    0     0    12 6977 13495  6  6 89  0  0
 0  0      0 2389112 249256 1679176    0    0     0     0 6074 14039  4  4 92  0  0
 0  0      0 2387616 249256 1679236    0    0     0     0 5966 13956  4  4 92  0  0
 0  0      0 2403196 249256 1679296    0    0     0     0 1412 2950  1  1 99  0  0
 0  0      0 2403444 249256 1679304    0    0     0   136  217  450  0  0 100  0  0

iowaitは常に 0。圧倒的な効果がでました。

データの安全性対策

念のため、1秒間隔でdiskへのsyncが行われるように設定しました。

$ sudo sysctl -w vm.dirty_writeback_centisecs=100

productionへの適用

f:id:kazeburo:20161111142950p:plain

IO-waitが消え、送信にかかる時間も短くなりました。やった!