Персональный
сайт
Игоря
Сысоева


 
english
обо мне
 
sysoev.ru
 
nginx
 
mod_accel
mod_realip
mod_deflate
программирование
всякая всячина
windows
freebsd
apache
pppd
unix
web
 
 

FreeBSD 4.3 и Initial Sequence Number

 

26.04.2002

Год назад вышла FreeBSD 4.3, в которой была проблема, связанная с изменением алгоритма генерации начального номера последовательности (ISN, Initial Sequence Number) TCP соединения. С ней можно столкнуться, если потестировать Apache входящей в его дистрибутив программой ab. Если Apache успевает обработать 3976 запросов менее, чем за 60 секунд, то ab -n 4000, запущенная на FreeBSD 4.3, через некоторое время выдаёт

Server timed out
: Operation now in progress
или же просто работает очень долго.

Суть проблемы в следующем. После закрытия соединения каждый сокет на серверной стороне в течение 60 секунд (2*MSL) находится в состоянии TIME_WAIT. В этом состоянии новое соединение с такими же параметрами (то есть, с такими же портами и адресами удалённой и локальной сторон) возможно лишь в том случае, если ISN пришедшего пакета с флагом SYN больше номера последовательности соединения, находящегося в состоянии TIME_WAIT. В противном случае соединение не устанавливается и на удалённой стороне висит в состоянии SYN_SENT. Поскольку на FreeBSD 4.3 для исходящих соединений используется 3976 портов в диапазоне 1024-5000, то после установления 3976 соединений, локальные порты повторяются. Проблемы не возникает, если машина не успевает обработать 3976 запросов за 60 секунд, так как ко времени обработки 3977 запроса первое соединение, находившееся в состоянии TIME_WAIT, уже будет удалено. Однако сейчас такие машины нужно поискать — например, Apache на P3-733 обрабатывает 3976 статических запросов всего за 3.6 секунды.

В качестве некоторого решения этой проблемы можно увеличить диапазон портов, используемых для исходящих соединений на клиентской стороне, с помощью sysctl net.inet.ip.portrange.first и net.inet.ip.portrange.last — они равны 1024 и 5000 соответственно.

Интересно, что, согласно Стивенсу (Stevens, UNIX Network Programming, v.1, p.43), 5000 - это банальная опечатка, и верхний предел должен быть 50000. Тем не менее, TCP/IP стэки некоторых современных систем до сих пор используют этот диапазон портов. Во FreeBSD недавно этот диапазон был изменён на рекомендованный IANA — 49152 — 65535.
Также можно уменьшить время MSL на серверной стороне с помощью sysctl net.inet.tcp.msl, по умолчанию равное 30000 миллисекундам.

История появления и исправления проблемы такова. 17.04.2001 во FreeBSD 5.0-CURRENT был изменён способ генерации ISN — вместо предыдущего метода, в котором номера генерировались случайно, но при этом всегда увеличивались, был взят алгоритм из OpenBSD, в котором номера генерируются просто случайным образом. Понятно, что при этом вероятность установления 3977-го соединения равна 50%. 18.04.2001 изменения были внесены и в FreeBSD-4.3-RELEASE, а 2.05.2001 и в FreeBSD-3.5-STABLE. Однако, пересобрав ядро с опцией

option TCP_COMPAT_42
можно было восстановить старый вариант генерации. Но 22.06.2001 из FreeBSD 4.3-STABLE эта опция была удалена. Во FreeBSD 5.0-CURRENT это случилось сразу же после импортирования нового варианта — 20.04.2001. 8.07.2001 в обеих системах появился sysctl net.inet.tcp.tcp_seq_genscheme, позволяющий на ходу менять вариант генерации. По умолчанию он был равен единице, означающей алгоритм OpenBSD. Ноль означал старый алгоритм. 22.08.2001 две схемы генерации в обеих системах были заменены на схему, описанную в RFC 1948, и этот sysctl был удалён. Однако упоминание о нём забыли удалить из Release Notes FreeBSD 4.4-RELEASE.

(C) Игорь Сысоев
http://sysoev.ru