Микросервисы на C# (.NET): архитектура и практика

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

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

Начать курс

Микросервисы на C# (.NET): от теории к практике

В современной разработке программного обеспечения микросервисная архитектура стала стандартом для построения масштабируемых и отказоустойчивых систем. Платформа .NET предоставляет все необходимые инструменты для создания надежных микросервисов на C#. В этой статье мы рассмотрим ключевые принципы архитектуры, практические примеры кода и лучшие практики, которые помогут вам начать строить микросервисы на C#.

1. Основы микросервисной архитектуры на .NET

Микросервисы — это подход к разработке, при котором приложение разбивается на небольшие, независимые сервисы, каждый из которых отвечает за свою бизнес-функцию. В экосистеме .NET для этого используется ASP.NET Core — легковесный и кроссплатформенный фреймворк.

Ключевые принципы микросервисов на C#:

  • Независимость развертывания — каждый сервис может быть обновлен без остановки других.
  • Слабая связанность — сервисы общаются через API (REST, gRPC) или очереди сообщений.
  • Собственная база данных — каждый микросервис владеет своими данными (Database per Service).
  • Отказоустойчивость — сбой одного сервиса не должен блокировать всю систему.

Начнем с создания простого микросервиса на C#. Используем шаблон ASP.NET Core Web API.

// Создание нового проекта микросервиса
dotnet new webapi -n OrderService
cd OrderService

// Пример простого контроллера
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IOrderRepository _repository;

    public OrdersController(IOrderRepository repository)
    {
        _repository = repository;
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> GetOrder(int id)
    {
        var order = await _repository.GetByIdAsync(id);
        if (order == null)
            return NotFound();
        return Ok(order);
    }

    [HttpPost]
    public async Task<IActionResult> CreateOrder(OrderDto orderDto)
    {
        var order = new Order(orderDto.CustomerId, orderDto.TotalAmount);
        await _repository.AddAsync(order);
        return CreatedAtAction(nameof(GetOrder), new { id = order.Id }, order);
    }
}

2. Межсервисное взаимодействие: REST, gRPC и очереди

Микросервисы должны общаться друг с другом. В .NET доступны три основных подхода:

REST API (HTTP)

Самый простой и распространенный способ. Используйте HttpClient с фабрикой для правильного управления подключениями.

// Пример вызова другого микросервиса через HttpClient
public class InventoryServiceClient
{
    private readonly HttpClient _httpClient;

    public InventoryServiceClient(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<bool> CheckStockAsync(int productId, int quantity)
    {
        var response = await _httpClient.GetAsync(
            $"/api/inventory/check?productId={productId}&quantity={quantity}");
        return response.IsSuccessStatusCode;
    }
}

// Регистрация в Program.cs
builder.Services.AddHttpClient<InventoryServiceClient>(client =>
{
    client.BaseAddress = new Uri("http://inventory-service:5001");
});

gRPC

Для высокопроизводительной синхронной связи используйте gRPC. Он основан на HTTP/2 и Protocol Buffers.

// Определение сервиса в .proto файле
syntax = "proto3";

service OrderProcessor {
  rpc ProcessOrder (OrderRequest) returns (OrderResponse);
}

message OrderRequest {
  int32 order_id = 1;
  string customer_email = 2;
}

message OrderResponse {
  bool success = 1;
  string message = 2;
}

// Серверная часть на C#
public class OrderProcessorService : OrderProcessor.OrderProcessorBase
{
    public override async Task<OrderResponse> ProcessOrder(
        OrderRequest request, ServerCallContext context)
    {
        // Логика обработки заказа
        return new OrderResponse 
        { 
            Success = true, 
            Message = $"Order {request.OrderId} processed" 
        };
    }
}

Очереди сообщений (RabbitMQ, Azure Service Bus)

Для асинхронного взаимодействия и обеспечения отказоустойчивости используйте брокеры сообщений.

// Отправка сообщения в RabbitMQ
public class MessagePublisher
{
    private readonly IConnection _connection;
    private readonly IModel _channel;

    public MessagePublisher()
    {
        var factory = new ConnectionFactory() { HostName = "localhost" };
        _connection = factory.CreateConnection();
        _channel = _connection.CreateModel();
        _channel.QueueDeclare(queue: "order_created",
                              durable: false,
                              exclusive: false,
                              autoDelete: false,
                              arguments: null);
    }

    public void Publish(OrderCreatedEvent orderEvent)
    {
        var json = JsonSerializer.Serialize(orderEvent);
        var body = Encoding.UTF8.GetBytes(json);
        _channel.BasicPublish(exchange: "",
                              routingKey: "order_created",
                              basicProperties: null,
                              body: body);
    }
}

3. Паттерны для отказоустойчивости: Circuit Breaker и Retry

В распределенной системе сбои неизбежны. Библиотека Polly для .NET помогает реализовать паттерны устойчивости.

// Настройка политики Circuit Breaker и Retry
using Polly;
using Polly.Extensions.Http;

var retryPolicy = HttpPolicyExtensions
    .HandleTransientHttpError()
    .WaitAndRetryAsync(3, retryAttempt => 
        TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

var circuitBreakerPolicy = HttpPolicyExtensions
    .HandleTransientHttpError()
    .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));

// Применение к HttpClient
builder.Services.AddHttpClient<PaymentServiceClient>(client =>
{
    client.BaseAddress = new Uri("http://payment-service:5002");
})
.AddPolicyHandler(retryPolicy)
.AddPolicyHandler(circuitBreakerPolicy);

Этот код автоматически повторяет запросы 3 раза с экспоненциальной задержкой, а при 5 последовательных ошибках размыкает цепь на 30 секунд.

4. Контейнеризация и оркестрация с Docker и Kubernetes

Для управления микросервисами используйте Docker. Каждый микросервис упаковывается в отдельный контейнер.

// Dockerfile для микросервиса на C#
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["OrderService/OrderService.csproj", "OrderService/"]
RUN dotnet restore "OrderService/OrderService                

Блоги

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