Рубріки: Опыт

Миграция с HTTP API на GRPC: мои «за» и «против» на собственном опыте работы над проектом

Ігор Закутинський

Привет! Меня зовут Игорь Закутинский, я Head of Engineering GetProspect — украинского инструмента лидогенерации, позволяющего находить тысячи имейлов в LinkedIn за несколько кликов.

В этой статье я хочу поделиться собственным опытом миграции одного из сервисов проекта с HTTP API на GRPC, что позволило компании оптимизировать ресурсы и значительно увеличить ее производительность.

Краткий обзор платформы для лидогенерации GetProspect

Главная задача нашего сервиса — поиск электронного адреса определенного профиля в LinkedIn. Это происходит благодаря алгоритму, анализирующему данные, которые указывает пользователь в соцсети. После того, как все имейлы найдены, благодаря GetProspect можно легко управлять своими контактами в нашей CRM-системе. Для того, чтобы база электронных почт была максимально полной, пользователь дополнительно может загружать в нее данные из следующих источников:

  • Google Chrome extension;
  • CSV-файл;
  • через API;
  • интеграции со сторонними сервисами (например, Zapier);
  • Google-таблицы.

Поиск имейл-адреса, энричмент данных, экспорты и импорты — ресурсозатратные задачи. Поэтому эти процессы выполняются через очереди с определенными лимитами для равномерного распределения ресурсов сервиса между всеми пользователями.

Почему мы используем микросервисы?

Нагрузка динамическая и труднопрогнозируемая, поэтому основные требования к архитектуре сервиса — доступность и масштабируемость.

GetProspect реализован по классической микросервисной архитектуре, где каждый микросервис отвечает следующим критериям:

  • фокус на конкретные бизнес-задачи;
  • независимость от языка программирования и фреймворков;
  • простота тестирования;
  • развертывание и деплоймент конкретного сервиса не зависит от других сервисов.

Микросервисная коммуникация

Большинство сервисов должны взаимодействовать как с внутренними, так и внешними ресурсами. Поэтому одна из главных составляющих, влияющей на производительность системы — микросервисная коммуникация. 

Наши микросервисы используют HTTP RESTfull API в качестве базового протокола обмена данными. 

REST (Representational State Transfer) — это архитектурный стиль взаимодействия распределенных компонентов в сети.

Основные преимущества REST API и почему мы его используем:

  • интуитивно понятный;
  • прост в масштабировании;
  • прост в поддержке и отладке;
  • структура API не зависит от технологии и языка программирования.

HTTP REST API удовлетворяет основные потребности обмена данными между микросервисами, но из-за конструктивных особенностей не может использоваться во всех случаях.

Одна из основных задач нашего инструмента лидогенерации — поиск имейла пользователя. Поиск электронной почты основан на SMTP-диалоге с email-сервером и может занять от нескольких секунд до 10 минут. 

SMTP (Simple Mail Transfer Pro tocol) — это коммуникационный протокол для передачи электронной почты.

Процесс поиска и валидации email-адресов реализован на отдельном микросервисе — Mail verification service, а логика сохранения и управления данными — на API service

На первом этапе реализация выглядела следующим образом:

Начальная схема реализации (нажмите, чтобы рассмотреть)

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

Как видно из схемы, API service инициирует поиск имейл-адреса на Mail verification service с помощью HTTP-запроса, и через некоторое время, когда будет завершен процесс поиска, Mail verification service возвращает результат также через HTTP-запрос на API Service.

То есть для того, чтобы найти email-адрес, выполнялось как минимум два HTTP-запроса (на самом деле их было немного больше 😉), что порождало несколько проблем:

  • Во-первых, влияние на скорость и производительность. Каждый HTTP-запрос инициирует новое клиент-сервер-соединение, создающее большую нагрузку.
  • Во-вторых, это то, что запросы не имели общего контекста, поскольку в REST-архитектуре отсутствует сохранение состояния запроса (stateless), то есть сервер выполняет каждый запрос клиента независимо от предыдущих.

В качестве оптимизации мы рассмотрели использование GRPC для коммуникации этих двух микросервисов, поскольку в нем архитектурно устранены недостатки, о которых я писал выше.  

Что такое GRPC? Почему мы выбрали его для микросервисной коммуникации?

GRPC — это современный протокол RPC, реализуемый поверх HTTP/2.

HTTP/2 — это протокол уровня 7 (уровень приложений), работающий поверх TCP (уровень 4 — транспортный уровень), который работает поверх протокола IP (уровень 3 — сетевой уровень). 

У GRPC есть множество преимуществ перед традиционным HTTP/REST/JSON, например:

  • двоичный протокол (HTTP/2);
  • мультиплексирование многих запросов на одном соединении (HTTP/2);
  • сжатие заголовка (HTTP/2);
  • строго типизированный сервис и сообщение (Protobuf);
  • сериализация/десериализация данных.

Сообщения GRPC сериализируются с помощью Protobuf — эффективного двоичного формата сообщений. Protobuf быстро выполняет сериализацию на сервере и клиенте. 

Protobuf быстро выполняет сериализацию на сервере и клиенте

С помощью Protobufсериализации нам удалось значительно снизить объем полезных данных, а значит увеличить пропускную способность между API-сервисом и сервисом, который процессит поиск email-адресов.

Также значительно упростилась логика поиска. На стороне API service процесс поиска имейла выглядит как вызов асинхронной функции (удаленной процедуры в случае gRPC 😉).

Тест производительности: GRPC vs HTTP Restful API

Я решил провести тест, для которого использовался два AWS EC2 c5.2xLarge instance, на которых были запущены Node.js application — клиент и сервер.

В этом тесте клиент делает простой запрос на сервер или вызывает процедуру, а сервер просто возвращает значение без какой-либо сложной логики, поскольку цель — определить производительность протокола. В тесте определяется количество возможных запросов за единицу времени (1 секунду, а также время на выполнение 100к запросов или вызовов процедур).

gRPC server, который использовался для теста:

Нажмите для просмотра

gRPC client, который использовался для теста:

Нажмите для просмотра

Для теста HTTP Rest API реализована аналогичная логика на Fastify и Axios.  

Результаты теста:

HTTP Post request gRPC procedure call
100k async requests, sec 32.342 4.370
Requests per second 2147 26102
CPU usage – ms/req 491 ms / per request 211 ms / per request

Как видно из графика, пропускная способность GRPC более чем в восемь раз выше HTTP API, что значительно повышает производительность на больших объемах запросов. Также следует отметить то, что CPU-время на 1 gRPC-процедуру более чем в два раза меньше, чем на аналогичный HTTP-запрос. 

Балансировка нагрузки

Поскольку общая нагрузка на сервис постоянно меняется, возникает необходимость масштабирования каждого отдельного микросервиса, и, соответственно, балансировка нагрузки между ними. Балансировка GRPC-сервисов несколько сложнее балансировки сервисов с HTTP-сервером. 

Существует два основных подхода к GRPC-балансировке: 

  • на стороне клиента;
  • балансировка через proxy-сервер.

Преимущество клиентской балансировки — прямое соединение клиент-сервер, обеспечивающее минимальное время обмена сообщениями. Тем не менее при таком подходе есть много минусов, из-за которых мы отказались от такой реализации, а именно:

  • сложность реализации клиента;
  • клиент отслеживает нагрузку и доступность сервера;
  • необходимость реализации и поддержания алгоритма балансировки.

Эти проблемы значительно усложняются при росте числа клиентов.

В нашем случае балансировка реализована через Haproxy, что значительно упрощает реализацию и полностью удовлетворяет нашим требованиям по производительности. 

Балансировка через Haproxy / Нажмите, чтобы рассмотреть

Безопасность в GRPC-микросервисах

GRPC поддерживает SSL/TLS encryption, что позволяет шифровать данные, которыми обменивается клиент и сервер. Также GRPC предоставляет простой Auth API, позволяющий предоставить авторизационные данные при создании канала или вызове функции.

Пример авторизации через SSL/TLS-сертификаты:

const cert = fs.readFileSync('path/to/cert');
const ssl = grpc.credentials.createSsl(cert);
const stub = new service.Verification('grpc.service.com', ssl);

Слабые стороны GRPC

Браузерная поддержка

К сожалению, сегодня не существует полноценной браузерной поддержки GRPC, поэтому его не стоит использовать для служб, вызываемых непосредственно из браузерных приложений.

Недоступно для чтения человеком

Запросы HTTP Rest API отправляются в текстовом виде (JSON), что позволяет разработчикам их легко читать и редактировать. gRPC использует двоичный протокол Protobuf, что значительно эффективнее, но не читаемо человеком, что затрудняет и замедляет процесс отладки и разработки.

Выводы

На сегодня GRPC — перспективное решение для микросервисов, где необходима высокая пропускная способность. Его использование позволило нам оптимизировать bottleneck нашей системы, значительно сократить расходы на трафик и увеличить производительность. 

Тем не менее из-за сложности в реализации, а также отсутствия полноценной браузерной поддержки мы не можем рассматривать GRPC как полноценного конкурента HTTP REST API. 

Делитесь вашими мыслями, мигрировали ли вы с HTTP API на GRPC, и каковы результаты?

If you have found a spelling error, please, notify us by selecting that text and pressing Ctrl+Enter.

Останні статті

Токсичные коллеги. Как не стать одним из них и прекратить ныть

В благословенные офисные времена, когда не было большой войны и коронавируса, люди гораздо больше общались…

07.12.2023

Делать что-то впервые всегда очень трудно. Две истории о начале карьеры PM

Вот две истории из собственного опыта, с тех пор, когда только начинал делать свою карьеру…

04.12.2023

«Тыжпрограммист». Как люди не из ІТ-отрасли обесценивают профессию

«Ты же программист». За свою жизнь я много раз слышал эту фразу. От всех. Кто…

15.11.2023

Почему чат GitHub Copilot лучше для разработчиков, чем ChatGPT

Отличные новости! Если вы пропустили, GitHub Copilot — это уже не отдельный продукт, а набор…

13.11.2023

Как мы используем ИИ и Low-Code технологии для разработки IT-продукта

Несколько месяцев назад мы с командой Promodo (агентство инвестировало в продукт более $100 000) запустили…

07.11.2023

Университет или курсы. Что лучше для получения IT-образования

Пару дней назад прочитал сообщение о том, что хорошие курсы могут стать альтернативой классическому образованию.…

19.10.2023