За последние 6 месяцев мы увидели огромный рост Magicpin. Количество пользователей и продавцов выросло в 6 раз, а среднее время сеанса выросло более чем на 50%. Весь этот рост привел к экспоненциальному увеличению генерируемых данных - транзакций, обзоров, лайков, селфи, чек-инов, погашения ваучеров и многого другого. С самого начала мы осознали, насколько важны эти данные для обеспечения взаимодействия с пользователем. От поиска лучших ресторанов на основе интересов пользователей до персонализации сделок с возвратом денег для наших пользователей - это данные, которыми они пользуются, и многое другое. В этом посте мы сосредоточимся на важнейшем компоненте создания этих функций - надежной и масштабируемой системе для обработки и приема различных потоков данных и предоставления рекомендаций, созданных на их основе.

Как и у многих компаний, занимающихся потребительскими технологиями, у нас есть несколько потоков данных с разными источниками происхождения и разной величины. Мы хотели создать систему, которая могла бы обрабатывать все из них, от данных о потоках кликов, генерируемых приложением и сайтом, до транзакций, выполняемых пользователем и ваучерами, сделок, заключенных этими пользователями. Мы также хотели изолировать вышестоящие системы от этой системы приема потоков и гарантировать, что вышестоящие системы работают в режиме запустил и забыл. Учитывая наше использование и рост, нам нужно, чтобы система могла обрабатывать тысячи запросов в лучшем случае параллельно (в худшем - одновременно) и поддерживать асинхронные вызовы. Архитектура, которая действительно впечатлила нас, была Keystone Pipeline в Netflix. Поскольку потоковая обработка была центральной, мы быстро остановились на Kafka в качестве центральной очереди. Кроме того, как и в блоге выше, мы предпочитали восходящие системы для передачи данных через HTTP и избегали записи напрямую в Kafka, поскольку это означало бы множество изменений в вышестоящих сервисах, особенно в отношении обработки ошибок, повторных попыток и выполнения асинхронных вызовов. Кроме того, мы представили конечную точку веб-сокета, чтобы приложение могло отправлять данные в реальном времени в систему без накладных расходов HTTP. Что касается хранения данных, мы решили использовать Cassandra и Elastic. На основе этих хранилищ данных мы создали наш механизм персонализации и рекомендаций, который генерирует рекомендации с использованием библиотеки машинного обучения Spark. Подробнее о нашей системе рекомендаций мы расскажем в отдельном посте.

В magicpin у нас большой опыт масштабирования приложений MVC на основе Java. В то же время мы также знали, насколько требовательной может быть настройка JVM, и, как компания, мы прилагаем все усилия, чтобы оставаться на вершине новых и появляющихся технологий, и постоянно спрашивать себя, можем ли мы делать это лучше? Обсуждая реализацию этой системы, мы поняли, что язык с параллелизмом и параллелизмом с нуля может быть лучше. Дальнейшие исследования привели нас к замечательному докладу Параллелизм - это не параллелизм и вдохновили на дальнейшее изучение Go. Основы Golang и то, как такие конструкции, как каналы, делают параллельное программирование более элегантным, взволновали нас, и после прочтения этого сообщения в блоге - Обработка 1 миллиона запросов в минуту с помощью golang мы убедились, что Golang - это путь идти!

Пару недель спустя, после первоначального ускоренного курса на Голанге, мы были более впечатлены тем, насколько элегантным и эффективным (как с точки зрения кода, так и с точки зрения производительности) был Голанг. Мы начали моделировать нашу архитектуру и черпали вдохновение из замечательной статьи Malwarebyte в Golang и придумали архитектуру пула рабочих, которая передавала данные из исходных источников через Kafka в ES и Cassandra. Мы написали задания Spark поверх этих данных и записали полученные рекомендации обратно в Elastic / Cassandra.

Служба приема данных построена на основе пула рабочих HTTP и делегатора / маршрутизатора, который передает входящие задания незанятым рабочим. Каждый воркер запускает свою собственную процедуру Go, отправляя данные в тему Kafka. Как только работа завершена, она возвращается в пул. Просто и эффективно. В сочетании с эффективным и действенным хранилищем NoSQL (Cassandra хорошо сработала для нашего варианта использования), мы должны обрабатывать 5 тыс. Запросов / с на каждой машине с 4 виртуальными ЦП. Помимо приема данных, разные потребители размещаются на наших HTTP-серверах. Эти потребители выполняют ряд операций, таких как очистка, массирование и агрегирование данных, прежде чем направить их в конвейер рекомендаций и / или другие приемники данных (например, ES).

REST API, который предоставляет выходные данные механизма рекомендаций / персонализации, использует мультиплексный пакет Golang Gorilla для маршрутизации и отправки. Пакет http, который используется Gorilla (и практически всеми другими веб-фреймворками для Golang), гарантирует, что на каждый HTTP-запрос будет приходиться одна подпрограмма Go. На стороне API мы могли бы получить один экземпляр 1 vCPU для обслуживания 600 запросов / с.

Все наши приложения Golang созданы с использованием методологии двенадцатифакторных приложений, что упрощает их контейнеризацию с помощью Docker. Чтобы еще больше оптимизировать стоимость нашего оборудования, мы развертываем эти контейнеры в Kubernetes и используем автоматическое масштабирование для раскрутки контейнеров по запросу при скачках трафика.

Наш переход и эксперимент с Golang оказались очень плодотворными. Мы начали смотреть, можем ли мы переместить другие микросервисы и промежуточное ПО из нашего стека в Golang. В то же время мы понимаем, что Голанг - не серебряная пуля. Мы внимательно смотрим на наши услуги и все время задаем один фундаментальный вопрос - может ли это быть лучше? Это постоянно развивающийся процесс, требующий тщательного исследования и планирования. По мере того, как мы продолжаем расти, мы рады выяснить, как увеличить эти услуги в 10 раз по сравнению с текущим уровнем. Напишите нам, если у вас есть вопросы о том, что мы сделали, или вы хотите рассказать нам, как мы могли бы сделать что-то лучше? Если вы хотите приехать и строить вместе с нами, даже лучше!