# G. Event-driven development ## Drawbacks of traditional microservices architecture * **Operational cost** - need to maintain big number of services. Each service requires it’s own git repository, it’s own build, dependencies, bug tracker, README, wiki, documentation, etc. * **Maintenance** - upgrading core libraries for the huge number of microservices is time-consuming. Keeping unified standards is hard. * **Performance** - in-process function call of monolith tirns into a number of HTTP calls which is: perform TCP connections, serialization, HTTP transfer, deserialization, and back to complete a round trip. With any large dataset you’ll need to implement paging. * **Coupling** - if service cannot work properly without other services it depends on - they are tightly coupled, which is not a rare case. * **Higher level tooling** - microservices require additional attention to discover, monitor, control, and centrally configure services. * **Transactions** - distributed transactions are not easy to implement * **Locking** - microservices require distributed locking. * **Dependency hell** - services need to maintain contract backward compartibility * **Debugging** - monolith can be easily run localy, with microservices it's next to impossible. So the only way is rely on monitoring and logging tools * **Data transfer** - Microservices, by definition, are built to encapsulate, or hide, data. They are not built to transfer data between systems. ## Event-driven architecture The event-driven architecture pattern is a distributed asynchronous architecture pattern used to produce highly scalable applications. Being applied to microservices architecture it allows to **decouple** dependant services thus provides **scalability** and **stability**. Two main topologies, the **mediator** and the **broker**. ### Broker topology The mediator topology is useful for events that have multiple steps and require some level of orchestration to process the event. #### Components * Event queues * Event mediator * Event channels * Event processors #### Event flow * A client sending an event to an event queue, which is used to transport the **event to the event mediator**. * The **event mediator** receives the initial event and **orchestrates that even**t by sending additional asynchronous events to event channels to execute each step of the process. * Event processors, which listen on the event channels, receive the event from the event mediator and execute specific business logic to process the event. #### Mediator topology schema ![](https://i.imgur.com/VKfyqAx.png) #### Mediator topology use case example ![](https://i.imgur.com/p52S51Z.png) ### Broker topology The broker topology differs from the mediator topology in that there is **no central event mediator**; rather, the message **flow is distributed across the event processor components** in a chain-like fashion through a lightweight message broker (e.g., ActiveMQ, HornetQ, etc.). This topology is useful when you have a relatively **simple event processing flow** and you do not want (or need) central event orchestration. #### Components * Broker component - can be centralized or federated and contains all of the event channels that are used within the event flow * Event processors #### Event flow Each event-processor component is responsible for processing an event and publishing a new event indicating the action it just performed. #### Broker topology schema ![](https://i.imgur.com/JmkNHMp.png) #### Broker topology use case example ![](https://i.imgur.com/AuKbxko.png) ### Distributed transactions in asynchronous event-driven systems Use an event-driven, eventually consistent approach. Each service publishes an event whenever it update its data. Other service subscribe to events. When an event is received, a service updates its data. #### Example * The `Order Service` creates an Order in a pending state and publishes an `OrderCreated` event. * The `Customer Service` receives the event and attempts to reserve credit for that Order. It then publishes either a `CreditReserved` event or a `CreditLimitExceeded` event. * The `Order Service` receives the event from the `Customer Service` and changes the state of the order to either approved or cancelled ## Event sourcing ### Reasons to look at event sourcing Event-sourcing architecture claims to keep benefits of microservices like the concepts of team autonomy, modularization, and single responsibility that microservices provide, but at the same time to eliminate the coupling and dependency management that microservices provide. It is also provides the ability to access the raw data across systems in order to power new applications. It doesn't hide data, but exposes it. Data and access to it is key. ### Key concept * Requests are comands * Each command produces an event * All events are stored as a change log * This event log is a source of truth. It doesn't contain the final state but the log of changes instead. * Data is never deleted or modified as in traditional relational dbs * All applications can have their own storages to keep state view based on event source. ### Advantages * **Audit trail** * Event sourcing allows you to see the history of events and state changes over time. * Having a historical record acts as an audit trail, allowing you to trace back the history of a record over time. * **Complete Rebuild** * The current state of a system could be rebuilt by simply replaying the events. * Real time backup / restore or simplify disaster recovery scenarios by simply adding a second event consumer. * **Temporal query** — queries at different points in time. * You could replay events to a certain point in time, allowing you to query or examine or learn from data at various historical points. * You could also run multiple timelines or “what / if” scenarios in parallel to determine which of multiple algorithms would produce better results. * **Replay** * If bugs are found, the event history could be updated by inserting a reversing event. * Bugs impacts can be fixed by changing code and reprocessing the events. * **Scalability** * Systems can listen for events, process them in parallel. Clients can scale up the number of receivers. * **Loosely coupled** * Systems operate independently on only the data they care about, isolating themselves from other systems. * Easy to add new applications / combine streams without requiring involvement from the stream producer * **Performance** * Event sourcing allows you to keep data local to your application, avoiding costly network connections and REST calls. * Writes are high performance since the writer can write to disk sequentially and the reader can read from disk sequentially. * **Stability** * Systems are more resilient when they are loosely coupled. Many services don’t need to be available 99.99% of the time. Since services have their own local views of all required data they can function independently even in case other services are down. * **Debugging** * Event sourcing enables advanced debugging and diagnostic scenarios. Events could be replayed to help debug an invalid state. Or for testing different code branches for performance state of multiple other systems. * You can replay events into a clean room for debugging. ### Problems * **Events versioning** * Changed requirements may lead to changing event structure, while code should support all versions the events from the beginning of times to be able to replay them. * **Data duplication** * If many services require some common data (e.g. user data) they have to duplicate it and keep localy. * **Eventual consistency** * **Distribution of responsibility** * Since services are not responsible for their oen domain only but use raw data (events) of other services they need to be well aware of business logic and lifecycle of each domain entity to properly use the data. Example: Purchase service needs to validate if merchant is eligible for purchase. Assume that elligibility is defined by many factors (account status, country, previous purchases, etc) purchase survice and any other survice that requires to know merchant elligibility should know all these details. Alternatively their maybe separate service introduced which defines merchant elligibility and produces corresponding event which is used by all other services. ## CQRS CQRS stands for Command-Query Segregation Principle. CQRS states the fact that operations that trigger state transitions should be described as **commands** and any data retrieval should be named a **query**. Any operation should be either comand or query but not both. ### Commands * Successful execution of the command leads to the system **transition to a new state**. * Command conveys the **intent of the user** ### Queries * Allow **getting data** from the persistent store, so it can be shown to the user, sent to another system or used for any other purpose. * **Do not execute any operations** and should not contain any business logic. * Have **no side effects** and are completely **idempotent**