JavaRush /Курси /Модуль 5. Spring /Лекція 209: Основні помилки при використанні EDA і як їх ...

Лекція 209: Основні помилки при використанні EDA і як їх уникнути

Модуль 5. Spring
Рівень 13 , Лекція 8
Відкрита

Давайте поговоримо про підводні камені, які можуть трапитися на шляху проєктування подійно-орієнтованої архітектури. Як кажуть, "розумний вчиться на чужих помилках", тому давайте розберемося, які помилки найпоширеніші і як їх можна уникнути.


Помилка №1: Надмірна зв'язаність між сервісами

Якщо ваша подійна система нагадує павутину, де кожен сервіс залежить від десятків інших, значить, щось пішло не так. Основна ідея EDA — роз’єднати сервіси і зробити їх незалежними. Проте, якщо кожен сервіс залежить від інших за схемою "я чекаю, поки вони щось зроблять", то це вже не слабка зв'язаність, а пекельний клубок.

Чому це відбувається?

  • Неправильний дизайн подій, де одна подія викликає каскад інших подій.
  • Використання одного топіка для різних типів даних, що змушує сервіси аналізувати "не свої" дані.
  • "Тонкі" події, які не містять достатнього контексту, змушують підписників звертатися до інших сервісів за додатковою інформацією.

Як уникнути?

  • Проєктуйте події з урахуванням контексту. Кожна подія має бути самодостатньою і містити всю необхідну інформацію.
  • Мінімізуйте кількість підписників. Сервіс має підписуватися лише на ті події, які йому справді потрібні.
  • Використовуйте різні топіки для різних типів подій. Це зменшить ймовірність "перехресного забруднення".

Приклад з реального життя: якщо мікросервіс "Замовлення" публікує подію OrderCreated, мікросервіс "Склад" не повинен залежати від відповіді сервісу "Оплата". Нехай вони працюють незалежно один від одного.


Помилка №2: Слабка обробка помилок і негарантована доставка

Уявіть ситуацію: ви відправили подію, але її ніхто не обробив. Або ще гірше: сервіс, який мав обробити подію, впав. І ваші дані просто загубилися. Це класична проблема, пов'язана з відсутністю правильного управління помилками.

Чому це відбувається?

  • Використання доставок "at most once" у критичних сценаріях.
  • Некоректна конфігурація брокерів повідомлень (наприклад, невеликий retention period в Kafka).
  • Ігнорування повторної доставки повідомлень (retries).

Як уникнути?

  • Використовуйте підхід "at least once". Нехай повідомлення в системі доставляються принаймні один раз, навіть якщо є ризик повторної обробки.
  • Реалізуйте ідемпотентність. Якщо одна й та сама подія буде оброблена кілька разів, це не повинно зашкодити системі. Наприклад, обробляти транзакцію тільки якщо її статус ще не "завершений".
  • Моніторьте життєвий цикл повідомлень. Налаштуйте алертинг на випадки, якщо подія не дійшла до підписника в розумні терміни.

Приклад коду ідемпотентної обробки:


@Service
public class PaymentEventProcessor {

    @Autowired
    private PaymentRepository paymentRepository;

    public void processPaymentEvent(PaymentEvent event) {
        // Перевіряємо, чи оброблювалася подія раніше
        if (paymentRepository.existsByTransactionId(event.getTransactionId())) {
            // Просто логіруємо і виходимо
            log.info("Подія з ID {} вже оброблена", event.getTransactionId());
            return;
        }

        // Обробляємо подію
        Payment payment = new Payment(event.getTransactionId(), event.getAmount());
        paymentRepository.save(payment);
    }
}

Помилка №3: Надмірна деталізація подій

Замість однієї події OrderCreated, яка містить всю інформацію про замовлення, ви генеруєте купу маленьких подій: OrderItemAdded, OrderItemRemoved, OrderAddressChanged і так далі. Це може призвести до створення "подійного хаосу", де підписники загрузнуть в обробці міріад дрібних подій.

Чому це відбувається?

  • Перевтома в прагненні зробити систему гнучкою.
  • Недосвідченість у проєктуванні архітектури подій.

Як уникнути?

  • Події повинні бути великоблоковими. Нехай кожна подія описує завершену дію.
  • Рефакторьте події. Якщо помітили, що ваші події занадто дрібні, об'єднуйте їх у більші, що містять контекст.

Антипатерн:

class OrderEvents {
    class OrderItemAdded { /* ... */ }
    class OrderItemRemoved { /* ... */ }
    class OrderAddressChanged { /* ... */ }
}

Кращий підхід:

class OrderCreatedEvent {
    private String orderId;
    private List<OrderItem> items;
    private Address shippingAddress;
    // Вся інформація тут!
}

Помилка №4: Ігнорування моніторингу і логування

Якщо ви не знаєте, що відбувається з вашими подіями, ви втрачаєте контроль над системою. Подія може застрягти, не дійти до підписника або викликати помилку, і ви навіть не дізнаєтеся про це.

Чому це відбувається?

  • Відсутність централізованого логування.
  • Невідповідність рівня моніторингу складності системи.

Як уникнути?

  • Інструменти для моніторингу: ELK-стек (Elasticsearch, Logstash, Kibana), Prometheus, Grafana.
  • Розподілений трасинг: Використовуйте Spring Sleuth і Zipkin для відстеження шляху подій у системі.
  • Оповіщення: Налаштуйте алерти, щоб дізнаватися про проблеми в режимі реального часу.

Приклад налаштування моніторингу з Grafana:

  1. Налаштуйте метрики в Prometheus.
  2. Створіть дашборд у Grafana для метрик, таких як затримка повідомлень, кількість подій на годину тощо.

Помилка №5: Відсутність стратегій при зростанні навантаження

Система працює нормально, коли у вас 100 подій на хвилину. А що буде, якщо їх стане 10 000? Або мільйон? Якщо ви не враховуєте зростання навантаження, ваша архітектура може впасти під її вагою.

Чому це відбувається?

  • Неправильний вибір інструментів (наприклад, використання RabbitMQ замість Kafka для високонавантажених систем).
  • Відсутність горизонтального масштабування.

Як уникнути?

  • Використовуйте брокери повідомлень, які підходять для вашого навантаження. Kafka відмінно справляється з мільйонами повідомлень, але не ідеальна для запитів з низькою затримкою.
  • Додавайте партиції. Kafka дозволяє горизонтально масштабувати продуктивність за допомогою партицій.
  • Проводьте навантажувальне тестування. Використовуйте інструменти, такі як Apache JMeter, для перевірки вашої архітектури.

Помилка №6: Неправильне управління життєвим циклом подій

Ваші події не повинні висіти в системі вічно. Якщо ви забуваєте очищати застарілі повідомлення або не налаштували retention policy, ви можете зіткнутися з переповненням брокера повідомлень.

Чому це відбувається?

  • Відсутність політики життєвого циклу подій.
  • Неправильні налаштування брокера повідомлень.

Як уникнути?

  • Очищення старих даних. Використовуйте налаштування retention.ms в Kafka для видалення застарілих повідомлень.
  • Автоматизація процесів. Налаштуйте скрипти для управління життєвим циклом і очищення даних.

Ми обговорили шість основних помилок, які можуть виникати при проєктуванні подійно-орієнтованих систем. Незважаючи на всю складність теми, якщо дотримуватись запропонованих рекомендацій, можна розробляти системи, які будуть не лише надійними, а й легко масштабованими.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ