1. Challenges Faced While Migrating to or Implementing Microservices Architecture
a. Network Complexity and Latency
- Microservices are inherently distributed. Unlike monoliths, where communication is mostly in-memory, microservices use HTTP/gRPC over a network.
- Example: If Service A depends on B, and B is down, A will fail unless retry/circuit breaker is used. This introduces failure points and latency.
- Analogy: Imagine a relay race vs. a solo runner—each baton handoff (network call) increases the chances of a fumble (failure).
b. Distributed Transaction Management
- A single business transaction might span multiple services.
- Example: In an e-commerce app, placing an order updates the inventory, payment, and shipping services.
- Challenge: ACID transactions don’t work well here; use Saga Patterns instead.
c. Monitoring and Debugging
- Logs are spread across services.
- Requires centralized logging (e.g., ELK stack) and distributed tracing (e.g., Zipkin, Jaeger).
- Example: A bug in OrderService may originate from a downstream PaymentService.
d. Operational Complexity
- Multiple services mean more deployment pipelines, configs, and CI/CD jobs.
- Analogy: Managing one monolith is like managing one large pet. Microservices are like managing a farm of pets.
2. Importance of Containerization and Microservices
a. Addressing Diverse Technology Stacks
- Each microservice can use its own language or runtime.
- Example: ProductService in Node.js, UserService in Java.
- Containers abstract environment differences.
b. Resource Isolation
- Containers use namespaces and cgroups to limit CPU/memory.
- Prevents one service from hogging all the resources.
c. Scalability
- Services can be scaled independently.
- Example: PaymentService may need 10 replicas, while AuthService needs only 2.
d. Development Velocity
- Faster onboarding: Pull the Docker image and run it.
e. Technology Diversity
- Pick the best tool per service without tech lock-in.
3. Logging and Monitoring in Microservices
a. Centralized Logging
- Tools: ELK (Elasticsearch, Logstash, Kibana), Loki, Fluentd.
- Helps correlate logs using trace/request IDs.
b. Alerting
- Set alerts using Prometheus + AlertManager or Grafana.
- Example: CPU usage > 90%, or HTTP 5xx spikes trigger an alert.
4. Implementing Data Consistency Across Microservices
a. Saga Pattern
- Orchestrated Saga: Central orchestrator handles flow (e.g., Netflix Conductor).
- Choreographed Saga: Services publish/consume events.
- Example: Order → Payment → Inventory.
b. Eventual Consistency
- Not all services are updated immediately but will reach consistency.
- Trade-off against strict ACID.
5. Design Patterns Used in Microservices
a. API Gateway Pattern
- Single entry for external clients.
- Responsibilities: Routing, rate-limiting, auth, load balancing.
- Tools: Kong, Zuul, Spring Cloud Gateway.
b. Circuit Breaker Pattern
- Avoids continuous calls to failing services.
- Tools: Resilience4j, Hystrix (legacy).
- Analogy: Like a fuse in an electric circuit—prevents overload.
c. Bulkhead Pattern
- Isolate resources per service or module.
- Prevents cascading failures.
d. Strangler Fig Pattern
- Gradual migration from monolith to microservices.
- Example: Move one module at a time to a new service.
6. Handling Inter-Service Communication
a. Synchronous (REST/HTTP)
- Easy to implement but introduces tight coupling.
b. Asynchronous (Message Queues)
- Tools: Kafka, RabbitMQ.
- Decouples services, allows retry, improves resiliency.
c. gRPC
- Faster and lighter than REST.
- Binary protocol, supports streaming.
7. Deployment Strategies for Microservices
a. Blue-Green Deployment
- Maintain two environments. Switch traffic once green is verified.
- Zero downtime.
b. Canary Deployment
- Release to a small % of users first.
- Monitors errors before full rollout.
c. Rolling Deployment
- Replace instances one at a time.
d. A/B Testing
- Send traffic to different versions to test feature impact.
e. Feature Flag Strategy
- Toggle features on/off at runtime.
- Tools: LaunchDarkly, Unleash.
8. Additional Topics (Mentioned Briefly)
a. Database Design Choices
- Per-service DB recommended to avoid tight coupling.
- Shared DB is anti-pattern.
b. Versioning
- URI versioning:
/api/v1/product - Header-based versioning:
Accept: application/vnd.product.v1+json
c. Authentication & Authorization
- Use OAuth2 + JWT for token-based auth.
- API Gateway can handle auth checks.