[Перевод] Qihoo 360 и Go

image

Предлагаю вашему вниманию перевод гостевого поста из блога Go от лица Yang Zhou, в данный момент занимающего позицию инженера в Qihoo 360.

Qihoo 360 является лидирующим поставщиком антивирусных продуктов для интернета и мобильных устройств в Китае, контролирует крупную платформу дистрибьюции мобильных приложений для Android (магазин приложений). На конец июня 2014 года Qihoo пользовались 500 миллионов активных пользователей ПК в месяц и свыше 640 миллионов пользователей мобильных устройств. У Qihoo также имеется свой браузер и поисковый движок, оба не менее популярны среди китайцев.
Моя команда, отдел push-сообщений, предоставляет фундаментальный сервис обмена сообщениями для более чем 50 приложений среди продуктов компании (как для ПК, так и для мобильных устройств), а также тысячам сторонних приложений, использующих нашу открытую платформу.

Наш «роман» с Go берёт своё начало в 2012 году, когда мы пытались наладить работу push. Самый первый вариант представлял из себя связку nginx + lua + redis, но производительность под серьёзной нагрузкой не подошла под наши требования. Во время очередного поиска правильного стека наше внимание привлёк свежий релиз Go 1.0.3. Мы изготовили прототип буквально за несколько недель, во многом благодаря горутинам (легковесные потоки) и го-каналам (типизированные очереди), которые являются примитивами языка.

Изначально наша гофернутая система была развёрнута на 20 серверах, обслуживая в общем 20 миллионов активных соединений. Она справлялась с отправкой всего 2 миллионов сообщений в день. Сейчас же система развёрнута на 400 серверах, поддерживает 200+ миллионов активных соединений и обеспечивает отправку более чем 10 миллиардов сообщений ежедневно.

Параллельно со стремительным ростом бизнеса и повышением требований к сервису push-сообщений изначальная система на Go быстро упёрлась в лимиты: размер кучи достигал 69G, паузы GC составляли по 3–6 секунд. Более того, мы перезагружали наши сервера еженедельно для освобождения памяти. Если честно, думали даже избавиться от Go и переписать всё ядро на C. Однако, вскоре планы поменялись: затык произошел во время переноса бизнес логики. Одному человеку (мне) невозможно было осилить поддержку системы на Go, параллельно обеспечивая портирование бизнес логики на C.

Так что я принял решение остаться с Go (и на мой взгляд — это самое мудрое из всех, что я мог тогда принять) и качественный прогресс пришёл довольно скоро.

Вот несколько приёмов и оптимизаций:

  • Повторно использовать HTTP соединения (пул соединений), во избежание создания новых объектов и буферов во время взаимодействия;
  • Повторно использовать объекты и выделенную память, для уменьшения нагрузки на GC;
  • Использовать группы продолжительно живущих горутин для обработки очередей задач или сообщений, полученных от
    горутин подключений. Т.е. классический pub/sub вместо порождения множества горутин, по одной на каждый входящий запрос;
  • Мониторить и контролировать количество горутин в процессе. Отсутствие контроля может привести к появлению непосильной нагрузки на GC из-за скачка в количестве создаваемых горутин. Например, если допустить бесконтрольное создание горутин для обработки запросов извне, то блокировка только что созданных вследствие обращения к внутренним сервисам, например, приведёт к созданию новых горутин и так далее;
  • Не забудьте указать дедлайны на чтение и на запись для сетевых соединений при работе с мобильной сетью, иначе горутины могут заблокироваться. Однако, применяйте их осторожно с LAN сетью, иначе эффективность RPC-взаимодействия может пострадать;
  • Использовать при необходимости HTTP Pipelining.

image

В результате получилось три итерации нашей архитектуры, две итерации RPC фреймворка, даже с ограниченным количеством людей для реализации. Я бы отнёс это достижение к удобству разработки на Go. Привожу свежую диаграмму нашей архитектуры:

image

Результат непрерывных улучшений и доработок в виде таблицы:

image

И, что не менее круче, заодно мы разработали платформу для профилирования Go программ в реальном времени (Visibility Platform). Теперь мы имеем доступ к статусу системы и диагностической информации, предвидя любые неполадки.

Скриншоты:

image
image

Из замечательного: с этим инструментом мы можем симулировать подключение и поведение миллионов пользователей, используя модуль Distributed Stress Test Tool (также написан на Go), наблюдать за результатами в реальном времени и с визуализацией. Это позволяет нам изучать эффективность любого нововведения или оптимизации, предотвращая любые проблемы с производительностью в боевых условиях. Практически любая возможная оптимизация системы уже была опробована нами. И мы с нетерпением ждём хороших новостей от команды, отвечающей за GC в Go, они могли бы избавить нас от лишней работы с оптимизацией кода под GC в дальнейшем. Я также допускаю, что наши ухищрения скоро станут попросту рудиментарными, поскольку Go продолжает развиваться.

Я хочу завершить эту историю благодарностью за возможность участвовать в Gopher China. Это было торжественное мероприятие, позволившее нам узнать многое, поделиться своими знаниями, проникнуться популярностью и успехом Go в Китае. Большое количество команд в Qihoo уже успели ознакомиться с Go и даже попробовать. Я убеждён, что скоро ещё больше китайских интернет-компаний присоединятся к тренду и перепишут свои системы на Go, таким образом усилия команды, стоящей за Go, принесут пользу огромному количеству разработчиков и компаний в ближайшем будущем.

© Habrahabr.ru