Re: как правильно закрывать соединения при наступлении keepalive_requests: обсудим ?

Maxim Dounin mdounin на mdounin.ru
Пн Сен 3 13:15:19 UTC 2018


Hello!

On Mon, Sep 03, 2018 at 05:43:17PM +0500, Илья Шипицин wrote:

> пн, 3 сент. 2018 г. в 17:30, Maxim Dounin <mdounin at mdounin.ru>:
> 
> > Hello!
> >
> > On Mon, Sep 03, 2018 at 04:45:31PM +0500, Илья Шипицин wrote:
> >
> > > пн, 3 сент. 2018 г. в 16:11, Maxim Dounin <mdounin at mdounin.ru>:
> > >
> > > > On Sun, Sep 02, 2018 at 11:12:31PM +0500, Илья Шипицин wrote:
> > > >
> > > > > есть такое наблюдение. если проксировать на апстрим БЕЗ киэлайв, то
> > на
> > > > > стороне nginx удивительным образом все хорошо (потому что соединение
> > > > > закрывается по инициативе бекенда)
> > > > >
> > > > > если проксировать с включенным кипэлайвом, то в случаях, когда
> > соединение
> > > > > закрывается по инициативе nginx, на стороне  nginx порт уходит в
> > > > > TIME_WAIT.
> > > > >
> > > > > с одной стороны - несмертельно. все с этим живут.
> > > > > с другой стороны - например, в случае, когда запрос последний (100-й
> > при
> > > > > дефолтном значении keepalive_requests), можно ведь явно добавить
> > > > > "Connection: Close" ? тем самым помочь бекенду закрыть соединение, и
> > > > > сэкономить один порт на nginx ?
> > > >
> > > > Теоретически - можно.
> > > >
> > > > Практически - формирование запроса на бэкенд происходит до того,
> > > > как бэкенд выбран и/или установлено или извлечено из кэша
> > > > соединение, которое будет использоваться для отправки запроса.
> > > > Кроме того, один и тот же запрос может быть отправлен на несколько
> > > > разных бэкендов и/или в несколько разных соединений.
> > > >
> > > > Соответственно выставление "Connection: close" по достижении
> > > > keepalive_requests для конкретного соединения к бэкенду -
> > > > потребует достаточно серьёзных переделок в логике работы с
> > > > бэкендами.  Не говоря уже о том, что сейчас при использовании
> > > > keepalive-соединений заголовок Connection выставляется из конфига
> > > > через proxy_set_header, и это тоже понадобится переделывать.
> > >
> > > да, я про эту магию и говорил. в некоторых случаях можно сделать более
> > умно
> > >
> > > > Так что если порты очень жмут - то проще поднять
> > >
> > > не жмут. мы научились с этим жить.
> > > просто в процессе исследований пришла мысль, про которую я и написал.
> > > было бы круто в какие-нибудь планы разработки ее включить
> >
> > Ну вот я изложил выше - там много всего переделывать, причём - с
> > деградацией производительности в некоторых краевых случаях.  При
> > этом сама проблема, скажем так, представляется не то чтобы
> > критичной.  Так что шансов, что мы решим-таки это место
> > переделывать - не очень много.
> >
> 
> с деградацией не надо, конечно.
> из того, что вы изложили - непонятно, каким именно бекендом обработается
> запрос - кажется, что
> можно предположить "если к первому бекенду это последний запрос -
> принудительно пишем Connection: close"
> 
> другое дело, что в момент, когда выставляется хедер, непонятно про бекенд
> вообще ничего - это да.

Сейчас запрос создаётся до того, как что-либо становится известно 
про бэкенды.  И используется этот единожды созданный запрос - для 
всех последующих обращений к любым бэкендам.  Таких обращений 
может быть много, в соответствии с proxy_next_upstream.  Более 
того, иногда "много" - это штатное поведение, скажем при 
"proxy_next_upstream http_404" предполагается, что nginx 
перебирает бэкенды, пока не найдёт тот, на котором есть 
соответствующий ресурс.

Чтобы выставить "Connection: close" - надо менять логику так, 
чтобы запрос создавался уже в процессе обращения к бэкенду, когда 
соединение с бэкендом уже установлено или получено из кэша.  И 
соответственно делать так, чтобы запрос для каждого обращения на 
бэкенд в рамках proxy_next_upstream - создавался заново.

> > > > keepalive_requests.  Или выставить на бэкенде аналогичное
> > >
> > > на бекенде iis, там нет такой крутилки
> > >
> > > > ограничение в значение, которое бы было такое же или меньше, чему
> > > > у nginx'а, и тогда бэкенд будет закрывать соединение сам.
> > > > Собственно, текущее значение по умолчанию keepalive_requests к
> > > >
> > >
> > > поднимать keepalive_requests в потолок - была такая ошибка.
> > > мы налетели на примерно такой сценарий
> > >
> > > по умолчанию keepalive_requests равен 100. и ... при релоаде старые
> > воркеры
> > > довольно быстро завершаются.
> > > подняли до 4 миллиардов, и на каждый релоад получили плюсом еще 40
> > > воркеров. и потом память закончилась
> > >
> > > keepalive_requests - это ОЧЕНЬ удобный способ завершать http- воркеры :))
> >
> > Соединения в keepalive'е - что клиентские, что к бэкендам - никак
> > не должны влиять на завершение рабочих процессов при reload'е.
> > Они просто закрываются при получении сигнала о перезагрузке
> > конфигурации и/или если соединение переходит в keepalive, когда
> > рабочий процесс завершается.  Если влияют - приносите подробности,
> > будем разбираться.
> >
> 
> воркер же будет обрабатывать запросы по уже установленным соединениям, пока
> либо клиент не отключится,
> либо пока   воркер сам не закроет (при исчерпании keepalive_requests) ?

Keepalive-соединения nginx впрове закрывать в любой момент, и 
именно это он и делает - в любой момент времени, когда бы рабочий 
процесс не попросили завершиться.

Поэтому в случае http - время завершения старых рабочих процессов 
определяется длительностью запросов, и не зависит от того, 
используется ли keepalive или нет.

> а новый релоад приводит к запуску кучи новых воркеров. но не приводит к
> завершению старых воркеров ?

Reload приводит к запуску новых рабочих процессов, а также к 
команде на плавное завершение старым рабочим процессам.  Плавное 
завершение - подразумевает закрытие всех keepalive-соединений, и 
выход в тот момент, когда открытых соединений (точнее - работающих 
таймеров) не останется, то есть тогда, когда доработают все 
существующие запросы.

-- 
Maxim Dounin
http://mdounin.ru/


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