Tuesday, December 31, 2019

MSA Data Mgmt patterns -> Event sourcing


Pattern: Event sourcing
Event sourcing is a great way to atomically update state and publish events. The traditional way to persist an entity is to save its current state. Event sourcing uses a radically different, event-centric approach to persistence. A business object is persisted by storing a sequence of state changing events. Whenever an object’s state changes, a new event is appended to the sequence of events. Since that is one operation it is inherently atomic. A entity’s current state is reconstructed by replaying its events.
To see how event sourcing works, consider the Order entity. Traditionally, each order maps to a row in an ORDER table along with rows in another table like the ORDER_LINE_ITEM table. But when using event sourcing, the Order Service stores an Order by persisting its state changing events: Created, Approved, Shipped, Cancelled. Each event would contain sufficient data to reconstruct the Order’s state.

Events are persisted in an event store. Not only does the event store act as a database of events, it also behaves like a message broker. It provides an API that enables services to subscribe to events. Each event that is persisted in the event store is delivered by the event store to all interested subscribers. The event store is the backbone of an event-driven microservices architecture.
In this architecture, requests to update an entity (either an external HTTP request or an event published by another service) are handled by retrieving the entity’s events from the event store, reconstructing the current state of the entity, updating the entity, and saving the new events.
Here is how the Order Service handles a request to update an Order


Other benefits of event sourcing

As you can see, event sourcing addresses a challenge of implementing an event-driven architecture. Additional significant benefits of persisting business events include the following:
·         100% accurate audit logging - Auditing functionality is often added as an afterthought, resulting in an inherent risk of incompleteness. With event sourcing, each state change corresponds to one or more events, providing 100% accurate audit logging.
·         Easy temporal queries - Because event sourcing maintains the complete history of each business object, implementing temporal queries and reconstructing the historical state of an entity is straightforward.

Event sourcing also has several drawbacks:
  • It is a different and unfamiliar style of programming and so there is a learning curve.
  • The event store is difficult to query since it requires typical queries to reconstruct the state of the business entities. That is likely to be complex and inefficient. As a result, the application must use Command Query Responsibility Segregation (CQRS) to implement queries. This in turn means that applications must handle eventually consistent data.
  • The Saga and Domain event patterns create the need for this pattern.
  • The CQRS must often be used with event sourcing.
  • Event sourcing implements the Audit logging pattern.




MSA Data Mgmt patterns -> Domain event


Domain event

Context
A service often needs to publish events when it updates its data. These events might be needed, for example, to update a CQRS view. Alternatively, the service might participate in an choreography-based saga, which uses events for coordination.

Problem
How does a service publish an event when it updates its data?

Solution
Organize the business logic of a service as a collection of DDD aggregates that emit domain events when they created or updated. The service publishes these domain events so that they can be consumed by other services.

Related patterns
·         The Saga and CQRS patterns create the need for this pattern
·         The Aggregate pattern is used to structure the business logic
·         The Transactional outbox pattern is used to publish events as part of a database transaction
·         Event sourcing is sometimes used to publish domain events

MSA Data mgmt patterns -> Command Query Responsibility Segregation (CQRS)

Problem

Once we implement database-per-service, there is a requirement to query, which requires joint data from multiple services — it's not possible. Then, how do we implement queries in microservice architecture?

 Solution

 CQRS suggests splitting the application into two parts — the command side and the query side.

  • The command side handles the Create, Update, and Delete requests.
  • The query side handles the query part by using the materialized views.
The event sourcing pattern is generally used along with it to create events for any data change. Materialized views are kept updated by subscribing to the stream of events.

MSA Data mgmt patterns - API Composition


API Composition

You have applied the Microservices architecture pattern and the Database per service pattern. As a result, it is no longer straightforward to implement queries that join data from multiple services.
This pattern is a direct solution to the problem of implementing complex queries in a microservices architecture.
In this pattern, an API Composer invokes other microservices in the required order. And after fetching the results it performs an in-memory join of the data before providing it to the consumer.
As evident, the downside to this pattern is the use of inefficient in-memory joins on potentially large datasets.

Problem

How to implement queries in a microservice architecture?

Solution

Implement a query by defining an API Composer, which invoking the services that own the data and performs an in-memory join of the results.

Example

An API Gateway often does API composition.

This pattern has the following benefits:
  • It a simple way to query data in a microservice architecture
This pattern has the following drawbacks:
  • Some queries would result in inefficient, in-memory joins of large datasets.

MSA Data mgmt patterns - Saga Pattern

Problem

When each service has its own database and a business transaction spans multiple services, how do we ensure data consistency across services? For example, for an e-commerce application where customers have a credit limit, the application must ensure that a new order will not exceed the customer’s credit limit. Since Orders and Customers are in different databases, the application cannot simply use a local ACID transaction.

Solution

The Saga pattern is the solution to implementing business transactions spanning multiple microservices.

Saga is basically a sequence of local transactions. For every transaction performed within a Saga, the service performing the transaction publishes an event. The subsequent transaction is triggered based on the output of the previous transaction. And if one of the transactions in this chain fails, the Saga executes a series of compensating transactions to undo the impact of all the previous transactions. It can be implemented in two ways:

  1. Choreography — When there is no central coordination, each service produces and listens to another service’s events and decides if an action should be taken or not.
  2. Orchestration — An orchestrator (object) takes responsibility for a saga’s decision making and sequencing business logic.

The Saga pattern is one of the microservice design patterns that allow you to manage such transactions using a sequence of local transactions. Each transaction is followed by an event that triggers the next transaction step.

If one transaction fails, the saga pattern triggers a rollback transaction compensating for the failure.


Example: Managing multiple eCommerce transactions with a Saga pattern

Here’s an example of an eCommerce application that consists of multiple transactions for orders, payment, inventory, shipping, and notifications. Once an order is generated for a specific product, the next transaction for the payment and the inventory update is initialized.



If the transaction for inventory update fails, for example, due to unavailability of a product, a rollback is triggered. If the transaction for inventory update is successful further transactions are initialized.

Moreover, Saga transactions don’t need to know about the command or the role of other transactions. This allows developers to build simplified business logic with clear separation of concerns.

This pattern is suggested for applications where ensuring data consistency is critical without tight coupling. Likewise, it’s less suitable for applications with tight coupling.


MSA Data mgmt patterns - Shared Database per Service

Problem

We have talked about one database per service being ideal for microservices, but that is possible when the application is greenfield and to be developed with DDD. But if the application is a monolith and trying to break into microservices, denormalization is not that easy. What is the suitable architecture in that case?

Solution

A shared database per service is not ideal, but that is the working solution for the above scenario. Most people consider this an anti-pattern for microservices, but for brownfield applications, this is a good start to break the application into smaller logical pieces. This should not be applied for greenfield applications. In this pattern, one database can be aligned with more than one microservice, but it has to be restricted to 2-3 maximum, otherwise scaling, autonomy, and independence will be challenging to execute.


Shared Database per Service
Use a (single) database that is shared by multiple services. Each service freely accesses data owned by other services using local ACID transactions.

Example
The OrderService and CustomerService freely access each other’s tables. For example, the OrderService can use the following ACID transaction ensure that a new order will not violate the customer’s credit limit.
BEGIN TRANSACTION
SELECT ORDER_TOTAL
 FROM ORDERS WHERE CUSTOMER_ID = ?
SELECT CREDIT_LIMIT
FROM CUSTOMERS WHERE CUSTOMER_ID = ?
INSERT INTO ORDERS …
COMMIT TRANSACTION
The database will guarantee that the credit limit will not be exceeded even when simultaneous transactions attempt to create orders for the same customer.

The benefits of this pattern are:
·         A developer uses familiar and straightforward ACID transactions to enforce data consistency
·         A single database is simpler to operate.

The drawbacks of this pattern are:
· Development time coupling - a developer working on, for example, the OrderService will need to coordinate schema changes with the developers of other services that access the same tables. This coupling and additional coordination will slow down development.
·   Runtime coupling - because all services access the same database they can potentially interfere with one another. For example, if long running CustomerService transaction holds a lock on the ORDER table then the OrderService will be blocked.
·    Single database might not satisfy the data storage and access requirements of all services.

MSA Database Patterns - Database per Service

Problem

There is a problem of how to define database architecture for microservices. Following are the concerns to be addressed:

·         Services must be loosely coupled. They can be developed, deployed, and scaled independently.
·         Business transactions may enforce invariants that span multiple services.
·         Some business transactions need to query data that is owned by multiple services.
·         Databases must sometimes be replicated and shared to scale.
·         Different services have different data storage requirement

 Solution

To solve the above concerns, One database per microservice must be designed; it must be private to that service only. It should be accessed by the microservice API only. It cannot be accessed directly by other services.

There are a few different ways to keep a service’s persistent data private. You do not need to provision a database server for each service. For example, if you are using a relational database then the options are:
·         Private-tables-per-service – each service owns a set of tables that must only be accessed by that service
·         Schema-per-service – each service has a database schema that’s private to that service
·         Database-server-per-service – each service has its own database server.
Private-tables-per-service and schema-per-service have the lowest overhead. Using a schema per service is appealing since it makes ownership clearer. Some high throughput services might need their own database server.

Using a database per service has the following benefits:
·         Helps ensure that the services are loosely coupled. Changes to one service’s database does not impact any other services.
·         Each service can use the type of database that is best suited to its needs. For example, a service that does text searches could use ElasticSearch. A service that manipulates a social graph could use Neo4j.

Using a database per service has the following drawbacks:
·         Implementing business transactions that span multiple services is not straightforward. Distributed transactions are best avoided because of the CAP theorem. Moreover, many modern (NoSQL) databases don’t support them.
·         Implementing queries that join data that is now in multiple databases is challenging.
·         Complexity of managing multiple SQL and NoSQL databases.

There are various patterns/solutions for implementing transactions and queries that span services:
·         Implementing transactions that span services - use the Saga pattern.
·         Implementing queries that span services:
o    API Composition - the application performs the join rather than the database. For example, a service (or the API gateway) could retrieve a customer and their orders by first retrieving the customer from the customer service and then querying the order service to return the customer’s most recent orders.
o    Command Query Responsibility Segregation (CQRS) - maintain one or more materialized views that contain data from multiple services. The views are kept by services that subscribe to events that each services publishes when it updates its data. For example, the online store could implement a query that finds customers in a particular region and their recent orders by maintaining a view that joins customers and orders. The view is updated by a service that subscribes to customer and order events.

It is a good idea to create barriers that enforce this modularity. You could, for example, assign a different database user id to each service and use a database access control mechanism such as grants. Without some kind of barrier to enforce encapsulation, developers will always be tempted to bypass a service’s API and access it’s data directly.

MSA Decomposition Pattern - Decompose by Subdomain

Problem

Decomposing an application using business capabilities might be a good start, but you will come across so-called "God Classes" which will not be easy to decompose. These classes will be common among multiple services. For example, the Order class will be used in Order Management, Order Taking, Order Delivery, etc. How do we decompose them?

Solution

For the "God Classes" issue, DDD (Domain-Driven Design) comes to the rescue. It uses subdomains and bounded context concepts to solve this problem. DDD breaks the whole domain model created for the enterprise into subdomains. Each subdomain will have a model, and the scope of that model will be called the bounded context. Each microservice will be developed around the bounded context.

Note: Identifying subdomains is not an easy task. It requires an understanding of the business. Like business capabilities, subdomains are identified by analyzing the business and its organizational structure and identifying the different areas of expertise.

The subdomains of an Order management include:
·         Product catalog service
·         Inventory management services
·         Order management services
·         Delivery management services

MSA Decomposition Pattern: Decompose by business capability


Pattern: Decompose by business capability

Problem

Microservices is all about making services loosely coupled, applying the single responsibility principle. However, breaking an application into smaller pieces has to be done logically. How do we decompose an application into small services?

Solution

One strategy is to decompose by business capability. A business capability is something that a business does in order to generate value. The set of capabilities for a given business depend on the type of business. For example, the capabilities of an insurance company typically include sales, marketing, underwriting, claims processing, billing, compliance, etc. Each business capability can be thought of as a service, except it’s business-oriented rather than technical.

 e.g.

  • Order Management is responsible for orders.
  • Customer Management is responsible for customers.

Microservice Architecture Design patterns


What are Microservices?
Microservices is an architectural style that structures an application as a collection of small autonomous services, modeled around a business domain. In a Microservice Architecture, each service is self-contained and implements a single business capability.
Principles Used to Design Microservice Architecture
The principles used to design Microservices are as follows:
1.    Independent & Autonomous Services
2.    Scalability
3.    Decentralization
4.    Resilient Services
5.    Real-Time Load Balancing
6.    Availability
7.    Continuous delivery through DevOps Integration
8.    Seamless API Integration and Continuous Monitoring
9.    Isolation from Failures
10. Auto -Provisioning







Application architecture patterns
  • Monolithic architecture
  • Microservice architecture

Decomposition

Refactoring to microservices

Data management
Transactional messaging
  • Transactional outbox
  • Transaction log tailing
  • Polling publisher
Testing
  • Service Component Test
  • Consumer-driven contract test
  • Consumer-side contract test
Deployment patterns
  • Multiple service instances per host
  • Service instance per host
  • Service instance per VM
  • Service instance per Container
  • Serverless deployment
  • Service deployment platform
Cross cutting concerns
Communication style
  • Remote Procedure Invocation
  • Messaging
  • Domain-specific protocol
External API
  • Client-side discovery
  • Server-side discovery
  • Service registry
  • Self registration
  • 3rd party registration
Reliability
Security
  • Access Token
Observability
UI patterns
Microservices architecture involves designing and building a software system as a collection of small, independent, and loosely coupled services. Various design patterns have emerged to address common challenges associated with building and maintaining microservices-based systems. Here are some key microservices design patterns:
  1. Service Registry and Discovery:
    • Pattern: Service Discovery
    • Description: A service registry is used to keep track of the available microservices and their locations. Services register themselves with the registry, and clients can discover and communicate with services through the registry.
    • Benefits: Enables dynamic scaling and seamless service discovery.
  2. API Gateway:
    • Pattern: API Gateway
    • Description: An API Gateway acts as a single entry point for managing requests from clients. It can handle tasks such as authentication, authorization, and request routing to different microservices.
    • Benefits: Simplifies client communication and provides a centralized point for managing cross-cutting concerns.
  3. Circuit Breaker:
    • Pattern: Circuit Breaker
    • Description: Introduces a circuit breaker mechanism to prevent a microservice from repeatedly attempting to execute an operation that is likely to fail. If the failure rate exceeds a threshold, the circuit breaker opens, preventing further attempts until the system stabilizes.
    • Benefits: Improves system resilience by avoiding cascading failures.
  4. Event Sourcing:
    • Pattern: Event Sourcing
    • Description: Instead of storing only the current state of data, all changes to the state are captured as a sequence of events. The system's state can be reconstructed at any point by replaying the events.
    • Benefits: Provides a reliable audit trail, supports scalability, and allows for building event-driven architectures.
  5. Saga Pattern:
    • Pattern: Saga Pattern
    • Description: Manages distributed transactions across multiple microservices by breaking them into a series of smaller, independent transactions (sagas). Each saga has its own compensating transactions to handle failures and ensure eventual consistency.
    • Benefits: Enables long-running business transactions in a distributed environment.
  6. Bulkhead Pattern:
    • Pattern: Bulkhead Pattern
    • Description: Segregates components into isolated pools to prevent the failure of one component from affecting others. For example, thread pools can be used to isolate requests to a specific microservice.
    • Benefits: Enhances system resilience by isolating failures and limiting their impact.
  7. Choreography vs. Orchestration:
    • Pattern: Choreography and Orchestration
    • Description: Defines how microservices collaborate to achieve a specific goal. Choreography is a decentralized approach where each service communicates directly with others. Orchestration is a centralized approach where a central component (orchestrator) coordinates the interactions.
    • Benefits: Flexibility with choreography and centralized control with orchestration.
  8. Polyglot Persistence:
    • Pattern: Polyglot Persistence
    • Description: Recommends using different data storage technologies for different microservices based on the specific data requirements of each service.
    • Benefits: Optimizes data storage choices for individual microservices.
  9. Cross-Cutting Concerns:
    • Pattern: Microservices Centralized Configuration
    • Description: Manages cross-cutting concerns such as logging, monitoring, and configuration in a centralized manner to ensure consistency across microservices.
    • Benefits: Simplifies management and ensures uniformity of concerns.

These patterns provide solutions to common challenges in microservices architecture, promoting scalability, resilience, and maintainability in distributed systems. Depending on specific use cases, additional patterns and variations may be applied.


Here are some common database patterns associated with microservices:

  1. Database per Service:
    • Pattern: Database per Service
    • Description: Each microservice has its own dedicated database. Microservices communicate with each other through well-defined APIs, and each service is responsible for its own data storage and retrieval.
    • Benefits: Provides strong isolation between microservices, allowing them to choose the most suitable database technology for their specific needs.
  2. Shared Database:
    • Pattern: Shared Database
    • Description: Multiple microservices share a common database. This pattern is often seen in legacy systems, but it can lead to tight coupling between services and hinder independent development and scaling.
    • Considerations: Can create dependencies between services and make it challenging to evolve or scale independently.
  3. API Composition:
    • Pattern: API Composition
    • Description: Instead of relying on a single microservice to fetch and aggregate data from multiple sources, each microservice retrieves and composes its own data through API calls. This pattern helps maintain independence and scalability.
    • Benefits: Reduces dependencies between microservices, allowing them to evolve independently.
  4. CQRS (Command Query Responsibility Segregation):
    • Pattern: CQRS
    • Description: Separates the read and write operations of a system. Commands (updates) and queries (reads) are handled by different components, often with separate databases optimized for their respective operations.
    • Benefits: Optimizes performance for read and write operations independently and allows for scalability based on different usage patterns.
  5. Database Sharding:
    • Pattern: Database Sharding
    • Description: Divides a large database into smaller, more manageable pieces (shards) based on certain criteria. Each shard can be hosted on a separate server or cluster.
    • Benefits: Improves scalability by distributing data across multiple servers, reducing the load on a single database.
  6. Read Replicas:
    • Pattern: Read Replicas
    • Description: For microservices with heavy read workloads, create read-only replicas of the database to handle read requests. The replicas can be distributed geographically to improve performance.
    • Benefits: Enhances read scalability and offloads read operations from the primary database.

Choosing the right database pattern for each microservice depends on factors such as data consistency requirements, scalability needs, and the specific use cases of each service. It's common to use a combination of these patterns within a microservices architecture based on the characteristics of individual services.

Aggregator Pattern

Problem

We have talked about resolving the aggregating data problem in the API Gateway Pattern. However, we will talk about it here holistically. When breaking the business functionality into several smaller logical pieces of code, it becomes necessary to think about how to collaborate the data returned by each service. This responsibility cannot be left with the consumer, as then it might need to understand the internal implementation of the producer application.

 Solution

The Aggregator pattern helps to address this. It talks about how we can aggregate the data from different services and then send the final response to the consumer. This can be done in two ways:

1. A composite microservice will make calls to all the required microservices, consolidate the data, and transform the data before sending back.

2. An API Gateway can also partition the request to multiple microservices and aggregate the data before sending it to the consumer.

It is recommended if any business logic is to be applied, then choose a composite microservice. Otherwise, the API Gateway is the established solution.

This pattern can be useful when a developer seeks an output by combining data from multiple services.

If there are two services, each with its own database, an aggregator with a unique transaction ID can collect data from each, apply the business logic, and publish it as a REST endpoint. Then, the data collected can be handed over to whichever respective microservices require it.


Blue-Green Deployment Pattern

 Problem

With microservice architecture, one application can have many microservices. If we stop all the services then deploy an enhanced version, the downtime will be huge and can impact the business. Also, the rollback will be a nightmare. How do we avoid or reduce downtime of the services during deployment?

Solution

The blue-green deployment strategy can be implemented to reduce or remove downtime. It achieves this by running two identical production environments, Blue and Green. Let's assume Green is the existing live instance and Blue is the new version of the application. At any time, only one of the environments is live, with the live environment serving all production traffic. All cloud platforms provide options for implementing a blue-green deployment.

There are many other patterns used with microservice architecture, like Sidecar, Chained Microservice, Branch Microservice, Event Sourcing Pattern, Continuous Delivery Patterns, and more. The list keeps growing as we get more experience with microservices. I am stopping now to hear back from you on what microservice patterns you are using.