Microsserviços em Go: arquitetura e prática de nível avançado
A transição do monolito para a arquitetura de microsserviços é uma etapa inevitável na evolução de muitos sistemas de alta carga. A linguagem Go (Golang) tornou-se uma das líderes nesta área devido ao seu desempenho, suporte nativo a concorrência e runtime minimalista. Neste artigo, exploraremos padrões arquiteturais avançados e técnicas práticas para construir microsserviços em Go, que ajudarão você a criar sistemas robustos, escaláveis e tolerantes a falhas.
1. Padrões arquiteturais: CQRS e Event Sourcing em Go
Para modelos de domínio complexos, o CRUD clássico muitas vezes não é suficiente. Os padrões CQRS (Command Query Responsibility Segregation) e Event Sourcing permitem separar operações de escrita e leitura, além de armazenar o histórico de mudanças de estado.
Implementação de CQRS em Go
Dividimos o modelo em comandos (alteração de estado) e consultas (leitura). Como exemplo, vamos usar um serviço de gerenciamento de pedidos.
// commands.gopackage orders
type CreateOrderCommand struct { UserID string Items []OrderItem}
type OrderCommandHandler struct { repo OrderRepository bus EventBus}
func (h *OrderCommandHandler) Handle(ctx context.Context, cmd CreateOrderCommand) error { order := NewOrder(cmd.UserID, cmd.Items) if err := h.repo.Save(ctx, order); err != nil { return err } h.bus.Publish(ctx, OrderCreatedEvent{ OrderID: order.ID, UserID: order.UserID, }) return nil}
// queries.gotype OrderQueryHandler struct { readRepo OrderReadRepository}
func (h *OrderQueryHandler) GetOrderByID(ctx context.Context, orderID string) (*OrderView, error) { return h.readRepo.FindByID(ctx, orderID)}Para Event Sourcing, use a biblioteca github.com/looplab/eventhorizon ou implemente sua própria solução baseada em canais do Go.
2. Padrão Saga: transações distribuídas
No mundo dos microsserviços, transações ACID entre vários serviços são impossíveis. O padrão Saga resolve esse problema através de uma sequência de transações locais com ações compensatórias.
Coreografia vs Orquestração
Existem duas abordagens: coreografia (serviços se comunicam através de eventos) e orquestração (coordenador central). Para projetos Go, a coreografia é frequentemente escolhida devido à sua descentralização.
// saga.gopackage saga
type SagaStep struct { Name string Action func(ctx context.Context) error Compensate func(ctx context.Context) error}
type Saga struct { steps []SagaStep}
func (s *Saga) Execute(ctx context.Context) error { executed := []SagaStep{} for _, step := range s.steps { if err := step.Action(ctx); err != nil { // Compensação de todos os passos executados for i := len(executed) - 1; i >= 0; i-- { executed[i].Compensate(ctx) } return err } executed = append(executed, step) } return nil}
// Exemplo de uso:func CreateOrderSaga(ctx context.Context) error { saga := Saga{ steps: []SagaStep{ {Name: "ReserveInventory", Action: reserveInventory, Compensate: releaseInventory}, {Name: "ChargePayment", Action: chargePayment, Compensate: refundPayment}, {Name: "SendEmail", Action: sendEmail, Compensate: noop}, }, } return saga.Execute(ctx)}Para brokers de mensagens, use RabbitMQ ou NATS — eles se integram perfeitamente com Go através dos pacotes github.com/streadway/amqp e github.com/nats-io/nats.go.
3. gRPC e comunicação entre serviços
A API REST frequentemente se torna um gargalo em microsserviços devido ao formato textual e à n