On Wednesday 05 April 2006 17:58, Igor Sysoev wrote:
On Fri, 31 Mar 2006, Andrei Nigmatulin wrote:
On Friday 31 March 2006 16:08, Igor Sysoev wrote:
On Fri, 31 Mar 2006, Alexey N. Kovyrin wrote:
Igor Sysoev пишет:
Нужно собрать nginx с профилированием.
Для gprof это делается примерно так:
./configure --with-cc-opt="-pg -g" --with-ld-opt="-pg" ...
Потом запускается nginx, получаем файл nginx.gmon.
Потом запускаем gprof nginx, вывод присылаем мне.
А если попробовать без профилирования
./configure --with-cc-opt="-D NGX_ALIGNMENT=16" ...
Эффект абсолютно нулевой... :-(
Какие есть еще варианты кроме "выкинуть процессор"? :-)
Кажется, я понял, в чём проблема.
Если не секрет в чем же ? У меня аналогичные проблемы...
Сколько времени занимает запуск ?
Что используется - map и куча виртуальных серверов ?
Да, map используется, но кажется дело не в нем. Например, при
server_names_hash_max_size 100000 и server_names_hash_max_size 384:
Имеется в виду server_names_hash_bucket_size 384 ?
# time ../sbin/nginx -t
2006/04/06 19:36:31 [info] 28658#0: the configuration
file /home/nginx/conf/nginx.conf syntax is ok
2006/04/06 19:36:31 [info] 28658#0: the configuration
file /home/nginx/conf/nginx.conf was tested successfully
real 0m47.037s
user 0m46.841s
sys 0m0.185s
Увеличиванием server_names_hash_max_size до 512 проблема решается (время
Имеется в виду server_names_hash_bucket_size 512 ?
становится 2 секунды) но поскольку кол-во server_names постоянно
увеличивается - такую систему сложно поддерживать - было уже несколько раз
когда nginx отказывался плавно перезагружаться из-за того что "could not
build the server_names_hash, you should increase either
server_names_hash_max_size or server_names_hash_bucket_size".
Я так понимаю, что проблема в том, что в ngx_hash[_wildcard]_init() реализован
алгоритм поиска minimal hashing. Это понятно, ведь nginx везде пытается
использовать как можно меньше памяти. Однако если пользователь указал
*_hash_max_size и *_hash_bucket_size то он (пользователь) уже дал согласие на
то, что в худшем случае nginx найдет hash_size == hash_max_size и использует
максимальное кол-во памяти.
Следовательно, может быть, было бы оптимальнее начать искать hash_size с
nelts / (ngx_cacheline_size / (2 * sizeof(void *)) - 1) в сторону увеличения,
а с hash_max_size в сторону уменьшения ?
(кстати, эвристику этой хитрой формулы я до сих пор не понял ;-)
Эвристика такая - каждый ключ в корзине хэша занимает минимум
2 * sizeof(void *): один void * - указатель на значение,
второй - длина имени ключа (один байт) плюс само имя ключа, выравненное
на void *. В линии кэша может поместится несколько ключей.
Для кэша с линией в 32 байта на 32-битной архитектуре в одной линии
может поместится максимум 2*4=8 ключей. После ключей есть ещё указатель
на NULL - это признак конца корзины, поэтому "- 1". Стало быть, ключей уже 7.
Ну а теперь делим общее количество элементов на максимальное число
ключей в одной линии кэша. Получаем значение, с которого нужно стартовать.
Меньше не имеет смысла (с). Но проблема в том, что основное время
тратится не на стартовых итерациях, а на последних, особенно, когда
массив, в котором считается размер корзин, уже не помещается в кэш
процессора.
Получившийся хэш был бы более perfect чем minimal, но вряд ли это будет
критично для производительности. В теории, она даже может улучшиться ;-)
Правда, пользователю может хотется "все равно построить хэш, даже вылезая за
указанные hash_max_size / hash_bucket_size", в этом случае стратегию нужно
пересмотреть.
Наверное, в дополнение к server_names_hash_max_size имеет смысл сделать
директиву server_names_hash_size, задающую стартовый размер хэша.
И ещё можно выводить найденные размеры хэшней.
В этом случае есть только одна проблема - хэши создаются отдельно
для каждого слушающего сокета. И для одного сокета хэш может
быть маленький, а для - другого огромный.
Игорь Сысоев
http://sysoev.ru