Не закрывающаяся сессия после запроса http.Client

360 views
Skip to first unread message

Anton Byshovets

unread,
Jan 9, 2016, 11:48:53 AM1/9/16
to Golang Russian
Доброго дня.

Есть функция, в которой есть http клиент, который совершает запросы запросы, и просто отдаёт Body.

Столкнулся с тем, что коннекты после окончания он не закрывает. При приличном количестве запросов это дело начинает занимать приличное количество памяти. pprof говорит о огромном (соответствующем) количестве горутин висящих с 'net/http.(*persistConn).readLoop+0xace c:/go/src/net/http/transport.go:976' и 'net/http.(*persistConn).writeLoop+0x413 c:/go/src/net/http/transport.go:1009'.
Если проверять http.Response.Close (соответственно уже после http.Response.Body.Close()) - то состояние подтверждает незакрытое соеденение.

Попытка осилить самому или нагуглить решение - вывела только на большое количество багрепортов на эту тему, каждый из которых был помечен как решенный с новыми версиями.
Код функции (функцию, если это важно, дёргают из других горутин): http://play.golang.org/p/r4SlncXynJ

Если кто-то сталкивался, или может пролить свет на это дело - буду благодарен за любую помощь, или указание направления раскопок.
Заранее благодарен.

Dmitry Vyukov

unread,
Jan 9, 2016, 12:20:43 PM1/9/16
to gola...@googlegroups.com
Похоже на персисентные соединия HTTP1.1. Попробуй установить
Transport.DisableKeepAlives
https://golang.org/pkg/net/http/#Transport
> --
> Вы получили это сообщение, поскольку подписаны на группу "Golang Russian".
> Чтобы отменить подписку на эту группу и больше не получать от нее сообщения,
> отправьте письмо на электронный адрес
> golang-ru+...@googlegroups.com.
> Чтобы настроить другие параметры, перейдите по ссылке
> https://groups.google.com/d/optout.

Anton Byshovets

unread,
Jan 9, 2016, 12:55:56 PM1/9/16
to Golang Russian
Сделал. Соединения теперь сообщают что они закрыты. Но при этом pprof продолжает указывать на спавнящихся и висящих net/http.(*persistConn).writeLoop и net/http.(*persistConn).readLoop.

суббота, 9 января 2016 г., 19:20:43 UTC+2 пользователь Dmitry Vyukov написал:

Aliaksandr Valialkin

unread,
Jan 19, 2016, 6:38:11 AM1/19/16
to Golang Russian


On Saturday, January 9, 2016 at 7:55:56 PM UTC+2, Anton Byshovets wrote:
Сделал. Соединения теперь сообщают что они закрыты. Но при этом pprof продолжает указывать на спавнящихся и висящих net/http.(*persistConn).writeLoop и net/http.(*persistConn).readLoop.

Создайте client один раз в глобальной области видимости, после чего используйте его в функции HTTPGet из http://play.golang.org/p/r4SlncXynJ . Сейчас он у вас создается при каждом вызове функции. Каждый объект http.Client создает по две горутины на каждое подключение к серверу - для чтения и записи. Их-то и видно в pprof. Если бы использовался один client, то таких горутин было бы намного меньше.

Навязчивая реклама: попробуйте fasthttp.Client - он автоматически закрывает idle соединения через 10 секунд, в отличие от net/http.Client, который вроде закрывает idle соединения только в случае, если их закроет сервер. Это может привести к недостатку свободных файловых дескрипторов при опросе большого количества разных серверов, которые долго не закрывают keep-alive соединения. А еще fasthttp.Client быстрее до 10 раз по сравнению с net/http.Client - см. результаты бенчмарков :)

Anton Byshovets

unread,
Jan 19, 2016, 6:58:38 AM1/19/16
to Golang Russian
С момента создания темы я тоже пришел к подобным подозрениям, и вынес клиент как вы и порекомендовали (да и вообще это да, более верная практика). Но к моему удивлению на дело это абсолютно никак не повлияло, и всё так же продолжает висеть и кушать память.

За рекламу - выглядит очень хорошо. Вечером оценю ваши труды в деле :)

Спасибо.

вторник, 19 января 2016 г., 13:38:11 UTC+2 пользователь Aliaksandr Valialkin написал:

Igor Yurchenko

unread,
Jan 19, 2016, 9:48:57 AM1/19/16
to Golang Russian


вторник, 19 января 2016 г., 13:38:11 UTC+2 пользователь Aliaksandr Valialkin написал:
On Saturday, January 9, 2016 at 7:55:56 PM UTC+2, Anton Byshovets wrote:
Сделал. Соединения теперь сообщают что они закрыты. Но при этом pprof продолжает указывать на спавнящихся и висящих net/http.(*persistConn).writeLoop и net/http.(*persistConn).readLoop.

Создайте client один раз в глобальной области видимости, после чего используйте его в функции HTTPGet из http://play.golang.org/p/r4SlncXynJ . Сейчас он у вас создается при каждом вызове функции. Каждый объект http.Client создает по две горутины на каждое подключение к серверу - для чтения и записи. Их-то и видно в pprof. Если бы использовался один client, то таких горутин было бы намного меньше.

Навязчивая реклама: попробуйте fasthttp.Client - он автоматически закрывает idle соединения через 10 секунд, в отличие от net/http.Client, который вроде закрывает idle соединения только в случае, если их закроет сервер. Это может привести к недостатку свободных файловых дескрипторов при опросе большого количества разных серверов, которые долго не закрывают keep-alive соединения.

А нельзя ли об этом поподробней? Я у себя этого не наблюдаю...
 

Aliaksandr Valialkin

unread,
Jan 19, 2016, 12:02:33 PM1/19/16
to Golang Russian


On Tuesday, January 19, 2016 at 4:48:57 PM UTC+2, Igor Yurchenko wrote:


вторник, 19 января 2016 г., 13:38:11 UTC+2 пользователь Aliaksandr Valialkin написал:


On Saturday, January 9, 2016 at 7:55:56 PM UTC+2, Anton Byshovets wrote:
Сделал. Соединения теперь сообщают что они закрыты. Но при этом pprof продолжает указывать на спавнящихся и висящих net/http.(*persistConn).writeLoop и net/http.(*persistConn).readLoop.

Создайте client один раз в глобальной области видимости, после чего используйте его в функции HTTPGet из http://play.golang.org/p/r4SlncXynJ . Сейчас он у вас создается при каждом вызове функции. Каждый объект http.Client создает по две горутины на каждое подключение к серверу - для чтения и записи. Их-то и видно в pprof. Если бы использовался один client, то таких горутин было бы намного меньше.

Навязчивая реклама: попробуйте fasthttp.Client - он автоматически закрывает idle соединения через 10 секунд, в отличие от net/http.Client, который вроде закрывает idle соединения только в случае, если их закроет сервер. Это может привести к недостатку свободных файловых дескрипторов при опросе большого количества разных серверов, которые долго не закрывают keep-alive соединения.

А нельзя ли об этом поподробней? Я у себя этого не наблюдаю...



// By default, Transport caches connections for future re-use.
// This may leave many open connections when accessing many hosts.
// This behavior can be managed using Transport's CloseIdleConnections method
// and the MaxIdleConnsPerHost and DisableKeepAlives fields. 

Anton Byshovets

unread,
Jan 20, 2016, 4:57:36 PM1/20/16
to Golang Russian
Прошу прощения за отсрочку с отписью.

В общем, ваш fasthttp - это выше всяких похвал. Низкий поклон за проделанный труд.
Утечек нет, работает словно метеор.

Единственное чего не нашел в readme - адреса для донейтов :)


вторник, 19 января 2016 г., 13:38:11 UTC+2 пользователь Aliaksandr Valialkin написал:
Reply all
Reply to author
Forward
0 new messages