Введение в микросервисы на C#
Микросервисная архитектура стала стандартом де-факто для построения сложных, масштабируемых и отказоустойчивых приложений. В отличие от монолита, где весь код объединен в один процесс, микросервисы разбивают систему на небольшие, независимо развертываемые сервисы. Платформа .NET (C#) предоставляет все необходимые инструменты для создания профессиональных микросервисов: от ASP.NET Core для веб-API до библиотек для работы с очередями, контейнеризации и оркестрации.
В этой статье мы рассмотрим полный путь от проектирования архитектуры до практической реализации микросервиса на C# с примерами кода.
1. Основы архитектуры микросервисов
Принципы и антипаттерны
Прежде чем писать код, важно понять ключевые принципы:
- Единая ответственность (SRP): Каждый сервис отвечает за одну бизнес-функцию (например, сервис заказов, сервис оплаты).
- Слабая связанность: Сервисы общаются через сеть (HTTP, gRPC, очереди) и не знают о внутреннем устройстве друг друга.
- Независимое развертывание: Вы можете обновить один сервис без остановки других.
- Децентрализация данных: Каждый сервис владеет своей базой данных (Database per Service).
Антипаттерны, которых стоит избегать: слишком мелкие сервисы (nanoservices), общая база данных, синхронные цепочки вызовов (chattiness).
Связь между сервисами
Для взаимодействия микросервисов на C# используются:
- Синхронная: REST API (HTTP/JSON) или gRPC (бинарный протокол, быстрее).
- Асинхронная: Очереди сообщений (RabbitMQ, Azure Service Bus, Kafka) — предпочтительный способ для слабой связанности.
2. Практическая реализация микросервиса на C#
Пример: Сервис управления заказами
Создадим простой микросервис на ASP.NET Core 8. Используем Clean Architecture для разделения слоев.
Шаг 1: Проект и структура
dotnet new webapi -n OrderService
cd OrderService
Создаем папки: Controllers, Models, Services, Data.
Шаг 2: Модель данных
// Models/Order.cs
public class Order
{
public int Id { get; set; }
public string CustomerName { get; set; }
public decimal TotalAmount { get; set; }
public DateTime CreatedAt { get; set; }
}
Шаг 3: Контекст базы данных (Entity Framework Core)
// Data/OrderDbContext.cs
public class OrderDbContext : DbContext
{
public OrderDbContext(DbContextOptions<OrderDbContext> options) : base(options) { }
public DbSet<Order> Orders { get; set; }
}
Шаг 4: Сервисный слой
// Services/IOrderService.cs
public interface IOrderService
{
Task<Order> CreateOrderAsync(Order order);
Task<List<Order>> GetAllOrdersAsync();
}
// Services/OrderService.cs
public class OrderService : IOrderService
{
private readonly OrderDbContext _context;
public OrderService(OrderDbContext context)
{
_context = context;
}
public async Task<Order> CreateOrderAsync(Order order)
{
_context.Orders.Add(order);
await _context.SaveChangesAsync();
return order;
}
public async Task<List<Order>> GetAllOrdersAsync()
{
return await _context.Orders.ToListAsync();
}
}
Шаг 5: Контроллер
// Controllers/OrdersController.cs
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
private readonly IOrderService _orderService;
public OrdersController(IOrderService orderService)
{
_orderService = orderService;
}
[HttpPost]
public async Task<IActionResult> CreateOrder([FromBody] Order order)
{
var created = await _orderService.CreateOrderAsync(order);
return CreatedAtAction(nameof(GetAllOrders), new { id = created.Id }, created);
}
[HttpGet]
public async Task<IActionResult> GetAllOrders()
{
var orders = await _orderService.GetAllOrdersAsync();
return Ok(orders);
}
}
Шаг 6: Регистрация в Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<OrderDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
3. Асинхронное взаимодействие и паттерны
Использование RabbitMQ в C#
Для отправки сообщений между сервисами используем библиотеку RabbitMQ.Client. Пример отправки события "OrderCreated":
// В сервисе OrderService после создания заказа
var factory = new ConnectionFactory() { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();
channel.QueueDeclare(queue: "order_created", durable: false, exclusive: false, autoDelete: false, arguments: null);
string message = JsonSerializer.Serialize(order);
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "", routingKey: "order_created", basicProperties: null, body: body);
Паттерн Saga для распределенных транзакций
Когда операция затрагивает несколько сервисов (например, заказ + оплата + доставка), используйте Saga:
- Хореография: Каждый сервис слушает события и публикует свои.
- Оркестрация: Центральный координатор (Saga Orchestrator) управляет шагами и компенсациями.
Пример простой хореографии: Сервис заказов публикует "OrderCreated" → Сервис оплаты слушает, списывает деньги, публикует "PaymentCompleted" → Сервис доставки слушает и отправляет товар.
4. Контейнеризация и развертывание
Dockerfile для микросервиса на C#
Блоги
Рекомендаций по книгам
Читайте также
Как Node.js обрабатывает аргументы командной строки: от process.argv до сырцов
Удаляем свойство из объекта JavaScript: 3 подхода и подводные камни
self или $this в PHP: когда что использовать? Разбор с примерами
Dictionary vs Hashtable в C#: почему словарь всегда побеждает?
Работа с JSON в PHP: парсинг и сериализация для начинающих