10 Common Microservice Pitfalls and How to Avoid Them
This article examines ten typical problems encountered when adopting microservices—such as improper service splitting, distributed transaction failures, configuration chaos, logging fragmentation, database sharing, API incompatibility, CI bottlenecks, monitoring gaps, and team collaboration issues—and provides concrete solutions, best‑practice principles, code examples, and architectural guidelines to help engineers build reliable, maintainable microservice systems.
Preface
As a seasoned practitioner who has led three microservice refactorings, I have seen many teams fall into microservice traps: the excitement of splitting services is quickly followed by painful operational overhead.
For example, after a large e‑commerce platform split its monolith into 120 microservices, the failure rate jumped 300% and troubleshooting time grew from 10 minutes to 3 hours.
This article discusses the ten most common microservice problems and offers practical guidance.
1. Wrong Service Splitting
Typical scenario: splitting services by code package name.
Consequences:
Order query requires calls to four services.
Interface latency increases from 50 ms to 350 ms.
Trace logs explode in volume.
Correct approach: split by business capability.
Splitting principles:
Single responsibility – one service solves one type of problem.
Team autonomy – a “two‑pizza” team can deliver independently.
Data autonomy – each service owns its own database.
2. Distributed Transaction Issues
Wrong example: cross‑service database operations.
@Transactional
// Local transaction ineffective!
public void createOrder(OrderDTO dto) {
// 1. Order service writes DB
orderService.save(dto);
// 2. Call inventory service
stockFeignClient.deduct(dto.getSkuId());
}Consequence: order created but inventory not deducted → oversell.
Solution: Saga pattern + reliable events.
Implementation example:
@SagaStart
public void createOrder(OrderDTO dto) {
Saga.with("freezeStock", () -> stockClient.freeze(dto))
.with("saveOrder", () -> orderService.save(dto))
.compensate("saveOrder", () -> orderService.delete(dto.getId()))
.compensate("freezeStock", () -> stockClient.unfreeze(dto))
.execute();
}3. Cascading Failure (Snowball Effect)
Scenario: Service A → Service B → Service C, and C times out, causing the whole chain to collapse.
Defense: circuit breaker + downgrade + timeout.
@FeignClient(name = "stock-service", configuration = FeignConfig.class, fallback = StockFallback.class)
public interface StockClient {
@GetMapping("/deduct")
@TimeLimiter(fallbackMethod = "defaultResult") // timeout control
CompletableFuture<Boolean> deduct(@RequestParam String skuId);
}
circuitBreaker:
failureRateThreshold: 50
waitDurationInOpenState: 10s
slidingWindowSize: 204. Configuration Chaos
Anti‑pattern: configuration files scattered across services.
user-service
├─ application-dev.yml
└─ application-prod.yml
order-service
├─ application-dev.yml
└─ application-prod.ymlConsequences:
Changing a log level requires redeploying ten services.
Production accidentally uses dev configuration.
Correct solution: centralized configuration center.
spring:
cloud:
nacos:
config:
server-addr: 192.168.1.10:8848
file-extension: yaml
shared-configs:
- data-id: common.yaml # common config5. Log Tracing Fragmentation
Problem: logs are split across three systems, making end‑to‑end tracing painful.
[user-service] User query succeeded userId=100
[order-service] Order creation failed userId=100
[payment-service] Payment timeout userId=100Pain: stitching three log systems together.
Solution: Sleuth + Zipkin full‑link tracing.
2023-08-20 14:30 [user-service,7a3b,9f2c] INFO User query
2023-08-20 14:30 [order-service,7a3b,d8e1] ERROR Order creation failed7a3b – global trace ID; 9f2c/d8e1 – service‑specific IDs.
6. Database Splitting Issues
Wrong practice: multiple services share the same database.
Consequences:
Order table lock blocks user registration.
Cannot scale services independently.
Correct design: vertical database split per service.
// Sharding by user ID
public String determineDatabase(Long userId) {
int dbIndex = (int) (userId % 4);
return "user_db_" + dbIndex;
}7. API Compatibility Issues
Incident: order service upgraded to v2 without notifying the payment service.
Solution: three‑version strategy (v1, v2, v3) and Spring Cloud gray release.
/v1/createOrder // old version
/v2/createOrder // new version
/v3/createOrder // pre‑release
spring:
cloud:
gateway:
routes:
- id: order_v2
uri: lb://order-service
predicates:
- Header=version, v2
filters:
- StripPrefix=18. Continuous Integration Bottleneck
Typical problem: 120 services built independently, causing pipeline congestion.
Optimization: layered builds and parallel execution.
stage('Parallel Build') {
parallel {
stage('Service A') { steps { sh './build-serviceA.sh' } }
stage('Service B') { steps { sh './build-serviceB.sh' } }
}
}9. Monitoring Gaps
Painful lessons:
Disk filled for 8 hours without detection.
Database connection pool exhausted, causing a site‑wide crash.
Golden four monitoring components:
rules:
- alert: HighErrorRate
expr: sum(rate(http_server_requests_errors_total[5m])) > 0.5
for: 2m
- alert: DBConnectionExhausted
expr: db_connections_active > db_connections_max * 0.9
for: 1m10. Team Collaboration Issues
Reality: different teams use different tech stacks and deployment methods.
Team
Tech Stack
Deployment
User Group
Java + MySQL
K8s
Order Group
Go + Postgres
VM
Payment Group
Node + Mongo
Serverless
10.1 Unified Technical Conventions
RESTful API standards.
Global error‑code definitions.
Standardized log format.
Health‑check endpoint /actuator/health.
10.2 Shared Infrastructure
Summary
Microservices bring many challenges; only teams with rich practical experience can master them.
Three‑layer defense system:
Ten microservice commandments:
Service granularity follows business capability, not code size.
Use eventual consistency instead of strong cross‑service transactions.
Configure circuit‑breaker and timeout thresholds.
Manage all environment parameters via a unified config center.
Propagate a full‑link trace ID across all services.
Each service owns its own database.
Maintain at least two API versions for compatibility.
Build layered CI pipelines.
Achieve 100% core‑metric monitoring coverage.
Define cross‑team technical conventions.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
