Microservicios en Go: arquitectura y práctica de nivel avanzado
La transición del monolito a la arquitectura de microservicios es una etapa inevitable en la evolución de muchos sistemas de alta carga. El lenguaje Go (Golang) se ha convertido en uno de los líderes en este ámbito gracias a su rendimiento, soporte integrado de concurrencia y tiempo de ejecución minimalista. En este artículo, exploraremos patrones arquitectónicos avanzados y técnicas prácticas para construir microservicios en Go que le ayudarán a crear sistemas robustos, escalables y tolerantes a fallos.
1. Patrones arquitectónicos: CQRS y Event Sourcing en Go
Para modelos de dominio complejos, el CRUD clásico a menudo resulta insuficiente. Los patrones CQRS (Command Query Responsibility Segregation) y Event Sourcing permiten separar las operaciones de escritura y lectura, así como almacenar el historial de cambios de estado.
Implementación de CQRS en Go
Dividimos el modelo en comandos (cambio de estado) y consultas (lectura). Tomemos como ejemplo un servicio de gestión 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, utilice la biblioteca github.com/looplab/eventhorizon o escriba su propia implementación basada en canales de Go.
2. Patrón Saga: transacciones distribuidas
En el mundo de los microservicios, las transacciones ACID a través de múltiples servicios no son posibles. El patrón Saga resuelve este problema mediante una secuencia de transacciones locales con acciones compensatorias.
Coreografía vs Orquestación
Existen dos enfoques: coreografía (los servicios se comunican a través de eventos) y orquestación (un coordinador central). Para proyectos Go, a menudo se elige la coreografía debido a su naturaleza descentralizada.
// 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 { // Compensación de todos los pasos ejecutados for i := len(executed) - 1; i >= 0; i-- { executed[i].Compensate(ctx) } return err } executed = append(executed, step) } return nil}
// Ejemplo 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 los brokers de mensajes, utilice RabbitMQ o NATS; se integran perfectamente con Go a través de los paquetes github.com/streadway/amqp y github.com/nats-io/nats.go.
3. gRPC e interacción entre servicios
La API REST a menudo se convierte en un cuello de botella en los microservicios debido al formato de texto y a la n