Що таке gRPC і як він працює
Зміст
Настав час розібратися, що таке gRPC — у чому принцип його роботи і які переваги перед звичним REST API.
Розроблений в 2016 році компанією Google фреймворк gRPC швидко став популярним і сьогодні активно використовується як у самому Google, так і в ряді великих проектів, серед яких, наприклад, Netflix, Cisco, Dropbox, Spotify та ін. Система виклику віддалених процедур gRPC є альтернативою звичному REST API, її доцільно розглядати в контексті мікросервісів. gRPC часто можна зустріти там, де доводиться обслуговувати велику кількість клієнтів. Останнім часом великі проекти активно переходять на мікросервісну архітектуру і все більше компаній сприймають gRPC як основний стандарт передачі даних замість REST API. Як він працює і в чому його перевага?
Принцип роботи gRPC
Ідея gRPC не нова – парадигма, яку використовує даний фреймворк, вже давно відома, вона ґрунтується на RPC (віддаленому виклику процедур). За допомогою RPC відбувається комунікація між клієнтом та сервером, для якої використовується не HTTP-запрос, а виклик функції. Клієнт викликає віддалену процедуру, серіалізує параметри та додаткову інформацію у повідомленні, після чого надсилає повідомлення на сервер. Прийнявши дані, сервер здійснює їх десеріалізацію, виконує потрібну операцію і надсилає результат назад клієнту. Такі об’єкти як stub сервера та stub клієнта беруть на себе функції серіалізації та десеріалізації параметрів.
Розглянемо наступний приклад – у нас є велика монолітна програма, яка має єдиний загальний модуль і яка працює на одному сервері. Поступово ця програма розвивається, додаються нові можливості, з’являються нові опції. В міру розростання монолітного додатку, вносити до нього зміни стає все важче, масштабування проекту не можливе. Додаткові можливості програми, нові функції – помітно збільшують навантаження на сервер, а тому вимагають все більше апаратних потужностей. До певного моменту цих потужностей вистачатиме. Але рано чи пізно доведеться зіткнутися з проблемою обмеженості ресурсів сервера. Потужність комп’ютера не можна збільшувати до нескінченності і в якийсь момент досягається рівень, який обмежує вертикальне масштабування проекту.
Для розв’язання цієї проблеми використовують розподіл монолітного додатка на окремі, невеликі, слабо пов’язані маленькі додатки – мікросервіси. Кожен такий мікросервіс – це автономна програма. Мікросервіси спілкуються один з одним і взаємодіють, виконуючи функції підсумкового додатка. Якщо у випадку монолітної архітектури користувач звертається до додатку і отримує відповідь, то з мікросервісною архітектурою він звертається до мікросервісу. Цей мікросервіс, у свою чергу, звертається до іншого мікросервісу, який, наприклад, може звернутися до третього мікросервісу або бази даних і т.д. Спілкуючись між собою за допомогою програмного інтерфейсу API, сукупність мікросервісів формує весь додаток повністю.
Навіщо це потрібно? Коли виникає потреба в масштабуванні, окремі мікросервіси можна розмістити на різних серверах, виконавши таким чином горизонтальне масштабування. Збільшувати число вузлів можна практично нескінченно, тому для масштабування програми мікросервісна архітектура більш зручна в порівнянні з монолітною реалізацією. Тим більше, що монолітна архітектура при масштабуванні набуває дуже об’ємного коду в якому розробнику складно розбиратися.
Крім того, коли ми вносимо зміни до монолітного додатку, через велику кількість зв’язків між різними його частинами, це може спричинити зміну тих чи інших модулів. У мікросервісній архітектурі програма декомпозована на безліч додатків — тому вносити зміни лише в якийсь певний модуль відносно легко і безпечно.
Однак мікросервісна архітектура має і мінуси. Чим більше мікросервісів використовується в проекті, тим більше програмних інтерфейсів API необхідно створювати, забезпечуючи взаємодію мікросервісів.
Стандартний спосіб реалізації API та організації спілкування з додатками – за допомогою REST API. Коротко це виглядає так: є клієнт та сервер, який має доступ до бази даних. Клієнт посилає якийсь HTTP-запит із певним методом, передаючи (або не передаючи) дані JSON. Сервер приймає цей HTTP-запит і відправляє відповідь (зазвичай, теж у форматі JSON або, рідше – у вигляді XML). Один із недоліків REST API полягає в тому, що для окремої мови програмування потрібно створювати свій код API. Всі мови програмування мають власні бібліотеки для розробки API, і щоразу код доводиться писати вручну. Звичайно, можна генерувати код за допомогою сторонніх інструментів (наприклад, Swagger), але стандартного способу виконати це в REST API – на жаль, немає.
Інша незручність REST API полягає в тому, що формат даних, що використовується для пересилання даних, – не бінарний, а текстовий. Такий формат зручний для візуального ознайомлення зі вмістом, однак він ніяк не оптимізується, не стискається при передачі. Відповідно розмір повідомлення, що передається, виходить великий і час на його відсилання збільшується. Якби дані були бінарними, ми могли б застосувати до них оптимізацію.
Ну, і третій недолік REST API полягає в тому, що транспортний протокол, що застосовується у передачі – HTTP 1.1. Як наслідок – організація стримінгу потокових даних ускладнена.
Переваги gRPC
Перераховані вище недоліки були усунені в gRPC, завдяки чому фреймворк стрімко набув популярності. Система обміну повідомленнями gRPC використовує замість JSON бінарний формат Protobuf, завдяки чому розмір повідомлень стає меншим і збільшується пропускна здатність – швидкість передачі в кінцевому підсумку зростає в 7-10 разів. Цей формат підтримує строгу типізацію, однак, для його читання необхідно декодувати повідомлення, а для надсилання – кодувати.
Буфер протоколу Protobuf дозволяє зберігати свої дані та функціональні контракти у вигляді proto файлу. Клієнт і сервер повинні зберігати той самий proto файл, він діє як посередницький договір клієнта для виклику будь-яких доступних функцій з сервера. Для proto файлів використовують мову опису інтерфейсів (IDL). У proto файлі ми описуємо типи даних, формат повідомлень і ті операції RPC, які передбачається використовувати в додатку. Скажімо, для опису структури даних повідомлення потрібно додати message, ім’я структури, всередині тип, ім’я та номер поля. На відміну від Protobuf, JSON не має суворої типізації – ключу “timestamp” може відповідати і рядок, і число. У Protobuf можна вказати, що якась колонка (“timestamp”) – це ціле число. При пересиланні масиву об’єктів JSON спостерігається надмірність — багаторазово передаються ті самі ключі (“timestamp” і “url”), в Protobuf надмірності немає.
У gRPC є стандартні засоби для генерації коду різними мовами програмування – компілятор protoc перекладає мову, яку ми використовуємо в proto файлі, на будь-яку з популярних мов програмування, включаючи Python, Java, C++, Golang і т.д.
Бінарний формат, що використовується в gRPC, транслюється через протокол HTTP 2, завдяки чому швидкість обміну даними (згідно з окремими тестами) збільшується на 14 відсотків. У HTTP 2 добре реалізовані потоки даних (можна запитувати сервер і отримувати від нього потік даних по каналу клієнт-сервер).
Типи RPC
Завдяки мультиплексуванню на HTTP 2, реалізація стрімінгу потокових даних не є проблемою. Розрізняють наступні види RPC:
- RPC потокової передачі сервера – клієнт надсилає один запит, а сервер посилає серію відповідей. Приклад використання – коли клієнт надсилає запит на домашню сторінку зі списком елементів, а сервер відправляє відповіді окремо, завдяки чому для клієнта можливе відкладене завантаження.
- Клієнтський стрімінг RPC – клієнт відправляє серію запитів, а сервер відправляє лише одну відповідь.
- Двонаправлений потоковий RPC – відправлення з боку клієнта і сервера відбувається одночасно, не чекаючи відповіді.
- Варіант коли клієнт надсилає один запит і повертає одну відповідь називається – унарним RPC.
Коли надходить кілька запитів до сервера (ситуація є актуальною, наприклад, при потоковій передачі), на сервері можна скасувати виклик gRPC, якщо відповідь не потрібна.
Коли доцільно використовувати gRPC
Незважаючи на те, що gRPC багато в чому зручний, є низка умов, за яких доцільніше відмовитись від нього на користь REST API. gRPC не підтримується у браузері, тому для монолітної програми, до якої має бути клієнтський доступ запитів ззовні або через браузер, слід використовувати звичайний API REST.
Якщо програма використовує архітектуру мікросервісів, де численні мікросервіси спілкуються один з одним, то вибір слід робити вибір на користь gRPC. У цьому випадку у вас можуть використовуватися різні мови програмування (що, втім, не є проблемою і для REST API, якщо використовувати Swagger), а також велика кількість передач повідомлень. Відповідно до gRPC ви можете використовувати автоматичну генерацію коду та отримаєте більш високу швидкість роботи порівняно з REST API. Також gRPC є актуальним у випадках, коли необхідний стрімінг даних.
Перехоплювачі (Interceptors) та балансування навантаження
В арсеналі gRPC є механізм розширення, який називається перехоплювач (interceptor). Коли потрібно змінити запит або відповідь перед передачею, можна перехопити виклик і змінити його (аналог проміжного ПЗ в REST API). Interceptors зручно використовувати для логування запитів, збору метрик, аутентифікації та ін.
Також gRPC підтримує механізм балансування навантаження клієнта – він уже реалізований за допомогою бібліотеки Golang.
Висновок
Тепер ви маєте уявлення про те, що таке gRPC, які у нього переваги та особливості роботи, в яких випадках даний фреймворк застосовується. Для більш детального занурення у тему рекомендуємо вам переглянути вебінар, на якому будуть розглянуті технології gRPC та REST на основі реального проекту.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: