← Назад к вопросам

Как связаны сервисы между собой на проекте?

1.3 Junior🔥 191 комментариев
#Другое

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Взаимодействие сервисов в современных Backend-системах на C#

На современных проектах сервисы связываются между собой через распределённую архитектуру, где каждый сервис автономен, но взаимодействует с другими для выполнения бизнес-процессов. Рассмотрим основные подходы и паттерны на примере экосистемы .NET/C#.

Основные стили взаимодействия

1. Синхронное взаимодействие (Request/Response)

Наиболее распространённый подход, где сервис ожидает немедленного ответа. Реализуется через:

  • HTTP/REST API — стандартный подход для внешнего взаимодействия
// Пример вызова другого сервиса через HttpClient
public async Task<Order> GetOrderDetailsAsync(int orderId)
{
    using var client = new HttpClient();
    client.BaseAddress = new Uri("https://orders-service/api/");
    
    var response = await client.GetAsync($"orders/{orderId}");
    response.EnsureSuccessStatusCode();
    
    return await response.Content.ReadFromJsonAsync<Order>();
}
  • gRPC — высокопроизводительный RPC-фреймворк от Google
// Определение сервиса в .proto файле
service ProductService {
  rpc GetProduct (ProductRequest) returns (ProductResponse);
}
// Клиентская реализация
var channel = GrpcChannel.ForAddress("https://product-service:5001");
var client = new ProductService.ProductServiceClient(channel);
var product = await client.GetProductAsync(new ProductRequest { Id = productId });

2. Асинхронное взаимодействие (Event-Driven)

Сервисы общаются через события без прямого вызова:

  • Message Brokers (RabbitMQ, Kafka, Azure Service Bus)
// Публикация события в Azure Service Bus
await using var sender = new ServiceBusSender("order-created");
var message = new ServiceBusMessage(JsonSerializer.Serialize(orderEvent));
await sender.SendMessageAsync(message);

// Подписка на событие
await using var processor = new ServiceBusProcessor("order-created");
processor.ProcessMessageAsync += async args =>
{
    var orderEvent = JsonSerializer.Deserialize<OrderCreatedEvent>(args.Message.Body);
    await HandleOrderCreatedAsync(orderEvent);
    await args.CompleteMessageAsync(args.Message);
};
  • Event Sourcing — хранение состояния как последовательности событий

Ключевые архитектурные паттерны

Service Discovery и Load Balancing

В микросервисной архитектуре сервисы динамически масштабируются:

  • Consul, Eureka для регистрации и обнаружения сервисов
  • Kubernetes Services с DNS-балансировкой
  • API Gateway (Ocelot, YARP) как единая точка входа
// Конфигурация Ocelot для маршрутизации
{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/products/{everything}",
      "DownstreamScheme": "https",
      "ServiceName": "product-service",
      "UpstreamPathTemplate": "/products/{everything}"
    }
  ],
  "GlobalConfiguration": {
    "ServiceDiscoveryProvider": {
      "Type": "Consul",
      "Host": "localhost",
      "Port": 8500
    }
  }
}

Межсервисная коммуникация с отказоустойчивостью

Circuit Breaker (Polly библиотека):

var circuitBreakerPolicy = Policy
    .Handle<HttpRequestException>()
    .CircuitBreakerAsync(
        exceptionsAllowedBeforeBreaking:           3,
        durationOfBreak:                           TimeSpan.FromSeconds(30)
    );

var result = await circuitBreakerPolicy.ExecuteAsync(async () =>
{
    return await httpClient.GetAsync("https://inventory-service/api/stock");
});

Retry Pattern с экспоненциальной задержкой:

var retryPolicy = Policy
    .Handle<TimeoutException>()
    .WaitAndRetryAsync(
        retryCount: 5,
        sleepDurationProvider: retryAttempt => 
            TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))
    );

Оркестрация vs Хореография

Оркестрация

Централизованный координатор (Orchestrator) управляет процессом:

public class OrderOrchestrator
{
    public async Task ProcessOrderAsync(Order order)
    {
        await paymentService.ProcessPayment(order);
        await inventoryService.ReserveItems(order);
        await shippingService.ScheduleDelivery(order);
        await notificationService.SendConfirmation(order);
    }
}

Хореография

Сервисы реагируют на события без центрального координатора:

// Каждый сервис подписывается на нужные события
public class ShippingService
{
    public async Task HandlePaymentProcessedEvent(PaymentProcessedEvent @event)
    {
        if (@event.Success)
        {
            await ScheduleDelivery(@event.OrderId);
            await PublishDeliveryScheduledEvent(@event.OrderId);
        }
    }
}

Контракты и версионирование

  • OpenAPI/Swagger для REST API
  • Protobuf схемы для gRPC
  • Schema Registry в Kafka для контроля форматов событий
  • Semantic Versioning для управления обратной совместимостью

Безопасность межсервисного взаимодействия

  • mTLS (mutual TLS) для двусторонней аутентификации
  • JWT токены с ограниченным временем жизни
  • API Keys для простых сценариев
  • OAuth2 Client Credentials Flow для сервис-сервис аутентификации

Мониторинг и трассировка

  • Distributed Tracing (OpenTelemetry, Jaeger)
  • Correlation IDs для отслеживания запросов через сервисы
  • Метрики и логи централизованного сбора
  • Health Checks для проверки доступности сервисов
// Инструментация для OpenTelemetry
services.AddOpenTelemetry()
    .WithTracing(builder => builder
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddOtlpExporter());

Заключение

Выбор способа взаимодействия сервисов зависит от требований:

  • Синхронные вызовы — для простых сценариев с гарантированным ответом
  • Асинхронные события — для сложных процессов, отказоустойчивости и масштабирования
  • Гибридные подходы — наиболее распространены на практике

Критически важными являются: идемпотентность операций, обработка дублей сообщений, консистентность данных в eventually-consistent системах, и декомпозиция ответственности между сервисами. Современные фреймворки .NET 6+ предоставляют богатый инструментарий для реализации всех этих паттернов с высокой производительностью.

Как связаны сервисы между собой на проекте? | PrepBro