- Published on
Java Interview Preparation - Microservices
- Authors
- Name
- Rahul Neelakantan
Advantages of microservices
- Independent development and deployment
- Fault isolation
- Technology diversity
- Scalability
- Easy to understand and maintain
- Faster development and testing
Challenges in moving from monolithic to microservices
- Decomposition: Breaking down the monolithic application into smaller services can be complex. It requires a deep understanding of the application and its dependencies.
- Data management: Data consistency and integrity can be challenging in a microservices architecture. Each service can have its own database and doesn't share data with other services.
- Inter-service communication: Services need to communicate with each other over the network. This can introduce latency and failure points.
- Service discovery: Services need to discover each other dynamically. This can be challenging in a dynamic environment where services can come and go.
- Monitoring and logging: Monitoring and logging become more complex in a microservices architecture. You need to monitor each service individually and aggregate the logs from all services.
- Testing: Testing a microservices architecture can be complex. You need to test each service individually and also test the interactions between services.
- Deployment: Deploying a microservices architecture can be complex due to inter-service dependencies.
- Security: Security becomes more complex in a microservices architecture. Due to the distributed nature of the architecture.
Common patterns used in communication between microservices
- REST, gRPC
- Messaging (Kafka, RabbitMQ)
- Service mesh
- API gateway
Microservice A, calls Microservice B (Rest API) - What could be the challenge in this architecture? (Related to Idempotency)
When Microservice A calls Microservice B via a REST API, idempotency can indeed be a challenge.
Repeated Calls: If Microservice A makes the same request multiple times to Microservice B (due to network issues, timeouts, etc.), it could lead to unwanted side effects if the operation is not idempotent. For example, if the operation is to create a new resource, it could result in duplicate resources.
Idempotency Key Management: To ensure idempotency, a unique key (idempotency key) is often associated with each request. Managing these keys can be complex. The service needs to store these keys and the result of the operation associated with them for some time.
State Management: To ensure idempotency, the service often needs to maintain the state of each operation. This can increase the complexity of the service.
Performance: Checking for idempotency (i.e., whether the same operation with the same idempotency key has been performed before) can add a performance overhead.
To handle these challenges, it's important to design the APIs in Microservice B to be idempotent where necessary. This means that no matter how many times Microservice A repeats the same request, the state of the system should remain the same after the first request.
Microservice Patterns
API Gateway Pattern: This pattern uses a single entry point for clients to access the microservices in the backend. The API Gateway handles requests in one of two ways: routing requests to the appropriate microservice, and processing requests by invoking multiple microservices and aggregating the results.
Circuit Breaker Pattern: This pattern prevents a network or service failure from cascading to other services. When a microservice invokes a remote service and the number of failed attempts crosses a threshold, the circuit breaker trips, and for the duration of a timeout period all attempts to invoke the remote service will fail immediately.
Saga Pattern: This pattern is used to manage transactions across multiple microservices. Instead of using a traditional distributed transaction, a saga splits the transaction into multiple local transactions, each local transaction updates data within a single service.
Event Sourcing Pattern: This pattern stores the state of a business entity as a sequence of state-changing events. When a state change is required, a new event is appended to the list of events. This allows the full history of actions to be replayed to reach the current state of an entity.
CQRS (Command Query Responsibility Segregation) Pattern: This pattern separates the read and write operations of a service. It allows you to scale read and write operations independently and optimize them separately.
Service Registry and Discovery Pattern: This pattern helps in automatic detection of network locations for service instances, which could have dynamically assigned network locations due to autoscaling, failures, or upgrades.
Sidecar Pattern: This pattern allows you to add functionality to a service without modifying the service itself by deploying it alongside the service as a sidecar application.
Bulkhead Pattern: This pattern isolates elements of an application into pools so that if one fails, the others will continue to function. It's named after the sectioned partitions (bulkheads) of a ship's hull. If the hull of a ship is compromised, only the damaged section fills with water, which prevents the ship from sinking.