[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"question-sovremennaya-razrabotka-web-kak-organizovat-asinkhronnoe-vzaimodeystvie-cherez-kafka":3},{"id":4,"slug":5,"topicId":6,"topicSlug":7,"topicName":8,"topicEmoji":9,"question":10,"answer":11,"codeLang":12,"codeSrc":12,"important":12,"commonMistakes":12,"modernUsage":12,"difficulty":13,"tags":14,"related":20,"progress":21,"seo":22},1194,"kak-organizovat-asinkhronnoe-vzaimodeystvie-cherez-kafka",37,"sovremennaya-razrabotka-web","Современная разработка WEB","🌐","Как организовать асинхронное взаимодействие через Kafka?","Apache Kafka — стандарт для event-driven взаимодействия между сервисами, обеспечивающий надёжную доставку сообщений с гарантией порядка в пределах partition.\n\n> Аналогия из жизни: Kafka — это как журнал бухгалтерских проводок. Каждая запись добавляется в конец, никогда не удаляется (до истечения срока хранения), и любой аудитор (consumer) может прочитать историю с любого места.\n\n### Kafka vs RabbitMQ\n\n| Критерий | Apache Kafka | RabbitMQ |\n|----------|-------------|----------|\n| Модель | Лог (append-only, retention) | Очередь (удаляется после обработки) |\n| Порядок | В пределах partition | В пределах очереди |\n| Производительность | Миллионы msg\u002Fsec | Десятки тысяч msg\u002Fsec |\n| Replay | Можно перечитать историю | Нет |\n| Подходит для | Event Sourcing, Event Streaming | Task queues, RPC, сложная маршрутизация |\n\n### Producer и Consumer\n\n\u003Cdetails>\n\u003Csummary>Пример Producer\u003C\u002Fsummary>\n\n```java\n@Component\n@RequiredArgsConstructor\npublic class KafkaOrderEventPublisher implements OrderEventPublisher {\n\n    private final KafkaTemplate\u003CString, Object> kafkaTemplate;\n\n    @Override\n    public void publishOrderCreated(Order order) {\n        OrderCreatedEvent event = new OrderCreatedEvent(\n            order.getId(), order.getCustomerId(),\n            order.getTotalAmount(), Instant.now());\n\n        kafkaTemplate.send(\"order.events\", order.getId().toString(), event)\n            .whenComplete((result, ex) -> {\n                if (ex != null) {\n                    log.error(\"Failed to publish event for order {}\", order.getId(), ex);\n                } else {\n                    log.info(\"Published event for order {} to partition {} offset {}\",\n                        order.getId(),\n                        result.getRecordMetadata().partition(),\n                        result.getRecordMetadata().offset());\n                }\n            });\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Пример Consumer с ручным подтверждением\u003C\u002Fsummary>\n\n```java\n@Component\n@RequiredArgsConstructor\n@Slf4j\npublic class PaymentEventConsumer {\n\n    private final OrderService orderService;\n\n    @KafkaListener(topics = \"payment.events\", groupId = \"order-service\")\n    public void handlePaymentEvent(\n            @Payload PaymentCompletedEvent event,\n            @Header(KafkaHeaders.RECEIVED_PARTITION) int partition,\n            @Header(KafkaHeaders.OFFSET) long offset,\n            Acknowledgment acknowledgment) {\n\n        log.info(\"Received PaymentCompletedEvent: orderId={}, partition={}, offset={}\",\n            event.orderId(), partition, offset);\n\n        try {\n            orderService.confirmOrder(event.orderId(), event.paymentId());\n            acknowledgment.acknowledge();\n        } catch (Exception e) {\n            log.error(\"Failed to process event for order {}\", event.orderId(), e);\n            \u002F\u002F Не подтверждаем — сообщение будет повторно обработано\n        }\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n### Transactional Outbox Pattern\n\nЕдинственный надёжный способ гарантировать атомарность бизнес-операции и публикации события:\n\n```java\n@Transactional\npublic Order createOrder(CreateOrderCommand command) {\n    Order order = Order.create(command);\n    orderRepository.save(order);\n\n    \u002F\u002F Событие сохраняется в outbox-таблицу в той же транзакции\n    OutboxEvent event = OutboxEvent.builder()\n        .aggregateType(\"Order\")\n        .aggregateId(order.getId().toString())\n        .eventType(\"OrderCreated\")\n        .payload(objectMapper.writeValueAsString(new OrderCreatedEvent(order)))\n        .build();\n    outboxRepository.save(event);\n    return order;\n}\n\n\u002F\u002F Отдельный scheduler читает из outbox и отправляет в Kafka\n@Scheduled(fixedDelay = 1000)\n@Transactional\npublic void publishOutboxEvents() {\n    List\u003COutboxEvent> events = outboxRepository.findUnpublished(100);\n    for (OutboxEvent event : events) {\n        kafkaTemplate.send(event.getTopic(), event.getAggregateId(), event.getPayload());\n        event.markPublished();\n    }\n}\n```\n\n### Spring Events для внутренней коммуникации\n\nДля событий внутри одного приложения (модульный монолит):\n\n```java\n@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)\n@Async\npublic void onOrderCreated(OrderCreatedEvent event) {\n    notificationService.sendOrderConfirmation(event.orderId());\n}\n```\n\n### Частые ошибки\n\n- Обработка без idempotency: consumer может получить одно сообщение несколько раз (at-least-once)\n- Использование auto-commit: сообщение может быть потеряно при падении до обработки\n- Публикация события до коммита транзакции (без Outbox): при откате событие уже отправлено\n\n> **На собеседовании:** три ключевых пункта: 1) Kafka vs RabbitMQ — разные модели (лог vs очередь), 2) Transactional Outbox Pattern для гарантированной доставки, 3) идемпотентность consumer. Если спросят \"Как гарантировать exactly-once?\" — ответ: exactly-once семантика в Kafka достигается через idempotent producer + transactional consumer, но на практике проще проектировать idempotent обработку.","","middle",[15,16,17,18,19],"outbox-pattern","kafka","event-driven","spring-boot","messaging",[],null,{"title":23,"description":24,"ogTitle":25,"ogDescription":26,"keywords":27,"schemaAnswer":36,"featuredSnippetReady":37},"Как организовать асинхронное взаимодействие через Kafka — Gymterview","Apache Kafka в Spring Boot: Producer, Consumer, Transactional Outbox Pattern, идемпотентность. Сравнение Kafka vs RabbitMQ, Spring Events для модульного монолита.","Асинхронное взаимодействие через Kafka в Spring Boot — Gymterview","Kafka Producer\u002FConsumer, Transactional Outbox Pattern, идемпотентность. Kafka vs RabbitMQ и Spring Events.",[28,29,30,31,32,33,17,34,35],"Apache Kafka","Spring Kafka","Transactional Outbox","KafkaTemplate","KafkaListener","RabbitMQ","идемпотентность","собеседование","Apache Kafka — стандарт для event-driven взаимодействия между сервисами. Гарантия порядка в пределах partition. Kafka vs RabbitMQ: лог (append-only) vs очередь (удаляется). Transactional Outbox Pattern — единственный надёжный способ атомарности бизнес-операции и публикации события. Consumer должен быть идемпотентным (at-least-once семантика). Spring Events для внутренней коммуникации в модульном монолите.",true]