Микросервисы на C#: архитектура и практика от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в микросервисы на 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#


                
                

Блоги

Рекомендаций по книгам