Очень долгий запуск на AMD64...

Igor Sysoev is at rambler-co.ru
Thu Apr 6 22:58:06 MSD 2006


On Thu, 6 Apr 2006, Igor Sysoev wrote:

> On Thu, 6 Apr 2006, Andrei Nigmatulin wrote:
>
>> 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, задающую стартовый размер хэша.
> И ещё можно выводить найденные размеры хэшней.
> В этом случае есть только одна проблема - хэши создаются отдельно
> для каждого слушающего сокета. И для одного сокета хэш может
> быть маленький, а для - другого огромный.

Я решил сделать несколько по-другому: если server_names_hash_max_size
больше 50000 и server_names_hash_max_size / число элементов в хэше < 100,
то начинать поиск размера с server_names_hash_max_size - 1000.

Патч прилагается. Интересно узнать результаты и кроме того, можно поиграть
с числами.


Игорь Сысоев
http://sysoev.ru
-------------- next part --------------
--- src/core/ngx_hash.c	Thu Mar  9 16:59:14 2006
+++ src/core/ngx_hash.c	Thu Apr  6 22:52:14 2006
@@ -164,10 +164,14 @@
         return NGX_ERROR;
     }
 
-    start = nelts / (ngx_cacheline_size / (2 * sizeof(void *)) - 1);
+    bucket_size = hinit->bucket_size - sizeof(void *);
+
+    start = nelts / (bucket_size / (2 * sizeof(void *)) - 1);
     start = start ? start : 1;
 
-    bucket_size = hinit->bucket_size - sizeof(void *);
+    if (hinit->max_size > 50000 && hinit->max_size / nelts < 100) {
+        start = hinit->max_size - 1000;
+    }
 
     for (size = start; size < hinit->max_size; size++) {
 


More information about the nginx-ru mailing list