1. Чому мікросервіси в .NET Core?
Перш ніж зануритися в REST або gRPC, давайте встановимо контекст: .NET Core (тепер просто .NET) — це кросплатформений, високопродуктивний та модульний фреймворк, який спрощує створення мікросервісів. Підхід мікросервісів полягає в розробці малих, незалежно розгортаних сервісів, які взаємодіють через легкі протоколи.
Основні переваги мікросервісів
- Незалежне розгортання: Оновлюйте сервіси окремо, не перезавантажуючи всю програму.
- Масштабованість: Масштабуйте лише «гарячі» сервіси горизонтально.
- Ізоляція: Кожен сервіс може використовувати власний стек технологій чи базу даних.
Зауваження з реального світу: Мікросервіси часто вносять складності, такі як затримки в мережі, розподілені транзакції та виявлення сервісів. Переконайтесь, що ваша команда та інфраструктура готові до цих викликів, перш ніж приступити.
2. Що таке REST і gRPC?
REST (Representational State Transfer)
- Протокол: Зазвичай використовує HTTP/1.1 або HTTP/2.
- Формат даних: JSON або XML.
- Стиль: Точки доступу на основі ресурсів (
GET /api/products
). - Переваги: Широко підтримується, легко тестується, зрозумілий для людини.
- Недоліки: Можуть бути великі корисні навантаження (JSON), немає вбудованого жорсткого контролю схеми.
gRPC (Google Remote Procedure Call)
- Протокол: Використовує HTTP/2 (або HTTP/3 з новішими інструментами), підтримує стрімінг.
- Формат даних: Бінарний (Protocol Buffers).
- Стиль: На основі RPC; визначення сервісів і повідомлень у файлах
.proto
. - Переваги: Висока продуктивність, строгі контракти, підтримка стрімінгу.
- Недоліки: Бінарний формат менш зрозумілий для людини; не так широко застосовується для публічних/зовнішніх API (хоча це змінюється).
3. Як вибрати між REST і gRPC
Коли використовувати REST:
- Публічні API з різноманітними клієнтами.
- Потрібен «людинозрозумілий» формат (JSON).
- Потрібні потужні інструменти спільноти (Swagger, Postman).
Коли використовувати gRPC:
- Висока пропускна здатність, низька затримка для внутрішньої комунікації.
- Строго типізовані контракти і стрімінг.
- Хочете використовувати можливості HTTP/2 (мультиплексування, контроль потоку).
Порада від професіонала: Багато архітектур використовують обидва підходи. Для зовнішніх або публічних точок доступу REST все ще є королем. Для внутрішньої комунікації між сервісами gRPC може бути великою вигодою.
REST в .NET Core
Налаштування
dotnet new webapi -n MyAwesomeRestService
cd MyAwesomeRestService
Контролери та Точки Доступу
У файлі Controllers/ProductsController.cs
:
using Microsoft.AspNetCore.Mvc;
namespace MyAwesomeRestService.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
// GET: api/Products
[HttpGet]
public IActionResult GetAllProducts()
{
return Ok(new[]
{
new { Id = 1, Name = "Laptop", Price = 999.99 },
new { Id = 2, Name = "Headphones", Price = 199.99 }
});
}
// GET: api/Products/{id}
[HttpGet("{id}")]
public IActionResult GetProductById(int id)
{
if (id == 1)
return Ok(new { Id = 1, Name = "Laptop", Price = 999.99 });
else
return NotFound();
}
// POST: api/Products
[HttpPost]
public IActionResult AddProduct([FromBody] Product product)
{
// У реальному додатку збереження в базі даних
return CreatedAtAction(nameof(GetProductById), new { id = product.Id }, product);
}
}
public class Product
{
public int Id { get; set; }
public string? Name { get; set; }
public double Price { get; set; }
}
}
Обробка Помилок у REST
У .NET 6+
можна використовувати Middleware або підхід UseExceptionHandler для обробки глобальних помилок:
app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
// Логування помилки або серіалізація власного об'єкта помилки
await context.Response.WriteAsync("{ \"error\": \"Сталася непередбачувана помилка.\" }");
});
});
Версійність RESTful API
Ви можете версіонувати свої точки доступу API, щоб дозволити безперервні оновлення:
dotnet add package Microsoft.AspNetCore.Mvc.Versioning
У Program.cs
:
builder.Services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
});
Потім додаємо атрибути до контролерів:
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ProductsController : ControllerBase { ... }
Приклад: Сервіс для електронної комерції
- Зовнішні клієнти (Web, Mobile) звертаються до
https://yourdomain.com/api/v1/products
для отримання списку товарів, створення, оновлень тощо. - Досвід розробника: Легко тестується за допомогою Swagger та Postman.
- Масштабованість: Масштабування горизонтально під час пикових навантажень — особливо під час святкових розпродажів.
5.
gRPC в .NET Core
Налаштування
dotnet new grpc -n MyAwesomeGrpcService
cd MyAwesomeGrpcService
Опис файлу .proto
Protos/orders.proto
:
syntax = "proto3";
option csharp_namespace = "MyAwesomeGrpcService";
package orders;
service OrderService {
rpc GetOrder (GetOrderRequest) returns (OrderResponse);
rpc PlaceOrder (PlaceOrderRequest) returns (OrderResponse);
}
message GetOrderRequest {
int32 order_id = 1;
}
message PlaceOrderRequest {
string product_name = 1;
int32 quantity = 2;
}
message OrderResponse {
int32 order_id = 1;
string status = 2;
string message = 3;
}
Реалізація gRPC Сервісу
Services/OrderService.cs
:
using System.Threading.Tasks;
using Grpc.Core;
using orders;
namespace MyAwesomeGrpcService.Services
{
public class OrderServiceImpl : OrderService.OrderServiceBase
{
public override Task GetOrder(GetOrderRequest request, ServerCallContext context)
{
if (request.OrderId == 1)
{
return Task.FromResult(new OrderResponse
{
OrderId = 1,
Status = "Shipped",
Message = "Your order is on the way!"
});
}
else
{
return Task.FromResult(new OrderResponse
{
OrderId = request.OrderId,
Status = "NotFound",
Message = "Order not found."
});
}
}
public override Task PlaceOrder(PlaceOrderRequest request, ServerCallContext context)
{
var newOrderId = new System.Random().Next(2, 1000);
return Task.FromResult(new OrderResponse
{
OrderId = newOrderId,
Status = "Created",
Message = $"Order created for {request.ProductName} (Qty: {request.Quantity})."
});
}
}
}
Реєстрація Сервісу
Program.cs
:
var builder = WebApplication.CreateBuilder(args);
// Реєстрація gRPC
builder.Services.AddGrpc();
var app = builder.Build();
// Маршрутизація gRPC сервісу
app.MapGrpcService();
app.MapGet("/", () => "gRPC service is running...");
app.Run();
Розширений gRPC: Стрімінг та Код помилок
- Серверний стрімінг: Сервер може відправляти кілька повідомлень у відповідь на один запит клієнта (корисно для оновлень прогресу в реальному часі).
- Клієнтський стрімінг: Клієнт може відправляти потік даних на сервер (наприклад, завантаження шматками).
- Двосторонній стрімінг: І клієнт, і сервер можуть одночасно обмінюватися потоками повідомлень.
- Коди помилок: Замість використання HTTP статус кодів, gRPC використовує об'єкти Status (
StatusCode.NotFound
,StatusCode.InvalidArgument
тощо). Це корисно для сильно типізованої обробки помилок.
Версійність gRPC Сервісів
- У файлах
.proto
зазвичай додаються нові поля з новими тегами для зворотної сумісності (Protocol Buffers може ігнорувати невідомі поля). - Також можна додавати нові RPC методи в той самий сервіс або версіонувати назву сервісу для великих змін.
Приклад: Обробка Замовлень у Реальному Часі
- Внутрішні виклики високої пропускної здатності: Внутрішні мікросервіси можуть викликати
OrderService
для оновлення статусів майже в реальному часі. - Затримка: Protobuf є бінарним форматом і швидше серіалізується/десеріалізується, ніж JSON.
- Стрімінг: Якщо потрібно отримувати оновлення в реальному часі по етапах обробки замовлення, серверний стрімінг може миттєво передавати ці оновлення.
6. Безпека та Продуктивність
Безпека
- REST: Зазвичай захищено за допомогою JWT, OAuth 2.0 або API ключів. ASP.NET Core Identity для інтегрованого управління користувачами.
- gRPC: Зазвичай працює через TLS/SSL; можна передавати токени в метаданих для автентифікації.
Продуктивність
- REST: Текстовий JSON може бути більшим і повільніше розбиратися. Кешування з HTTP заголовками (ETags) може допомогти.
- gRPC: Protobuf є компактним; HTTP/2 мультиплексує кілька викликів через одне з'єднання, часто зменшуючи накладні витрати.
7. Стратегії Тестування
REST:
- Swagger/OpenAPI: Вбудовано в ASP.NET Core для генерації та тестування кінцевих точок.
- Postman або curl: Швидке ручне тестування.
- xUnit/NUnit: Юніт-тести та інтеграційні тести для контролерів.
2. gRPC:
- BloomRPC, grpcurl або Postman (з підтримкою gRPC): Ручні виклики до ваших gRPC кінцевих точок.
- xUnit: Використовуйте gRPC клієнтські стуби у тестах для виклику методів сервісу безпосередньо.
8. Розгортання, масштабування та спостережуваність
Docker та Kubernetes
- Контейнеризація кожного мікросервісу за допомогою
Dockerfile
:
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
COPY . .
ENTRYPOINT ["dotnet", "MyAwesomeService.dll"]
- Kubernetes:
- Розгорніть кожен контейнер як Pod.
- Використовуйте Deployments для оновлень і відкатів.
- Експонуйте сервіси через ClusterIP або Ingress.
Логування, моніторинг та трасування
- Логування: Використовуйте Serilog, NLog або вбудоване логування в
.NET
. Централізуйте логи (наприклад, Elasticsearch, Azure Monitor). - Моніторинг: Експортуйте метрики до Prometheus або Azure Monitor.
- Трасування: Реалізуйте OpenTelemetry для розподіленого трасування (Jaeger, Zipkin).
Виявлення сервісів
- В середовищах мікросервісів потрібно мати спосіб виявлення кінцевих точок сервісів:
- Kubernetes: Виявлення сервісів на основі DNS (наприклад,
orderservice.default.svc.cluster.local
). - Service Mesh: Інструменти, такі як Istio або Linkerd, керують маршрутизацією трафіку, спостережуваністю та безпекою.
9. Підсумок
Основні висновки
- REST: Найкраще підходить для публічних API або там, де важлива читабельність для людини та широка сумісність.
- gRPC: Надзвичайно ефективний і сильно типізований — чудово підходить для внутрішніх мікросервісів на великій шкалі.
- Комбінація: Багато реальних систем відкривають REST шар для зовнішнього використання, а всередині використовують gRPC.
Остаточні думки
Використовуючи потужність .NET та сучасні платформи оркестрації контейнерів, ви можете створювати надійні, масштабовані мікросервіси, які безперешкодно інтегрують як REST, так і gRPC. Не забувайте враховувати безпеку, спостережуваність (логування/трасування) та стратегії тестування з першого дня — ці деталі часто визначають успішність або провал реальних розгортань.
Тепер, коли ви бачили, як налаштувати як REST, так і gRPC мікросервіси, ви готові побудувати екосистему кінцевих точок, яка відповідатиме вашим вимогам щодо продуктивності та інтеграції. Щасливого кодування — і нехай ваші сервіси залишаються здоровими, доступними та блискавично швидкими!
Перекладено з: REST and gRPC in .NET Core Microservices: A Comprehensive Guide