вопрос про горутины, способы их запуска и память

679 views
Skip to first unread message

Александр Пенкин

unread,
Oct 7, 2014, 5:48:56 AM10/7/14
to gola...@googlegroups.com
Есть приложение, которое принимает сообщение из очереди сообщений, обрабатывает его, и отправляет результат в другую очередь.
Собственно каждая часть (прием, обработка, отправка) выполняется в отдельной горутине, передача данных через каналы.

Приложение принимает из очереди ссылку, обработчик выполняет get запрос, получает статус код и прочую необходимую информацию и отправляет ее в очередь

Делали 3 варианта запуска горутин, далее опишу какие и проблемы в каждом случае, хотелось бы узнать какой из этих способов лучше, и возможные решения проблем.

Вариант 1:
запускаем по одной горутине на прием, обработку и отправку.
Проблема: очень медленная работа, со временем понемногу растет потребление памяти.
Вопрос: из за чего может течь память? (пробовали вызывать после каждой итерации runtime.GC, не помогает)

Вариант 2:
запускаем для каждого сообщения отдельную горутину обработчика.
Плюс: быстрая работа
Проблема: скорость приема сообщений выше скорости обработки, количество горутин растет, тем самым потребляя все больше памяти, временами превышая лимит коннекшенов, и в итоге приложение падает.
Вопрос: как можно контролировать количество горутин в каких то пределах? sync.WaitGroup не то, так как ждет завершения всех, убивая тем самым скорость работы

Вариант 3:
запускаем пул горутин обработчика
Не ясно необходимое количество горутин, при запуске большого количества, часть простаивает (видно по разнице принятых и отправленых сообщений), по всей видимости из за того, что сообщение из канала уходит первому свободному.
Проблема: Как и в первом варианте, но в больших объемах, так же со временем работы скорость работы падает.
Вопрос: как можно управлять пулом горутин, и опять же про память.

Спасибо.

Dmitry Vyukov

unread,
Oct 7, 2014, 6:06:02 AM10/7/14
to gola...@googlegroups.com
2014-10-07 13:48 GMT+04:00 Александр Пенкин <sasha...@gmail.com>:
> Есть приложение, которое принимает сообщение из очереди сообщений,
> обрабатывает его, и отправляет результат в другую очередь.
> Собственно каждая часть (прием, обработка, отправка) выполняется в отдельной
> горутине, передача данных через каналы.
>
> Приложение принимает из очереди ссылку, обработчик выполняет get запрос,
> получает статус код и прочую необходимую информацию и отправляет ее в
> очередь
>
> Делали 3 варианта запуска горутин, далее опишу какие и проблемы в каждом
> случае, хотелось бы узнать какой из этих способов лучше, и возможные решения
> проблем.
>
> Вариант 1:
> запускаем по одной горутине на прием, обработку и отправку.
> Проблема: очень медленная работа, со временем понемногу растет потребление
> памяти.
> Вопрос: из за чего может течь память? (пробовали вызывать после каждой
> итерации runtime.GC, не помогает)


Видимо какая-то очередь растет неограниченно.
Попробуйте хип профайлер, статистику памяти или хип дамп:
https://software.intel.com/en-us/blogs/2014/05/10/debugging-performance-issues-in-go-programs



> Вариант 2:
> запускаем для каждого сообщения отдельную горутину обработчика.
> Плюс: быстрая работа
> Проблема: скорость приема сообщений выше скорости обработки, количество
> горутин растет, тем самым потребляя все больше памяти, временами превышая
> лимит коннекшенов, и в итоге приложение падает.
> Вопрос: как можно контролировать количество горутин в каких то пределах?
> sync.WaitGroup не то, так как ждет завершения всех, убивая тем самым
> скорость работы

Примерно так:

sem := make(chan struct{}, N)
for req := range requests {
sem <- struct{}{}
req := req
go func() {
handleRequest(req)
<-sem
}()
}

> Вариант 3:
> запускаем пул горутин обработчика
> Не ясно необходимое количество горутин, при запуске большого количества,
> часть простаивает (видно по разнице принятых и отправленых сообщений), по
> всей видимости из за того, что сообщение из канала уходит первому
> свободному.
> Проблема: Как и в первом варианте, но в больших объемах, так же со временем
> работы скорость работы падает.
> Вопрос: как можно управлять пулом горутин, и опять же про память.

Вначале нужно понять куда девается память и почему замедляется,
Но я бы просто сделал (2) с лимитим на максимальное число горутин

Denis Bakhtin

unread,
Oct 7, 2014, 6:06:16 AM10/7/14
to gola...@googlegroups.com
Добрый день.
Я думаю, варианты 2 и 3 не могут быть принципиально быстрее и отказоустойчивей варианта 1, поскольку Вы сами обозначили проблемы - возникают промежуточные каналы, проблема их переполнения, дополнительные горутины на обработку и отправку результата. В то время как процесс обработки входящего сообщения вполне себе линейный и последовательный. 

7 октября 2014 г., 13:48 пользователь Александр Пенкин <sasha...@gmail.com> написал:

--
Вы получили это сообщение, поскольку подписаны на группу "Golang Russian".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес golang-ru+...@googlegroups.com.
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.

Dmitry Vyukov

unread,
Oct 7, 2014, 6:09:48 AM10/7/14
to gola...@googlegroups.com
2014-10-07 14:06 GMT+04:00 Denis Bakhtin <denis....@gmail.com>:
> Добрый день.
> Я думаю, варианты 2 и 3 не могут быть принципиально быстрее и
> отказоустойчивей варианта 1, поскольку Вы сами обозначили проблемы -
> возникают промежуточные каналы, проблема их переполнения, дополнительные
> горутины на обработку и отправку результата. В то время как процесс
> обработки входящего сообщения вполне себе линейный и последовательный.

Это в первом варианте возникают промежуточные каналы и горутины при
обработке сообщений
В 2 и 3 одна горутина обрабытывает сообщение от начала до конца

Denis Bakhtin

unread,
Oct 7, 2014, 6:10:42 AM10/7/14
to gola...@googlegroups.com
Точно, почему то я прочитал иначе )) виноват.

7 октября 2014 г., 14:09 пользователь 'Dmitry Vyukov' via Golang Russian <gola...@googlegroups.com> написал:
Настройки подписки и доставки писем: https://groups.google.com/d/optout.

Igor Yurchenko

unread,
Oct 7, 2014, 11:49:49 AM10/7/14
to gola...@googlegroups.com
Мы у себя используем второй вариант. Вы описываете какую-то странную проблему. Если средняя скорость обработки сообщений допустим в десять раз меньше средней скорости поступления сообщений, то десять (или двенадцать-пятнадцать, с учетом накладных расходов) параллельно запущенных гороутинов должно быть достаточно для обработки сообщений со скоростью их поступления. Если у вас число гороутинов сильно растет, то очевидно, есть какие-то проблемы с логикой приложения.
Возможно, вы просто не прибиваете гороутины, которые не дождались ответа от сервера. Таймаут на обработке сетевых запросов должен быть обязательно.

В общем надо смотреть код...

Александр Пенкин

unread,
Oct 8, 2014, 1:48:21 AM10/8/14
to gola...@googlegroups.com
Таймауты стоят, горутины умирают, но скорость создания новых гараздо быстрее закрытия работающих, так как в очереди могут быть десятки тысяч сообщений и нет ограничений на их прием, собственно в этом и проблема, как установить лимит?
Библиотека работы с очередью позволяет делать прием следующего сообщения, только после обработки предыдущего, но это дает обратный эффект, так как нельзя обрабатывать одновременно несколько сообщений.

вторник, 7 октября 2014 г., 21:49:49 UTC+6 пользователь Igor Yurchenko написал:

Ьу тщ

unread,
Oct 8, 2014, 2:47:14 AM10/8/14
to gola...@googlegroups.com
что-то вы хуюнюс какую-то гоните:

>в очереди могут быть десятки тысяч сообщений
>нет ограничений на их прием

если под очередью понимается канал, то зачем вы его делаете размерностью десятки тысяч ? , ёмкость канала это и есть ограничение на приём.

Александр Пенкин

unread,
Oct 8, 2014, 3:21:00 AM10/8/14
to gola...@googlegroups.com
Нет, под очередью сообщений понимается брокер (rabbitmq в нашем случае). С этим уже разобрались.

среда, 8 октября 2014 г., 12:47:14 UTC+6 пользователь Ьу тщ написал:

Александр Пенкин

unread,
Oct 8, 2014, 3:28:17 AM10/8/14
to gola...@googlegroups.com
Спасибо, помог ответ ко второму варианту, с памятью еще разбираемся.

вторник, 7 октября 2014 г., 16:06:02 UTC+6 пользователь Dmitry Vyukov написал:
Reply all
Reply to author
Forward
0 new messages