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

В чем разница между синхронной и асинхронной коммуникации?

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

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

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

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

# Разница между синхронной и асинхронной коммуникацией

Это фундаментальное различие в архитектуре распределённых систем. Выбор между ними определяет надёжность, производительность и сложность.

1. Синхронная коммуникация

Принцип

Отправитель блокируется ДО получения ответа

Отправитель: Отправляю запрос
             ↓
        Жду ответ (БЛОКИРОВАН)
             ↓
         Получил ответ
             ↓
         Продолжаю работу

Пример: HTTP запрос (REST API)

@RestController
public class OrderController {
    @PostMapping("/orders")
    public ResponseEntity<Order> createOrder(@RequestBody CreateOrderRequest req) {
        // 1. Блокировка
        Order order = orderService.create(req);
        // 2. Отправку на сервис платежей
        PaymentResult result = paymentService.charge(order.getAmount());
        // 3. Если платёж не прошёл → ошибка
        if (!result.isSuccess()) {
            throw new PaymentFailedException();
        }
        // 4. Сохраняю заказ
        orderRepository.save(order);
        // 5. Возвращаю результат клиенту
        return ResponseEntity.ok(order);
    }
}

public class SyncClient {
    public static void main(String[] args) {
        Order order = restTemplate.postForObject(
            "http://api.example.com/orders",
            createOrderRequest,
            Order.class
        );
        // Блокирован, пока не получит ответ
        System.out.println("Order created: " + order);
    }
}

Характеристики синхронной коммуникации

✅ Плюсы:
- Просто реализовать
- Понятный flow кода
- Сразу знаешь результат
- Легко handle ошибки

❌ Минусы:
- Зависимость между системами (coupling)
- Если получатель медленный → весь процесс медленный
- Если получатель упал → всё падает
- Плохая масштабируемость (нужно много потоков)
- Timeout проблемы

Проблема синхронной коммуникации

Сценарий:
order-service → payment-service → bank-api

Если bank-api медленный (5 секунд):
- order-service тоже медленный
- пользователь ждёт 5 секунд на каждый заказ
- при 1000 одновременных запросов → 5000 потоков заблокировано!

2. Асинхронная коммуникация

Принцип

Отправитель НЕ блокируется, продолжает работу

Отправитель: Отправляю сообщение в очередь
             ↓
         Сразу продолжаю работу
             ↓
         Получатель обрабатывает в своём темпе

Пример: Message Queue (Kafka, RabbitMQ)

@RestController
public class OrderController {
    @PostMapping("/orders")
    public ResponseEntity<Order> createOrder(@RequestBody CreateOrderRequest req) {
        // 1. Создаю заказ
        Order order = orderService.create(req);
        
        // 2. Сохраняю в БД
        orderRepository.save(order);
        
        // 3. Отправляю сообщение в Kafka (не блокирую!)
        kafkaTemplate.send("payment-topic", new PaymentEvent(
            order.getId(),
            order.getAmount()
        ));
        
        // 4. СРАЗУ возвращаю результат
        return ResponseEntity.accepted().body(order);
        // Платёж будет обработан в background
    }
}

@Service
public class PaymentProcessor {
    @KafkaListener(topics = "payment-topic", groupId = "payment-service")
    public void processPayment(PaymentEvent event) {
        // Эта функция выполняется В ОТДЕЛЬНОМ потоке
        // Получатель обрабатывает в своём темпе
        
        try {
            paymentService.charge(event.getAmount());
            // Если ошибка → send to dead-letter queue
        } catch (PaymentFailedException e) {
            kafkaTemplate.send("payment-failed-topic", event);
        }
    }
}

Характеристики асинхронной коммуникации

✅ Плюсы:
- Слабое связывание (loose coupling)
- Получатель может быть медленный — не влияет на отправителя
- Высокая масштабируемость (потребители обрабатывают в очереди)
- Отказоустойчивость (если получатель упал → message ждёт)
- Лучший throughput

❌ Минусы:
- Сложнее в реализации
- Не сразу знаешь результат
- Обработка ошибок сложнее (retry logic, DLQ)
- Нужна очередь (infrastructure)
- Данные могут быть в intermediate states

Сравнение диаграмм

Синхронная

Польз.    Order Service    Payment Service    Bank
  │             │                 │            │
  ├─ POST /orders ─────────────────→
  │             │                 │            │
  │             ├─ charge() ───────────────────→
  │             │                 │ блокирован │
  │      БЛОКИРОВАН              │            │
  │             │                 │← результат─┤
  │             │← результат ──────┤            │
  │← 200 OK ────┤                 │            │
  │             │                 │            │

Асинхронная

Польз.    Order Service    Kafka    Payment Service
  │             │           │              │
  ├─ POST /orders ────────────┥             │
  │← 202 Accepted ───┤                    │
  │ (сразу!)         │           │        │
  │                  │           │        │
  │ обрабатывает     │           │        │
  │                  ├─ send message ────→
  │                  │           │        │
  │                  │           │ обрабатывает
  │                  │           │ в своём темпе
  │                  │           │        │

Выбор между ними

Используй синхронную, если:

✅ Нужен сразу результат
✅ Simple request-response flow
✅ Система small (<10 RPS)
✅ Требуется ACID (транзакции)
✅ REST API, где результат обязателен

Используй асинхронную, если:

✅ Результат не нужен сразу
✅ Высокая нагрузка (>100 RPS)
✅ Получатель может быть медленный
✅ Отказоустойчивость важна
✅ Микросервисная архитектура
✅ Loose coupling нужен

Практические примеры

Пример 1: Email отправка

Синхронно (плохо)

@PostMapping("/register")
public ResponseEntity<User> register(@RequestBody RegisterRequest req) {
    User user = createUser(req);
    
    // БЛОКИРУЕМСЯ на отправку email (5 секунд!)
    emailService.sendWelcomeEmail(user.getEmail());
    
    return ResponseEntity.ok(user);
    // пользователь ждёт 5 сек, пока отправим email
}

Асинхронно (хорошо)

@PostMapping("/register")
public ResponseEntity<User> register(@RequestBody RegisterRequest req) {
    User user = createUser(req);
    userRepository.save(user);
    
    // Отправляем в Kafka (instant)
    kafkaTemplate.send("email-topic", new EmailEvent(
        user.getEmail(),
        "Welcome"
    ));
    
    // Сразу возвращаем (пользователь не ждёт)
    return ResponseEntity.ok(user);
}

Пример 2: Платёж

Синхронно (может быть OK)

@PostMapping("/checkout")
public ResponseEntity<Order> checkout(@RequestBody OrderRequest req) {
    Order order = createOrder(req);
    
    // НУЖНО знать результат платежа (success/fail)
    PaymentResult result = paymentGateway.charge(order.getAmount());
    if (!result.isSuccess()) {
        return ResponseEntity.badRequest().build();
    }
    
    orderRepository.save(order);
    return ResponseEntity.ok(order);
}

Асинхронно (для больших систем)

@PostMapping("/checkout")
public ResponseEntity<Order> checkout(@RequestBody OrderRequest req) {
    Order order = createOrder(req);
    order.setStatus(OrderStatus.PENDING_PAYMENT);  // Промежуточный статус
    orderRepository.save(order);
    
    // Асинхронный платёж
    kafkaTemplate.send("payment-topic", new PaymentEvent(
        order.getId(),
        order.getAmount()
    ));
    
    // Возвращаем сразу
    return ResponseEntity.accepted().body(order);
}

// Payment consumer
@KafkaListener(topics = "payment-topic")
public void processPayment(PaymentEvent event) {
    try {
        PaymentResult result = paymentGateway.charge(event.getAmount());
        if (result.isSuccess()) {
            // Update order
            Order order = orderRepository.findById(event.getOrderId()).orElse(null);
            order.setStatus(OrderStatus.PAID);
            orderRepository.save(order);
            
            // Отправить notification
            kafkaTemplate.send("order-paid-topic", order);
        }
    } catch (Exception e) {
        // Send to DLQ (Dead Letter Queue)
        kafkaTemplate.send("payment-failed-topic", event);
    }
}

Hybrid подход

Можно комбинировать оба подхода:

@PostMapping("/orders")
public ResponseEntity<Order> createOrder(@RequestBody OrderRequest req) {
    // 1. Синхронно создаём заказ (нужен результат)
    Order order = orderService.create(req);
    orderRepository.save(order);
    
    // 2. Асинхронно обрабатываем (не нужен результат)
    kafkaTemplate.send("order-processing-topic", order);
    
    return ResponseEntity.ok(order);
}

Timeout и Retry в синхронной коммуникации

// Важно! Всегда используй timeout
public void callRemoteService() {
    RestTemplate restTemplate = new RestTemplate();
    
    // Без timeout → может зависнуть на 60+ сек
    restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
    
    // С timeout
    String response = restTemplate.getForObject(
        "http://slow-service.com/api",
        String.class
    );
}

// Лучше: с CircuitBreaker
@Service
public class RemoteCallService {
    @CircuitBreaker(failureThreshold = 5, delay = 1000)
    public String callRemoteService() {
        return restTemplate.getForObject("http://...", String.class);
    }
}

Итог

АспектСинхроннаяАсинхронная
БлокировкаДа (ждёт ответ)Нет (сразу продолжает)
CouplingПлотноеСлабое
РезультатСразу известенПозже
ScalabilityПлохоОтлично
ComplexityПростоСложнее
ReliabilityЗависит от получателяНезависимо
LatencyЗависит от всехНизко
ThroughputОграниченоВысокий

Правило большого пальца:

  • Синхронная = когда результат критичен (checkout)
  • Асинхронная = когда масштабируемость критична (notifications, analytics)
В чем разница между синхронной и асинхронной коммуникации? | PrepBro