Pular para o conteúdo principal

Capítulo 1: Introdução aos Microservices

🎯 Objetivos do Capítulo​

  • Compreender a diferença entre monolito e microservices
  • Identificar as vantagens e desvantagens de cada abordagem
  • Descobrir os padrões essenciais dos microservices
  • Dominar os princípios da 12-Factor App
  • Saber quando escolher qual arquitetura

1. Arquitetura Monolítica​

1.1 Definição​

Um monolito é uma aplicação onde todas as funcionalidades são implantadas juntas em um único processo.

1.2 Exemplo: E-Commerce Monolítico​

// Structure typique d'un monolithe
src/main/java/com/ecommerce/
├── EcommerceApplication.java
├── config/
│ └── SecurityConfig.java
├── controller/
│ ├── UserController.java
│ ├── ProductController.java
│ ├── OrderController.java
│ ├── PaymentController.java
│ └── InventoryController.java
├── service/
│ ├── UserService.java
│ ├── ProductService.java
│ ├── OrderService.java
│ ├── PaymentService.java
│ └── InventoryService.java
├── repository/
│ ├── UserRepository.java
│ ├── ProductRepository.java
│ ├── OrderRepository.java
│ └── ...
└── model/
├── User.java
├── Product.java
├── Order.java
└── ...

1.3 Vantagens do Monolito​

VantagemExplicação
Simplicidade de desenvolvimentoUm único projeto, uma única IDE
Deploy simplesUm único JAR/WAR para implantar
Testes fáceisTestes de integração simples
Transações ACIDUm único BD = transações fáceis
Debugging simplesStack trace completo
Performance localSem latência de rede entre módulos
Refatoração fácilIDE pode renomear em todo o projeto

1.4 Desvantagens do Monolito​

DesvantagemExplicação
Scaling tudo ou nadaImpossível escalar apenas um módulo
Deploy arriscadoUm bug = toda a aplicação fora do ar
Stack únicaTudo em Java (ou outro)
Tempo de build longoRecompilar tudo a cada vez
Conflitos de equipeMerges difíceis em projeto grande
Dívida técnicaDifícil de modernizar
Onboarding demoradoNovo dev precisa entender tudo

1.5 Quando o Monolito se Torna Problemático​

Ano 1: Startup
- 3 desenvolvedores
- 50K linhas de código
- Deploy: 5 minutos
→ Monolito PERFEITO ✅

Ano 3: Crescimento
- 30 desenvolvedores
- 500K linhas de código
- Deploy: 45 minutos
- Conflitos de Git diários
→ Monolito começa a travar ⚠️

Ano 5: Escala
- 100 desenvolvedores
- 2M linhas de código
- Deploy: 2 horas
- Black Friday: tudo cai
→ Monolito = "Big Ball of Mud" ❌

2. Arquitetura Microservices​

2.1 Definição​

Os microservices são uma abordagem onde a aplicação é dividida em pequenos serviços autônomos, cada um:

  • Implantável de forma independente
  • Com seu próprio banco de dados
  • Comunicando via API (HTTP/REST ou messaging)
  • Gerenciado por uma pequena equipe

2.2 Características-Chave​

1. Single Responsibility​

Cada serviço faz UMA coisa bem:
- user-service: gestão de usuários SOMENTE
- order-service: gestão de pedidos SOMENTE
- inventory-service: gestão de estoque SOMENTE

2. Autonomia​

Cada serviço:
- Tem seu próprio repo Git
- Tem seu próprio BD (Database per Service)
- Tem seu próprio pipeline CI/CD
- Pode ser implantado sozinho
- Pode usar uma tecnologia diferente

3. Comunicação​

Síncrona (HTTP/REST):
- Cliente espera a resposta
- Simples mas acoplado

Assíncrona (Messaging):
- Fire and forget
- Desacoplado mas complexo

2.3 Vantagens dos Microservices​

VantagemExplicação
Scaling direcionadoEscalar apenas o serviço que precisa
Isolamento de falhasUm serviço fora ≠ tudo fora
Deploy independenteImplantar 10x por dia por serviço
PolyglotJava, Node, Python, Go... conforme necessário
Equipes autônomas"You build it, you run it"
EvolutividadeAdicionar um serviço sem mexer nos outros
ModernizaçãoReescrever um serviço por vez

2.4 Desvantagens dos Microservices​

DesvantagemExplicação
Complexidade distribuídaDebugging difícil
Latência de redeChamadas HTTP entre serviços
Transações distribuídasACID impossível, Sagas necessárias
Consistência eventualDados não sincronizados imediatamente
Operações complexasMonitoring, logging, tracing
Custo de infraestruturaMais servidores, mais BDs
OverheadCada serviço = overhead de memória

3. Comparação Detalhada​

3.1 Tabela Comparativa​

CritérioMonolitoMicroservices
Complexidade inicialBaixaAlta
Complexidade a longo prazoAltaControlada
DeployTudo ou nadaIndependente
ScalingVerticalHorizontal
TecnologiaÚnicaPolyglot
EquipeUma equipeEquipes por serviço
Banco de dadosCompartilhadoPor serviço
TransaçõesACID simplesSagas (complexo)
DebuggingSimplesDistribuído (complexo)
LatênciaBaixaMais alta
Custo inicialBaixoAlto
Time to marketRápido no inícioMais lento no início

3.2 Critérios de Decisão​


4. Padrões Essenciais de Microservices​

4.1 API Gateway Pattern​

Responsabilidades:

  • Roteamento das requisições
  • Autenticação/Autorização
  • Rate Limiting
  • Load Balancing
  • SSL Termination
  • Caching
  • Transformação de Request/Response

4.2 Service Discovery Pattern​

Como funciona:

  1. Serviço inicia → registra no Eureka
  2. Cliente quer chamar o Service A
  3. Cliente pergunta ao Eureka: "Onde está o Service A?"
  4. Eureka retorna a lista de instâncias
  5. Cliente escolhe uma instância (load balancing client-side)
  6. Cliente chama diretamente a instância

4.3 Circuit Breaker Pattern​

Estados:

  • CLOSED: Normal, as chamadas passam
  • OPEN: Muitos erros, chamadas bloqueadas → fallback
  • HALF-OPEN: Testa se o serviço voltou
// Exemple avec Resilience4j
@CircuitBreaker(name = "userService", fallbackMethod = "getUserFallback")
public User getUser(Long id) {
return userServiceClient.getUser(id); // Appel distant
}

public User getUserFallback(Long id, Exception ex) {
return new User(id, "Unknown", "Service temporarily unavailable");
}

4.4 Saga Pattern (Transações Distribuídas)​

Em um monolito:

@Transactional
public void createOrder(Order order) {
orderRepository.save(order); // ✅
inventoryService.reserve(order); // ✅
paymentService.charge(order); // ❌ Falha → ROLLBACK tudo
}

Com microservices (Saga Choreography):

4.5 Event Sourcing & CQRS​

Eventos ao invés de estados:

// Ao invés de: UPDATE orders SET status = 'SHIPPED'
// Armazenamos eventos:
OrderCreated { orderId: 1, items: [...], timestamp: ... }
PaymentReceived { orderId: 1, amount: 100, timestamp: ... }
OrderShipped { orderId: 1, trackingNumber: "ABC123", timestamp: ... }

5. The Twelve-Factor App​

Os 12 fatores são princípios para construir aplicações cloud-native:

Os 12 Fatores​

#FatorDescriçãoAplicação Spring Boot
1CodebaseUm repo = uma appUm repo Git por serviço
2DependenciesDeclarar explicitamentepom.xml / build.gradle
3ConfigConfiguração no ambienteapplication.yml + env vars
4Backing ServicesTratar como recursos anexadosDataSource configurável
5Build, Release, RunSeparar etapasPipeline CI/CD
6ProcessesStatelessSessão no Redis
7Port BindingExportar via portaTomcat embarcado
8ConcurrencyEscalar via processosMúltiplas instâncias
9DisposabilityInicialização/parada rápidaGraceful shutdown
10Dev/Prod ParityAmbientes similaresDocker
11LogsTratar como streamstdout → coletor
12Admin ProcessesTarefas admin one-offSpring Batch

Exemplo: Fator 3 - Configuração​

# ❌ Ruim: Configuração hardcoded
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: admin
password: secret123

# ✅ Bom: Configuração externalizada
spring:
datasource:
url: ${DATABASE_URL}
username: ${DATABASE_USERNAME}
password: ${DATABASE_PASSWORD}

Exemplo: Fator 6 - Processes Stateless​

// ❌ Ruim: Estado em memória
@RestController
public class CartController {
private Map<Long, Cart> carts = new HashMap<>(); // Estado local!

@PostMapping("/cart/{userId}/add")
public void addItem(@PathVariable Long userId, @RequestBody Item item) {
carts.computeIfAbsent(userId, Cart::new).add(item);
}
}

// ✅ Bom: Estado externalizado (Redis)
@RestController
public class CartController {
private final RedisTemplate<String, Cart> redis;

@PostMapping("/cart/{userId}/add")
public void addItem(@PathVariable Long userId, @RequestBody Item item) {
String key = "cart:" + userId;
Cart cart = redis.opsForValue().get(key);
if (cart == null) cart = new Cart();
cart.add(item);
redis.opsForValue().set(key, cart);
}
}

6. Domain-Driven Design (DDD) e Microservices​

6.1 Bounded Context​

O Bounded Context define as fronteiras de um microservice:

6.2 Mesmo Conceito, Contextos Diferentes​

// No Sales Context
public class Customer {
private Long id;
private String name;
private String email;
private List<Order> orders;
private LoyaltyLevel loyaltyLevel;
}

// No Shipping Context
public class Customer {
private Long id;
private String name;
private Address shippingAddress;
private String phoneNumber;
}

// No Billing Context
public class Customer {
private Long id;
private String name;
private PaymentMethod defaultPaymentMethod;
private BillingAddress billingAddress;
}

7. Anti-Patterns a Evitar​

7.1 Distributed Monolith​

❌ ANTI-PATTERN: Monolito distribuído
- 10 serviços que DEVEM ser implantados juntos
- Esquema de BD compartilhado
- Forte acoplamento entre serviços
- O pior dos dois mundos!

7.2 Nano-Services​

❌ ANTI-PATTERN: Serviços muito pequenos
- Um serviço por entidade
- UserService, UserAddressService, UserPreferenceService
- Overhead enorme
- Transações impossíveis

7.3 Shared Database​

❌ ANTI-PATTERN: Banco de dados compartilhado
Service A ──┬──> PostgreSQL <──┬── Service B
│ │
└──> orders table <┘

Problema:
- Forte acoplamento via esquema
- Impossível alterar uma tabela
- Tentação de transações cruzadas

7.4 Sync Everywhere​

❌ ANTI-PATTERN: Tudo síncrono

Order Service
↓ HTTP sync
Inventory Service
↓ HTTP sync
Payment Service
↓ HTTP sync
Notification Service

Problema:
- Latência acumulada
- Um serviço lento = tudo lento
- Cascade failures

8. Migração Monolito → Microservices​

8.1 Estratégia: Strangler Fig Pattern​

8.2 Etapas da Migração​

  1. Identificar os Bounded Contexts no monolito
  2. Começar pelo menos arriscado (ex: notificações)
  3. Extrair para um novo serviço
  4. Roteamento via API Gateway
  5. Remover o código antigo do monolito
  6. Repetir para o próximo contexto

9. Resumo​

Pontos-Chave​

✅ Monolito = Simples mas não escala
✅ Microservices = Complexo mas flexível
✅ Comece monolito se possível
✅ Migre quando o monolito travar
✅ 12-Factor App = boas práticas cloud-native
✅ DDD = ajuda a definir as fronteiras
✅ Padrões = Circuit Breaker, Saga, Event Sourcing

Checklist Antes de Microservices​

  • Equipe experiente em DevOps?
  • Infraestrutura Kubernetes/Docker?
  • Monitoring e logging centralizados?
  • CI/CD maduro?
  • Bounded Contexts bem definidos?
  • Problemas reais de scaling?

10. Quiz de Validação​

Pergunta 1​

Qual padrão evita a cascata de falhas entre serviços?

Ver resposta

Circuit Breaker - Ele detecta falhas e "abre" o circuito para retornar um fallback imediatamente ao invés de esperar timeouts.

Pergunta 2​

Por que "Database per Service" é importante?

Ver resposta
  • Desacoplamento: Cada serviço pode evoluir seu esquema de forma independente
  • Autonomia: Sem dependência de um DBA central
  • Tecnologia: PostgreSQL para um serviço, MongoDB para outro
  • Evita acoplamento oculto via esquema compartilhado

Pergunta 3​

O que é um "Distributed Monolith"?

Ver resposta

Um anti-pattern onde existem vários serviços mas:

  • Precisam ser implantados juntos
  • Compartilham um banco de dados
  • São fortemente acoplados

Você tem a complexidade dos microservices SEM as vantagens.


Próximo Capítulo: Service Discovery com Eureka →

Voltar ao Módulo 13