2014年1月20日月曜日

Linux kernelのTCP_TIMEWAIT_LEN を修正して、TIME_WAITを減らす


大量トラフィックを捌くサーバにありがちなのですが、
# netstat | grep tcp | wc -l
の結果が60000 とかになっていると、ポートが枯渇してTCPコネクションが詰まっている状態です。
そこで、TIME_WAIT となったセッションを早く終了させ、ポートの空きを作って、ポートの枯渇状態を解決します。
Linux kernelのTCP_TIMEWAIT_LENを60 -> 5にします。

環境は、CentOS6.5です。

rpmのビルドに必要なモジュールのインストール
# yum -y install rpm-build.x86_64 redhat-rpm-config.noarch patchutils.x86_64 elfutils-libelf-devel.x86_64 binutils-devel.x86_64 hmaccalc.x86_64 rng-tools.x86_64
# yum -y install redhat-rpm-config patchutils xmlto asciidoc binutils-devel newt-devel python-devel perl-ExtUtils-Embed bison flex hmaccalc elfutils-devel audit-libs-devel  bfa-firmware

SRPM(カーネル)の入手と解凍
# cd /usr/local/src
# wget http://vault.centos.org/6.5/updates/Source/SPackages/kernel-2.6.32-431.3.1.el6.src.rpm
# rpm -ivh kernel-2.6.32-431.3.1.el6.src.rpm

パッチの作成
# cd ~/rpmbuild/SOURCES/
# cp linux-2.6.32-431.3.1.el6.tar.bz2 /tmp
# cd /tmp
# tar xjvf linux-2.6.32-431.3.1.el6.tar.bz2
# mv linux-2.6.32-431.3.1.el6 linux-2.6.32-431.3.1.namibuild.el6
# cd linux-2.6.32-431.3.1.namibuild.el6

Makefileファイルを編集
# emacs Makefile
EXTRAVERSION =
->
EXTRAVERSION = -431.3.1.namibuild.el6

tcp.hファイルを編集
# emacs include/net/tcp.h
#define TCP_TIMEWAIT_LEN (60*HZ)
->
#define TCP_TIMEWAIT_LEN (5*HZ)

固めてコピー
# cd ..
# tar cjvf linux-2.6.32-431.3.1.namibuild.el6.tar.bz2 linux-2.6.32-431.3.1.namibuild.el6
# cp linux-2.6.32-431.3.1.namibuild.el6.tar.bz2 ~/rpmbuild/SOURCES/
# cd ~/rpmbuild/SPECS/

kernel.specファイルを編集
# emacs kernel.spec

%define distro_build 431.3.1
->
%define distro_build 431.3.1.namibuild

%define kversion 2.6.32-431.3.1.el6
->
%define kversion 2.6.32-431.3.1.namibuild.el6

Source0: linux-2.6.32-431.3.1.el6.tar.bz2
->
Source0: linux-2.6.32-431.3.1.namibuild.el6.tar.bz2

カーネルをビルドする
結構時間がかかります
# rpmbuild -bb --with firmware kernel.spec

gpg: keyring `./secring.gpg' created
gpg: keyring `./pubring.gpg' created
でストップしたら、別ターミナルでつないで、以下のコマンドを実行
# rngd -r /dev/urandom

インストール
# cd ../RPMS/x86_64/
# rpm -Uvh kernel-2.6.32-431.3.1.namibuild.el6.x86_64.rpm kernel-devel-2.6.32-431.3.1.namibuild.el6.x86_64.rpm kernel-headers-2.6.32-431.3.1.namibuild.el6.x86_64.rpm kernel-firmware-2.6.32-431.3.1.namibuild.el6.x86_64.rpm

確認します
# cat /proc/version
Linux version 2.6.32-431.3.1.el6.x86_64 (mockbuild@c6b10.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) ) #1 SMP Fri Jan 3 21:39:27 UTC 2014

リブートで反映です
# reboot

ベンチマークをしたりして、ポートの空きが早くできているか確認してみましょう。

参考)TIME_WAIT状態のTCPコネクションを早く終了させるべくKernelをリビルド
http://d.hatena.ne.jp/rx7/20131204/p1

※ See also.
革命の日々! Linuxカーネルの「TCP_TIMEWAIT_LEN」変更は無意味? の件について
http://mkosaki.blog46.fc2.com/blog-entry-1292.html
Linux - ぜんぶTIME_WAITのせいだ! - Qiita
http://qiita.com/kuni-nakaji/items/c07004c7d9e5bb683bc2
isucon3_cheatsheet/02.kernel.md at master · sonots/isucon3_cheatsheet
https://github.com/sonots/isucon3_cheatsheet/blob/master/02.kernel.md