netstat とかで出てくる TIME_WAIT ですが、デフォルトだと 60 秒になっています
今回はそれを 5 秒に変更しようと思います
せっかくなので rpm できちんと作ります(kernel-firmware も作る)
kernel src 内の TCP_TIMEWAIT_LEN
の値を変更して rpmbuild します
前提
- 今回は CentOS 6.5 (kernel-2.6.32-431.11.2) を例にしています
- 出来上がる version は kernel-2.6.32-431.11.2.el6.timewait5 のようにしています
事前準備
本家のwikiに従って
$ sudo yum groupinstall "Development Tools"
$ sudo yum install ncurses-devel
$ sudo yum install hmaccalc zlib-devel binutils-devel elfutils-libelf-devel
rpmbuild 環境作成
いくつか方法があります
その1
$ mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
$ echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros
その2
$ sudo yum install rpmdevtools
$ rpmdev-setuptree
-
rpmdev-setuptree
は mkdir してくれて~/.rpmmacros
を自動で生成してくれます
kernel の srpm を install
$ wget http://vault.centos.org/6.5/updates/Source/SPackages/kernel-2.6.32-431.11.2.el6.src.rpm
$ rpm -ivh kernel-2.6.32-431.11.2.el6.src.rpm
TCP_TIMEWAIT_LEN の patch ファイルを作る
今回いじるのは kernel の src の中にある include/net/tcp.h
というファイルになります
#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT
* state, about 60 seconds */
src を展開する
-
kernel-2.6.32-431.11.2.el6.src.rpm
を install したことによって~/rpmbuild/SOURCES/linux-2.6.32-431.11.2.el6.tar.bz2
が配置されていると思います - その src を一旦
/tmp
とかに解凍します
$ tar jxf ~/rpmbuild/SOURCES/linux-2.6.32-431.11.2.el6.tar.bz2 --directory=/tmp
tcp.h を編集して patch を作成する
$ cd /tmp/linux-2.6.32-431.11.2.el6
$ cp include/net/tcp.h include/net/tcp.h.org
$ vi include/net/tcp.h
$ diff -Naur include/net/tcp.h.org include/net/tcp.h > ~/rpmbuild/SOURCES/linux-kernel-timewait5.patch
- linux-kernel-timewait5.patch の中身は下記のようになると思います
-
~/rpmbuild/SOURCES/
に patch を置いて下さい
--- include/net/tcp.h.org 2014-04-09 19:46:13.823604279 +0900
+++ include/net/tcp.h 2014-04-09 19:46:44.227097917 +0900
@@ -111,7 +111,7 @@
*/
-#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT
+#define TCP_TIMEWAIT_LEN (5*HZ) /* how long to wait to destroy TIME-WAIT
* state, about 60 seconds */
#define TCP_FIN_TIMEOUT TCP_TIMEWAIT_LEN
/* BSD style FIN_WAIT2 deadlock breaker.
spec を編集する
-
~/rpmbuild/SPECS
にあるkernel.spec
を編集します
$ cd ~/rpmbuild/SPECS
$ cp kernel.spec kernel_timewait5.spec
$ vi kernel_timewait5.spec
- 変更箇所は下記 3 つです
define buildid
@@ -15,7 +15,7 @@
# that the kernel isn't the stock distribution kernel, for example,
# by setting the define to ".local" or ".bz123456"
#
-# % define buildid .local
+%define buildid .timewait5
%define distro_build 431.11.2
%define signmodules 1
patch1000 追加
@@ -610,6 +610,9 @@
Source85: config-powerpc64-debug-rhel
Source86: config-s390x-debug-rhel
+# TCP_TIMEWAIT_LEN patch (60 -> 5)
+Patch1000: linux-kernel-timewait5.patch
+
# empty final patch file to facilitate testing of kernel patches
Patch999999: linux-kernel-test.patch
ApplyOptionalPatch 追加
@@ -932,6 +935,7 @@
# Dynamically generate kernel .config files from config-* files
make -f %{SOURCE20} VERSION=%{version} configs
+ApplyOptionalPatch linux-kernel-timewait5.patch include/net/tcp.h
ApplyOptionalPatch linux-kernel-test.patch
# Any further pre-build tree manipulations happen here.
kernel-firmware の rpm を作成する
- kernel の package は依存関係で同じ version の kernel-firmware を要求されます
- これのせいで custom で kernel 作る時に以前と version 変えずに作ってしまうケースが多いようですが、横着しないで作ればいいと思います
-
norarch
じゃないと作ってくれないので--target=noarch
で作成します
$ rpmbuild -ba --target=noarch --without doc --with kernel_abi_whitelists --with firmware kernel_timewait5.spec
- kernel-doc や kernel-abi-whitelists は今回は作成しないようにしました
これで ~/rpmbuild/RPMS/noarch/kernel-firmware-2.6.32-431.11.2.el6.timewait5.noarch.rpm
が作成されていると思います
謎の挙動
ちょっと話がズレますが
# kernel-abi-whitelists
%define with_kernel_abi_whitelists %{?_with_kernel_abi_whitelists: 0} %{?!_with_kernel_abi_whitelists: 1}
- となっているので、
--with kernel_abi_whitelists
をつけると_with_kernel_abi_whitelists
が 0 になる - なので
--with kernel_abi_whitelists
で rpmbuild すると kernel-abi-whitelists が作成されない - 逆に
--without kernel_abi_whitelists
で rpmbuild すると kernel-abi-whitelists が作成される
ということで 多分これ逆なんじゃないかな と思うんですが、意図してそうなっているかは不明・・
- ちなみに似たような firmware の flag は 0 と 1 が逆になっている
# kernel-firmware
%define with_firmware %{?_with_firmware: 1} %{?!_with_firmware: 0}
kernel の rpm を作成する
必要なものだけ rpm を作る
$ rpmbuild -ba --target=$(uname -m) --with baseonly --without debug --without debuginfo kernel_timewait5.spec
これで下記の rpm が作成されていると思います(x86_64 の場合)
~/rpmbuild/RPMS/kernel-2.6.32-431.11.2.el6.timewait5.x86_64.rpm
~/rpmbuild/RPMS/kernel-headers-2.6.32-431.11.2.el6.timewait5.x86_64.rpm
~/rpmbuild/RPMS/kernel-devel-2.6.32-431.11.2.el6.timewait5.x86_64.rpm
作成した rpm を適用する
- yum の repository に置いたり rpm で直接入れたりしてください
- 適用後、
/boot/grub/grub.conf
に新しい kernel の設定が入っていることを確認してください - reboot !!
補足
- 今回はいろいろ余計な rpm を作らないように
--without
とか多用してますが、必要に応じて flag を外して下さい - 何も指定しないで default の flag でも全然問題はないでしょう
IP_VS_TCP_S_TIME_WAIT
も?
サーバーの用途によっては IP_VS_TCP_S_TIME_WAIT
等も変更したほうがいいかもしれませんね
static int tcp_timeouts[IP_VS_TCP_S_LAST+1] = {
[IP_VS_TCP_S_NONE] = 2*HZ,
[IP_VS_TCP_S_ESTABLISHED] = 15*60*HZ,
[IP_VS_TCP_S_SYN_SENT] = 2*60*HZ,
[IP_VS_TCP_S_SYN_RECV] = 1*60*HZ,
[IP_VS_TCP_S_FIN_WAIT] = 2*60*HZ,
[IP_VS_TCP_S_TIME_WAIT] = 2*60*HZ,
[IP_VS_TCP_S_CLOSE] = 10*HZ,
[IP_VS_TCP_S_CLOSE_WAIT] = 60*HZ,
[IP_VS_TCP_S_LAST_ACK] = 30*HZ,
[IP_VS_TCP_S_LISTEN] = 2*60*HZ,
[IP_VS_TCP_S_SYNACK] = 120*HZ,
[IP_VS_TCP_S_LAST] = 2*HZ,
};
TCP_TIMEOUT_INIT
も?
CentOS 6.5 では TCP 再送間隔の初期値が 1 秒なので特に変えないでいいと思いますが、古い OS とかだと 3 秒になっていることがありますので必要に応じて変えるのもいいと思います
#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ)) /* RFC2988bis initial RTO value */