2014年4月4日金曜日

Amazon EC2でTCPポート枯渇を防ぐために、Linuxカーネルをチューニング

http://www.flickr.com/photos/daniilr/7454436468

Linuxカーネルの"TCP_TIMEWAIT_LEN"をチューニングして、TCPポートの枯渇を防ぐ方法を紹介します。

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

環境は、Amazon EC2のCentOS6.6です。
AMIは、こちらです。
https://aws.amazon.com/marketplace/pp/B00NQAYLWO
AWS Marketplace - CentOS 6 (x86_64) - with Updates HVM
Linux/Unix, CentOS 6 | 64-bit Amazon Machine Image (AMI) | Updated: 9/29/14
Instance Type: c3.4xlarge
EBS: General Purpose (SSD)

カーネルのリビルド時には10Gほど使用するので、ディスクサイズは多めに設定して起動します。
あらかじめ、ディスクサイズを増加させておきます。下記参照。

EC2のCentOS6 HVMでresize2fs "Nothing to do!"と言われたとき
http://takeshiyako.blogspot.jp/2014/12/ec2centos6-hvmresize2fs-nothing-to-do.html

ライブラリをアップデート。
# yum -y update
# yum -y install gcc wget 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
# reboot

カーネルのバージョンを確認。
# cat /proc/version
Linux version 2.6.32-431.29.2.el6.x86_64 (mockbuild@c6b9.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) ) #1 SMP Tue Sep 9 21:36:05 UTC 2014

カーネルの最新バージョンを探します。
http://vault.centos.org/6.6/updates/Source/SPackages/
kernel-2.6.32-504.8.1.el6.src.rpmm
こちらが最新でした。

ダウンロードします。
# cd /usr/local/src
# curl -O http://vault.centos.org/6.6/updates/Source/SPackages/kernel-2.6.32-504.8.1.el6.src.rpm

パッチを作成。
# rpm -ivh kernel-2.6.32-504.8.1.el6.src.rpm
# cd ~/rpmbuild/SOURCES/
# cp linux-2.6.32-504.8.1.el6.tar.bz2 /tmp
# cd /tmp
# tar xjvf linux-2.6.32-504.8.1.el6.tar.bz2
# mv linux-2.6.32-504.8.1.el6 linux-2.6.32-504.8.1.namibuild.el6
# cd linux-2.6.32-504.8.1.namibuild.el6

Makefileファイルを編集。
# vim Makefile
EXTRAVERSION =
->
EXTRAVERSION = -504.8.1.namibuild.el6

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

圧縮してコピー。
# cd ..
# tar cjvf linux-2.6.32-504.8.1.namibuild.el6.tar.bz2 linux-2.6.32-504.8.1.namibuild.el6
# cp linux-2.6.32-504.8.1.namibuild.el6.tar.bz2 ~/rpmbuild/SOURCES/
# cd ~/rpmbuild/SPECS/

kernel.specファイルを編集。
# vim kernel.spec

%define distro_build 504.8.1
->
%define distro_build 504.8.1.namibuild

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

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

カーネルをビルドする。結構時間がかかります。(c3.4xlargeで30分ほど)
# rpmbuild -bb --with firmware kernel.spec

ビルドしたカネールをインストール。
# cd ../RPMS/x86_64/
# rpm -Uvh kernel-2.6.32-504.8.1.namibuild.el6.x86_64.rpm kernel-devel-2.6.32-504.8.1.namibuild.el6.x86_64.rpm kernel-headers-2.6.32-504.8.1.namibuild.el6.x86_64.rpm kernel-firmware-2.6.32-504.8.1.namibuild.el6.x86_64.rpm
# reboot

カネールを確認。
# cat /proc/version
Linux version 2.6.32-504.8.1.namibuild.el6.x86_64 (root@ip-172-31-19-117.ap-northeast-1.compute.internal) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-11) (GCC) ) #1 SMP Thu Dec 25 07:43:14 UTC 2014
ベンチマークをしたりして、ポートの空きが早くできているか確認してみましょう。

Enjoy!



参考)

TIME_WAIT状態のTCPコネクションを早く終了させるべくKernelをリビルド
http://d.hatena.ne.jp/rx7/20131204/p1
kernelをチューニングしてTIME_WAIT値を変更する - メモとかそんな感じなやつ
http://sarface2012.hatenablog.com/entry/2012/11/15/225509
TIME_WAITのチューニングとkernelリビルド for CentOS 6.0 - 逆襲のWebエンジニア
http://d.hatena.ne.jp/ono51/20111012/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