Re: Утечка памяти в случае кеширующего прокси

Grigory A. Mozhaev zcrendel на gmail.com
Вс Авг 14 18:03:54 UTC 2011


On Sunday 14 August 2011 21:39:38 you wrote:
> Hello!
>
> On Sun, Aug 14, 2011 at 06:27:21PM +0400, Grigory A. Mozhaev wrote:
> > On Tuesday 09 August 2011 13:10:56 Maxim Dounin wrote:
> > > Hello!
> > >
> > > On Tue, Aug 09, 2011 at 02:40:20AM +0400, Grigory A. Mozhaev wrote:
> > > > Добрый день!
> > > >
> > > > При использовании nginx как кеширующего прокси
> > > > происходит утечка памяти, совершенно аналогичная описанной здесь:
> > > >
> > > > http://serverfault.com/questions/298761/nginx-memory-leaks-when-actin
> > > >g-as -a-proxy-cache
> > > >
> > > > Используется версия 0.8.55, по ссылке 1.0.5.
> > > > Возможно проблема существует и в более поздних версиях.
> > > >
> > > > после запуска
> > > >
> > > > # pmap -x 11959
> > > > 11959:   nginx: worker process
> > > > Address           Kbytes     RSS   Dirty Mode   Mapping
> > > > 0000000000400000     496     352       0 r-x--  nginx
> > > > 000000000067c000      64      64      56 rw---  nginx
> > > > 000000000068c000      56      12      12 rw---    [ anon ]
> > > > 0000000001632000    9580    9548    9548 rw---    [ anon ]
> > > >   <---- 00007feb8b24e000  256000   38792   29064 rw-s-  zero
> > > > (deleted) ....
> > > >
> > > > Через некоторое время
> > > >
> > > > # pmap -x 11955
> > > > 11955:   nginx: worker process
> > > > Address           Kbytes     RSS   Dirty Mode   Mapping
> > > > 0000000000400000     496     352       0 r-x--  nginx
> > > > 000000000067c000      64      64      56 rw---  nginx
> > > > 000000000068c000      56      12      12 rw---    [ anon ]
> > > > 0000000001632000  208128  208120  208120 rw---    [ anon ]
> > > > <----- wtf???? 00007feb8b24e000  256000   60952   58004 rw-s-  zero
> > > > (deleted)
> > > > 00007feb9ac4e000      44      20       0 r-x-- 
> > > > libnss_files-2.12.90.so ...
> > > >
> > > > Доходит до того, что воркеры начинают занимать по 2Гб памяти
> > > > (согласно top).
> > > >
> > > > Если кеширование отключить - никакой утечки не происходит.
> > > >
> > > > п.с. буду еще перепроверять, но похоже, что утечка происходит при
> > > > кешировании очень больших файлов, порядка нескольких гигабайт.
> > >
> > > А в конфиге при этом что?
> >
> > К сожалению доступа к полному конфигу сервера у меня нет (ага, бывает и
> > такое :)). Однако настройки касающиеся прокси получить удалось, вот они:
> >
> >      proxy_cache_path /tmp/nginx/var/cache levels=1:1:2
> > keys_zone=mycache:250m inactive=10080m max_size=950769m; proxy_temp_path
> > /tmp/nginx/var/temp;
> >
> >      ....
> >      server {
> >                 listen 127.0.0.1:8282;
> >                 server_name localhost1;
> >
> >                 access_log /var/log/nginx/localhost1.access_log main;
> >                 error_log /var/log/nginx/localhost1.error_log info;
> >
> >                 location / {
> >                    proxy_pass   http://127.0.0.1:80;
> >                    set $reproxy $upstream_http_x_proxy_url;
> >                    set $proxyhost $upstream_http_x_proxy_host;
> >                    set $cachekey $upstream_http_x_cachekey;
> >                    proxy_cache_key "$cachekey";
> >                    proxy_set_header Host $proxyhost;
> >                    proxy_read_timeout 60;
> >
> >                    proxy_hide_header Connection;
> >                    proxy_hide_header Age;
> >                    proxy_hide_header Cache-Control;
> >                    proxy_ignore_headers "X-Accel-Redirect";
> >                    proxy_max_temp_file_size 30720m;
> >                    proxy_set_header Accept-Encoding "";
> >
> >                    proxy_buffering on;
> >                    proxy_cache mycache;
> >                    proxy_cache_use_stale error timeout invalid_header
> > http_500 http_502 http_503; proxy_cache_valid any 2m;
> >
> >                   #proxy_buffers 4 500k; # все в порядке
> >                    proxy_buffers 4 8k; # 4 32k, default - утечка
> >
> >                    proxy_cache_valid 200 259200m;
> >                    proxy_ignore_client_abort off;
> >                    add_header X-C4 $upstream_cache_status;
> >                }
> >         }
> >
> > Я проверял эти настройки локально, пытаясь воспроизвести ситуацию и в
> > резульате наблюдений установил зависимость утечки от значения настройки
> > "proxy_buffers". Кешировался файл очень большого размера, порядка 5
> > Гигабайт в 4 потока.
> >
> > Что происходит на локальной машине (и это легко воспроизводится
> > с помощью конфига выше):
> >
> > СЛУЧАЙ 1)
> >     При значениях proxy_buffers "4 8k",  "4 32k", дефолтных и
> >     прочих малых значениях происходит увеличение потребления
> >     резидентной памяти одним из воркеров в процессе проксирования
> >     очень большого файла.
> >
> > при использовании приведенного конфига происходит следующий сценарий.
> >
> > Проверялось запуском вот такого скрипта
> > curl -o test1.out -D test1.msg http://127.0.0.1:8282/files/file1.ac3
> > --limit-rate 15000k & curl -o test2.out -D test2.msg
> > http://127.0.0.1:8282/files/file1.ac3 --limit-rate 15000k & curl -o
> > test3.out -D test3.msg http://127.0.0.1:8282/files/file1.ac3 --limit-rate
> > 15000k & curl -o test4.out -D test4.msg
> > http://127.0.0.1:8282/files/file1.ac3 --limit-rate 15000k &
> >
> > * Изначально активный воркер занимает 800кб резидентной памяти.
> >
> > * Закешировано около 1.5Гб файла в temp директории.
> >   PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
> > 15758 nginx     20   0  262m 9508  844 S    5  0.3   0:15.13 nginx <----
> > 15754 root      20   0  254m  652  288 S    0  0.0   0:00.00 nginx
> > 15755 nginx     20   0  254m  832  372 S    0  0.0   0:00.00 nginx
> > ...
> >
> > * Закешировано 3Гб файла в temp директории.
> > PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
> > 15758 nginx     20   0  270m  16m  844 D    5  0.6   0:32.63 nginx <----
> > 15754 root      20   0  254m  652  288 S    0  0.0   0:00.00 nginx
> > 15755 nginx     20   0  254m  832  372 S    0  0.0   0:00.01 nginx
> > ...
> >
> > * Закешировано 5Гб файла в temp директории.
> >  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
> > 15758 nginx     20   0  274m  20m  844 D    6  0.7   0:45.14 nginx <----
> > 15754 root      20   0  254m  652  288 S    0  0.0   0:00.00 nginx
> > 15755 nginx     20   0  254m  832  372 S    0  0.0   0:00.01 nginx
> > ...
> >
> > Кеширование завершено, память освобождена:
> > PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
> > 15757 nginx     20   0  254m  832  372 S    0  0.0   0:00.02 nginx
> > 15758 nginx     20   0  254m 1572  892 S    0  0.1   0:49.96 nginx <----
> > 15759 nginx     20   0  254m  872  416 S    0  0.0   0:00.00 nginx
> > ....
>
> Т.е. реально утечки нет - после завершения запроса всё штатно
> освобождается.  См. ниже.
>
> > Что тоже интересно, в итоге я недополучил один из файлов.
> > test1.out  4390M <--- не получен полностью
> > test2.out  5016M
> > test3.out  5016M
> > test4.out  5016M
>
> Это скорее всего связано с тем, что бекенд по каким-то причинам
> закрыл соединение (e.g. по таймауту).
>
> > СЛУЧАЙ 2)
> >     При значениях proxy_buffers "4 500k",  и прочих больших
> >     значениях НЕ происходит увеличение потребления
> >     резидентной памяти ни одним из воркеров в
> >     процессе проксирования очень большого файла.
> >
> > За первые ~200Мб объем потребляемой памяти устанавливается в 9.5мб и не
> > меняется в течение всего процесса кеширования.
> >
> > PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
> > 18326 nginx     20   0  262m 9504  844 D    5  0.3   0:02.36 nginx <----
> > значение не изменяется в процессе ....
> >
> > По окончанию процесса память освобождается.
> >
> > ==============
> >
> > Что происходило на сервере:
> >
> > При условиях случая #1 (малые размеры proxy_buffers) происходила
> > перманентная утечка памяти, то есть память не освобождалась по окончанию
> > процесса.
> > При условиях случая #2 (большие размеры proxy_buffers) память выделялась
> > в процессе проксировани/кэшировани файла, однако по окончанию процесса
> > память освобождалась. То есть поведение при больших proxy_buffers было
> > похоже на случай #1 для тестируемой локальной машины.
> >
> > В итоге сейчас на сервере используется костыль:
> >  proxy_buffers 4 512k;
> >
> > За уже 3 дня не обнаружено утечек. При "4 8k" за 3 дня утекало более 1Гб
> > резидентной памяти на каждого воркера.
>
> Судя по описанию, всё обсуждаемое - не утечки, а следствие
> поведения системного аллокатора в условиях фрагментации
> используемой памяти.  Видимое "неосвобождение" памяти на сервере
> объясняется тем, что там есть ещё и другие запросы, и у аллокатора
> не наступает "спокойного" момента, когда бы он мог почистить за
> собой.  Использование больших буферов скорее всего меняет поведение
> аллокатора, и он начинает вести себя прилично.
>
> Я правильно понимаю, что операционная система - Linux?  Где-то тут
> должны быть люди, умеющие носить Linux, возможно они подскажут,
> за какие ручки подёргать аллокатор, чтобы стало лучше.
>
> Maxim Dounin
>
> _______________________________________________
> nginx-ru mailing list
> nginx-ru на nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx-ru

На сервере память не освобождалась, а наоборот еще и кушалась даже тогда, 
когда ни одного обрабатываемого запроса не было (все соединения были закрыты) - это скорее уже 
последствия сноса крыши этому аллокатору (или чему-то в nginx), чем причина. 
Кроме прочего являлись и другие проблемы навроде исчерпания числа доступных 
сокетов для соединения с апстримом, исчерпание лимита открытых файловых дескрипторов. 
Сейчас ничего такого нет, т.к. память нормально обратно вовращается.

Операционная системы:
- на сервере fc14 (FedoraCore) /2.6.35.6-45.fc14.x86_64gcc version 4.5.1 20100924. 
- машина для тестов Gentoo Linux(i686)/2.6.34-gentoo-r12 , gcc версия 4.4.5

-- 
С уважением,
Можаев Григорий


Подробная информация о списке рассылки nginx-ru