Enterprise Microservices Design [Part 3: Outer Architecture Zone]
The outer architecture is the space between microservices and is by far the most difficult part. Microservices is a tradeoff from inner complexity to outer complexity. Think of it as anything that is not the responsibility of an individual microservice team.
The outer architecture includes all of the infrastructures on which individual microservices are deployed, discovering and connecting to microservices, and releasing new versions of microservices, communicating between microservices, and security. It’s a wide area that can become complex. Following are the typical components of outer architecture zone
- API Gateway
- Load Balancer
- Service Registry
- Service Discovery
- Container Management
- Integration Microservices
- Configuration Management
Implementing and setting up most of these components are pretty standard and are usually handled by a dedicated DevOps team. From the development standpoint Integration microservices are necessary and the rest of the article focus on its design and implementation
3.1 Microservices Integration
Microservices are fine-grained, which means that clients need to interact with multiple microservices. In theory, the client could make requests to each of the microservices directly because each microservice has a public endpoint. However, this approach will produce considerable subsequent problems such as mismatches between the needs of the client and the fine‑grained APIs, non-uniform interfaces and protocols, duplication of code, etc
Because of these kinds of problems, it rarely makes sense for clients to talk to inner zone microservices directly. When designing and building large or complex microservice-based applications, a good approach to consider is using intermediaries. Intermediaries facilitate communication between the clients and microservices, performing functions that improve efficiency. They can be implemented as dedicated, purpose-built devices, but increasingly in modern web architectures, they are software applications that run on commodity hardware.
End-to-end business processes often involve numerous microservices, and their interaction must be organized using Intermediaries, in which microservices either call each other directly (Request / Response Pattern) or communicate only indirectly via events published on a central message or event bus (Publish / Subscribe Pattern).
Two commonly used integration patterns in microservices are:
- Microservices Orchestration
- Microservices Choreography
Classically, Orchestration denotes a guided execution inside one closed/bounded context conducted by some entity, in contrast to
Choreography, which is more about different multiple closed/bounded contexts exchanging messages, by knowing on what message to react how
3.1.2 Microservices Orchestration
Orchestration is the traditional way of handling interactions between different services in Service-Oriented Architecture (SOA). With orchestration, there is typically one controller that acts as the “orchestrator” of the overall service interactions. This typically follows a request/response type pattern. The client reaches the orchestrator for the services and orchestrator interacts with multiple microservices, aggregates and processes the data from all these microservices, and then responds back to the client.
For Microservices orchestration we use the BPMN tools like Camunda, JBPM, Activiti.
Our personal recommendation is Camunda. Camunda is lightweight and can be embedded inside a microservice, and it’s easy to deploy in a wide range of cloud and on-premises environments. Camunda acts as an orchestrator that uses process flow to drive the orchestration and business processing logic. Its also provides convenient tools to visualize the process flows
3.1.2 Microservices Choregraphy
In the Choregraphy pattern, each component of the system participates in the decision-making process about the workflow of a business transaction, instead of relying on a central point of control. One way to implement choreography is to use the asynchronous messaging pattern to coordinate the business operations.
A client request publishes messages to a message queue. As messages arrive, they are pushed to subscribers, or services, interested in that message. Each subscribed service does their operation as indicated by the message and responds to the message queue with success or failure of the operation. In case of success, the service can push a message back to the same queue or a different message queue so that another service can continue the workflow if needed. If an operation fails, the message bus can retry that operation. This way, the services choreograph the workflow among themselves without depending on an orchestrator or having direct communication between them.
Because there isn’t point-to-point communication, this pattern helps reduce coupling between services. Also, it can remove the performance bottleneck caused by the orchestrator when it has to deal with all transactions.
- Use choreography patterns if you expect to update, remove, or add new services frequently. The entire app can be modified with lesser effort and minimal disruption to existing services.
- Increased performance
Please keep in mind decentralizing the orchestrator can cause the following issues while managing the workflow.
- If a service fails to complete a business operation, it can be difficult to recover from that failure.
- The choreography pattern becomes a challenge if the number of services grows rapidly. Given the high number of independent moving parts, the workflow between services tends to get complex. Also, distributed tracing becomes difficult.
- Each service isn’t only responsible for the resiliency of its operation but also the workflow. This responsibility can be burdensome for the service and hard to implement.