Some other patterns such as database per service and shared database per service is mandatory.
1. CQRS Command Query Responsibility Segregation
CQRS means Command Query Responsibility Segregation. As the name implies, it is about separating the responsibility of writing and reading of data. CQRS is a code pattern and not an architectural pattern. It provide a way to optimise the database.
Return back result
In asynchronous workflow, it’s impossible to return the result thought the avocation path. There are several ways to return the result back to the caller. Note that it’s only an acknowledgment that the message has been store in queue.
- Using long polling technique, do it via another API endpoint. Let’s say we return the 302 status with location.
- Using webhooks. Of course, the client must provide webhooks. It should be a client as server.
- AWS WebSocket APIs
This asynchronous approach is not fit for all designs. It’s good for handling unpredictable traffic with significant volumes. So it’s not suitable for every use case. It’s better for scalability operations. There is no good design, only fit design for specific case.
Use cases:
- You implemented the database-per-service pattern and want to join data from multiple microservices.
- Your read and write workloads have separate requirements for scaling, latency, and consistency.
- Eventual consistency is acceptable for the read queries.
2. Event Sourcing
This pattern often used along with CQRS pattern.
Store events:
- AWS Eventbridge.
- Dynamodb if need to serve event like database in order to return GET response event event is being processed. Check the instruction here.
- Kinesis with S3.
Use case:
- Events are used to completely rebuild the application’s state.
- You require events to be replayed in the system, and that an application’s state can be determined at any point in time.
- You want to be able to reverse specific events without having to start with a blank application state.
- Your system requires a stream of events that can easily be serialized to create an automated log.
- Your system requires heavy read operations but is light on write operations; heavy read operations can be directed to an in-memory database, which is kept updated with the events stream.
3. Saga pattern
This pattern is for failure management. This help to build the consistency of data. Each service will handle both success and failure. We put the services in sequence. Many services need to work together to complete a task.
Imagine that we have many services: order, payment and inventory. When a users create an order. We need to check the payment and minus an amount of money in their account. But what we will do if then it check the inventory and no item left? How to rollback this money?
There are two types of implementation:
- Choreography/ˌkɔːriˈɑːɡrəfi/: we develop event sourcing using message broker and other services will listen for events and proceed them locally both success and failure. But if the saga workflow steps increase, it becomes hard to manage.
- Orchestration/ˌɔːrkɪˈstreɪʃn/: we build an orchestration service to call other services locally, gathering the inputs, outputs, make them processed in order. Can use lambda step function to implement this pattern. It’s good for many steps of workflow.
Use case: use this pattern if it requires data consistency and rollback mechanism.
4. Proxy microservice pattern
This proxy is at the request level. It’s really good at transition time when we are moving monolith application to Microservices. A proxy service will represent the monolith application. Behind this proxy, it will send request to other services.
5. API composing pattern
A service calls other service APIs separately to get results and join them in-memory combination. Use it if we need to join data from multiple services. We can not avoid this in distributed system.
Distributed system as well as Microservices are for scalable system. We don’t have to apply all patterns due to complex implementation, pros and cons of it. No code, no issue with code. Keep it simple and extending it carefully.