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

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

2.0 Middle🔥 171 комментариев
#REST API и микросервисы#Брокеры сообщений

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

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

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

Варианты общения между микросервисами

В микросервисной архитектуре сервисы должны взаимодействовать друг с другом. Я использую различные подходы в зависимости от требований проекта. Основных вариантов несколько.

1. REST API (HTTP/HTTPS)

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

// Вызывающий сервис
@Service
public class OrderService {
  
  private final RestTemplate restTemplate;
  private final String inventoryServiceUrl;
  
  public Order createOrder(OrderRequest request) {
    // Проверка товара в другом сервисе
    InventoryResponse inventory = restTemplate.getForObject(
      inventoryServiceUrl + "/products/" + request.getProductId(),
      InventoryResponse.class
    );
    
    if (inventory.getQuantity() < request.getQuantity()) {
      throw new InsufficientInventoryException();
    }
    
    return orderRepository.save(new Order(request));
  }
}

// Вызываемый сервис (Inventory)
@RestController
@RequestMapping("/api/v1/products")
public class ProductController {
  
  @GetMapping("/{id}")
  public InventoryResponse getProduct(@PathVariable String id) {
    Product product = productService.findById(id);
    return new InventoryResponse(product.getId(), product.getQuantity());
  }
}

Преимущества:

  • Простота реализации и отладки
  • Стандартизированный протокол
  • Хорошая IDE и tooling поддержка

Недостатки:

  • Синхронный — ожидание ответа
  • Тесная связанность между сервисами
  • Проблемы при недоступности целевого сервиса
  • Возможны deadlocks при циклических зависимостях

2. REST с Fallback и Circuit Breaker

Для повышения надёжности используется pattern Circuit Breaker (Resilience4j):

@Service
public class PaymentService {
  
  private final PaymentGatewayClient gatewayClient;
  
  @CircuitBreaker(name = "paymentService", fallbackMethod = "processPaymentFallback")
  public PaymentResult processPayment(PaymentRequest request) {
    return gatewayClient.charge(request);
  }
  
  // Fallback метод при сбое payment gateway
  public PaymentResult processPaymentFallback(PaymentRequest request, Exception ex) {
    logger.error("Payment gateway is unavailable, queuing for retry", ex);
    // Сохраняем платёж в очередь для повторной обработки
    paymentQueueRepository.save(new PendingPayment(request));
    return new PaymentResult("PENDING", "Payment queued for retry");
  }
}

// Конфигурация в application.yml
resilience4j:
  circuitbreaker:
    instances:
      paymentService:
        registerHealthIndicator: true
        slidingWindowSize: 10
        failureRateThreshold: 50
        slowCallRateThreshold: 50
        slowCallDurationThreshold: 2000ms
        permittedNumberOfCallsInHalfOpenState: 3

3. Message Broker — Асинхронное взаимодействие (RabbitMQ)

Для асинхронной обработки событий используется message broker:

// Publisher (Order Service)
@Service
public class OrderEventPublisher {
  
  private final RabbitTemplate rabbitTemplate;
  
  public void publishOrderCreated(Order order) {
    rabbitTemplate.convertAndSend(
      "order-events",
      "order.created",
      new OrderCreatedEvent(
        order.getId(),
        order.getCustomerId(),
        order.getAmount(),
        order.getCreatedAt()
      )
    );
  }
}

// Consumer (Inventory Service)
@Service
public class OrderEventConsumer {
  
  private final InventoryService inventoryService;
  
  @RabbitListener(queues = "inventory-update-queue")
  public void handleOrderCreated(OrderCreatedEvent event) {
    // Асинхронно обновляем инвентарь
    inventoryService.reserveItems(
      event.getOrderId(),
      event.getItems()
    );
  }
}

// Конфигурация
@Configuration
public class RabbitConfig {
  
  public static final String ORDER_EXCHANGE = "order-events";
  public static final String INVENTORY_QUEUE = "inventory-update-queue";
  
  @Bean
  public TopicExchange orderExchange() {
    return new TopicExchange(ORDER_EXCHANGE, true, false);
  }
  
  @Bean
  public Queue inventoryQueue() {
    return new Queue(INVENTORY_QUEUE, true);
  }
  
  @Bean
  public Binding binding(Queue queue, TopicExchange exchange) {
    return BindingBuilder.bind(queue)
      .to(exchange)
      .with("order.*");
  }
}

Преимущества:

  • Асинхронность — не ожидаем ответ
  • Слабая связанность между сервисами
  • Масштабируемость — multiple consumers
  • Надёжность — сообщения persisted

Недостатки:

  • Сложность отладки
  • Гарантии доставки требуют внимания
  • Возможны дублирующиеся обработки (idempotency needed)

4. Apache Kafka — Stream Processing

Для high-volume event streaming с retention:

// Producer
@Service
public class LogEventProducer {
  
  private final KafkaTemplate<String, LogEvent> kafkaTemplate;
  
  public void publishLogEvent(LogEvent event) {
    kafkaTemplate.send("user-activity-logs", 
      event.getUserId(), 
      event
    );
  }
}

// Consumer with Spring Kafka
@Service
public class AnalyticsService {
  
  @KafkaListener(topics = "user-activity-logs", groupId = "analytics-group")
  public void analyzeUserActivity(LogEvent event) {
    // Обработка с сохранением state
    userStatsRepository.incrementUserActions(event.getUserId());
  }
}

// Конфигурация
spring:
  kafka:
    bootstrap-servers: localhost:9092
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
    consumer:
      group-id: analytics-group
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
      properties:
        spring.json.type.mapping: "logEvent:com.example.LogEvent"

5. gRPC — Высокопроизводительное взаимодействие

Для крайне требовательных к производительности систем:

// Определение сервиса в .proto файле
// service ProductService {
//   rpc GetProduct(ProductId) returns (Product) {}
// }

@Service
public class ProductGrpcService extends ProductServiceGrpc.ProductServiceImplBase {
  
  private final ProductRepository productRepository;
  
  @Override
  public void getProduct(ProductId request, 
                        StreamObserver<Product> responseObserver) {
    Product product = productRepository.findById(request.getId())
      .orElse(null);
    
    if (product != null) {
      responseObserver.onNext(product.toProto());
    }
    responseObserver.onCompleted();
  }
}

// Клиент
@Service
public class OrderGrpcClient {
  
  private final ProductServiceGrpc.ProductServiceBlockingStub stub;
  
  public Product getProduct(String productId) {
    return stub.getProduct(ProductId.newBuilder()
      .setId(productId)
      .build());
  }
}

Преимущества:

  • Очень быстро (binary protocol, HTTP/2)
  • Strongly typed (proto contracts)
  • Двусторонняя streaming поддержка

Недостатки:

  • Сложнее, чем REST
  • Меньше tooling чем REST
  • Требует proto contract management

6. GraphQL — Flexible Data Queries

Для сложных data relationships:

@Service
public class OrderGraphQLResolver {
  
  private final OrderRepository orderRepository;
  private final CustomerGraphQLClient customerClient;
  
  @QueryMapping
  public Order order(@Argument String id) {
    return orderRepository.findById(id).orElse(null);
  }
  
  @SchemaMapping
  public Customer customer(Order order) {
    // Запрос к другому сервису
    return customerClient.getCustomer(order.getCustomerId());
  }
}

// Schema
@Component
public class GraphQLSchema {
  
  // type Order {
  //   id: ID!
  //   customer: Customer!
  //   total: Float!
  // }
  // 
  // type Customer {
  //   id: ID!
  //   name: String!
  // }
  // 
  // type Query {
  //   order(id: ID!): Order
  // }
}

7. WebSockets — Real-time двусторонняя коммуникация

Для real-time updates:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
  
  @Override
  public void configureMessageBroker(MessageBrokerRegistry config) {
    config.enableSimpleBroker("/topic");
    config.setApplicationDestinationPrefixes("/app");
  }
  
  @Override
  public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
  }
}

@Service
@RestController
public class OrderNotificationService {
  
  private final SimpMessagingTemplate messagingTemplate;
  
  public void notifyOrderStatus(String orderId, OrderStatus status) {
    messagingTemplate.convertAndSend(
      "/topic/order/" + orderId,
      new OrderStatusUpdate(orderId, status)
    );
  }
}

8. Saga Pattern — Распределённые транзакции

Для координации multi-service операций:

// Хореография (event-driven saga)
@Service
public class OrderSaga {
  
  private final RabbitTemplate rabbitTemplate;
  
  @Transactional
  public Order createOrder(OrderRequest request) {
    // 1. Создать заказ
    Order order = orderRepository.save(new Order(request));
    
    // 2. Опубликовать событие OrderCreated
    rabbitTemplate.convertAndSend(
      "order-events",
      "order.created",
      new OrderCreatedEvent(order.getId())
    );
    
    return order;
  }
  
  @RabbitListener(queues = "order-failed-queue")
  public void compensateOrderCreation(OrderFailedEvent event) {
    // Откат при ошибке в других сервисах
    orderRepository.delete(event.getOrderId());
  }
}

// Orchestration (service-driven saga)
@Service
public class OrderOrchestrationService {
  
  private final RestTemplate restTemplate;
  
  @Transactional
  public Order createOrderWithOrchestration(OrderRequest request) {
    try {
      // 1. Проверить товар
      restTemplate.postForObject("/inventory/reserve", request, Void.class);
      
      // 2. Обработать платёж
      restTemplate.postForObject("/payment/charge", request, Void.class);
      
      // 3. Создать заказ
      return orderRepository.save(new Order(request));
      
    } catch (Exception e) {
      // Откат
      restTemplate.postForObject("/inventory/release", request, Void.class);
      throw new OrderCreationFailedException(e);
    }
  }
}

Сравнение подходов

МетодСинхронностьСвязанностьНадёжностьПроизводительностьКогда использовать
RESTСинхронныйТеснаяСредняяСредняяПростые запросы
Message BrokerАсинхронныйСлабаяВысокаяХорошаяEvent-driven
KafkaАсинхронныйСлабаяВысокаяОтличнаяStream processing
gRPCСинхронныйСредняяВысокаяОтличнаяHigh-performance
GraphQLСинхронныйСредняяСредняяСредняяComplex queries
WebSocketДвустороннийСредняяСредняяХорошаяReal-time

Мой подход

В современных системах я использую комбинацию подходов:

  • REST с Circuit Breaker для простых синхронных операций
  • RabbitMQ/Kafka для event-driven логики
  • gRPC для критичных по производительности компонентов
  • Saga Pattern для распределённых транзакций

Выбор зависит от требований к latency, throughput, consistency и complexity системы.

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