Skip to main content

Технологія мікросервісів

Мікросервісна архітектура - це підхід до розробки програмного забезпечення, який полягає у створенні набору невеликих, незалежних служб, кожна з яких виконує певну функцію та спілкується з іншими через легко визначені інтерфейси, зазвичай через API. Кожен мікросервіс є самостійним та може бути розроблений, розгорнутий, працювати та масштабуватися незалежно від інших частин системи. Цей підхід може поліпшити модульність, спростити масштабування та сприяти неперервному впровадженню нових функцій.

Для розробки мікросервісів використовується технологія gRPC, яка дозволяє легко та швидко створити легкомаштабовані сервіси, які використовують протокол HTPP/2 для передачі інформації.

GRPC Python

Для розробки мікросервісів використовується мова програмування python та набір фрейморків для роботи з gRPC.

gRPC - це сучасна високопродуктивна платформа Remote Procedure Call (RPC) з відкритим кодом, яка може працювати в будь-якому середовищі. Дана технологія рохроблена компанією GOOGLE. У якості файлів з описом структур даних, які будуть передаватись, використовується технологія Protocol Buffers

До списку використаних розширень мови програмування входять:

  • grpcio - основний фреймворк для створення gRPC-сервісів
  • grpcio-tools - консольна ультиліта. Використовується для генерації описових файлів сервісу з .proto-файлів
  • protobuf - бібліотека роботи з .proto-файлами для мови програмування python

Структура проєктів мікросервісів

microservise_name/
├── venv/
├── test_files/
├── server_code.py
├── service_description.proto
├── start_server_script.sh
├── Dockerfile or docker-compose.yml
├── requiremets.txt
├── changelog.md
└── README.md

Опис компонентів проекту:

  • venv/ - віртуальне середовище
  • test_files/ - тека з файлами для тестування (якщо потрібні)
  • server_code.py - код сервера
  • service_description.proto - код опису функціонала сервісу
  • start_server_script.sh - скрипт ініціалізації сервісу
  • Dockerfile or docker-compose.yml - опис контейнера для сервісу
  • requiremets.txt - опис залежностей python
  • changelog.md - опис змін версій
  • README.md - опис сервісу

Protocol Buffers

Protocol Buffers (Protobuf) - це мовно-нейтральний, платформо-незалежний інструмент для серіалізації структурованих даних, розроблений Google. Він використовується для обміну даними між сервісами та системами. Protobuf пропонує більш ефективний і компактний спосіб, ніж традиційні формати обміну даними, як-от XML чи JSON, забезпечуючи швидше кодування та декодування даних.

Особливості які можна виділити:

  • Ефективність - protobuf оптимізований для низької витрати ресурсів і швидкого обміну даними
  • Переносимість - сумісний з багатьма мовами програмування і платформами
  • Простота використання - легко інтегрується з різними мовами програмування
  • Розширюваність - схеми даних можуть бути модифіковані без порушення сумісності з уже існуючими даними

Приклад опису сервісу за допомогою protobuf:

syntax = "proto3";

package example;

// Сервіс для керування користувачами
service UserService {
// Додавання нового користувача
rpc AddUser (AddUserRequest) returns (UserResponse);

// Отримання інформації про користувача
rpc GetUser (UserRequest) returns (UserResponse);
}

// Запит для додавання користувача
message AddUserRequest {
string name = 1;
string email = 2;
}

// Запит для отримання інформації про користувача
message UserRequest {
int32 user_id = 1;
}

// Відповідь з інформацією про користувача
message UserResponse {
int32 user_id = 1;
string name = 2;
string email = 3;
}

Компіляція protobuf

Відповідно до документації фреймворку grpcio, компіляція protobuf виконується за допомогою виконання команди:

python3 -m grpc_tools.protoc -I . --python_out=. --pyi_out=. --grpc_python_out=. <proto_file_path>

Створення функцій сервісу

Для створення функцій сервісу створюється окремий скрипт, який буде виконувати роль сервера. Всередині цього срипта обов'язково повинні бути наступні сніпети:

def server(port=4003):
server_opt = [('grpc.max_send_message_length', 512 * 1024 * 1024),
('grpc.max_receive_message_length', 512 * 1024 * 1024)] # Опис налаштуванб сервера
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10), options=server_opt) # Cтворення об'єкта сервера з максимальною кількістю паралельних воркерів 10
convertp_pb2_grpc.add_ConvertServicer_to_server(
Convert(), server) # Додавання описаних функцій до сервісу
server.add_insecure_port(f'[::]:{port}') # Встановлення каналу передачі даних для сервісу (налаштування робочої ip адреси та порта)
server.start() # Запус сервера
print(f'Server is runnig on port {port}')
server.wait_for_termination() # Запус циклу сервера

Приклад опису функції сервісу:

class MyServiceServicer(MyServiceServicer):
def MyFunction(self, request, context):
# Використання request
data = request.some_field

# Перевірка відміни запиту
if context.is_active():
# Обробка даних
pass
else:
# Обробка відміни
context.set_code(grpc.StatusCode.CANCELLED)
context.set_details('Request cancelled by the client')

return MyResponse()

⚠️ Warning

Усі функції описуються всередині відповідного класу, який наслідує клас, який згенерований з опису сервісу. Приклад класу:

class MyServiceServicer(MyServiceServicer):
# Опис функціоналу сервісу

Опис параметрів функцій сервера

1. request

request - це параметр, який містить дані, відправлені клієнтом до сервера. Властивості та тип request визначаються за допомогою файлів .proto, де описуються повідомлення та сервіси gRPC. Особливості:

  • Тип даних: Тип request відповідає типу вхідного повідомлення, яке було визначено у файлі .proto для даної RPC-функції.
  • Використання: request використовується для доступу до даних, які клієнт хоче передати серверу. Наприклад, якщо ви маєте RPC-функцію GetUser, яка приймає GetUserRequest, то ви можете отримати доступ до даних користувача через request.user_id або подібні поля.
2. context

context - це параметр, що надає метадані, контрольні можливості та інші можливості, пов'язані з обробкою поточного RPC-виклику. Особливості:

  • Контроль таймаутів та відмін: За допомогою context сервер може перевіряти, чи було відмінено запит або чи минув час очікування.
  • Метадані: Дозволяє отримувати та відправляти метадані, які супроводжують RPC-виклики.
  • Авторизація: Може використовуватися для перевірки даних авторизації, наприклад, токенів доступу.
  • Відповіді на помилки: Через context можна відправляти специфічні для gRPC помилки та повідомлення про статус.

Контейнеризація сервісу

Для стабільної роботи сервісів вони пакуються у Docker контейнери. Налаштування контейнера описуються у файлі Dockerfile або docker-compose.yml.

Документація зі створення контейнерів знаходиться за посиланням

GRPC Node JS

Для роботи з сервісом gRPC з сторони Node JS використовуються наступні залежності:

  • @grpc/grpc-js - складова пакету grpc для роботи та створення gRPC сервісами
  • @grpc/proto-loader - складова пакету grpc для роботи з .proto файлами

Налаштування підключення

Через те, що усі мікросервіси працюють віддалено - то виникає потреба у конфігурації підключення до сервісу.

Усі підключення описуються всередині конфігураційного файлу додатку Node JS configServer.json:

{
"<serverName>ServerAddress": "<ip>:<port>"
}

Структура тек з описом сервісу

grpc/
├── service_name.js
└── service_name.proto

Опис компонентів проекту:

  • service_name.js - код клієнта сервісу
  • service_name.proto - опис сервісу (повна копія файлу з проекту сервісу)

Опис функцій клієнту

Кожен опис клієнту у Node JS повинен мати наступні сніпети коду:

const convertClient = convertServerAddress ? new proto.Convert(
convertServerAddress,
grpc.credentials.createInsecure(),
{
'grpc.max_send_message_length': 512 * 1024 * 1024,
'grpc.max_receive_message_length': 512 * 1024 * 1024,
},
) : null;

Приклад опису функції:

onst pdfMerge = convertServerAddress ? async (data) => new Promise((res, rej) => {
convertClient.pdfMerge(data, (err, data) => {
if (err) {
return rej(err);
}
res(data);
});
}) : null;

Усі функції клієнта працюють через Promise та повертають помилку у якості reject, який емітить throw new Error