Microservices en Go : architecture et pratique de niveau avancé
Le passage du monolithe à l'architecture microservices est une étape inévitable dans l'évolution de nombreux systèmes à forte charge. Le langage Go (Golang) est devenu l'un des leaders dans ce domaine grâce à ses performances, son support intégré de la concurrence et son runtime minimaliste. Dans cet article, nous examinerons les patterns architecturaux avancés et les techniques pratiques de construction de microservices en Go qui vous aideront à créer des systèmes fiables, évolutifs et tolérants aux pannes.
1. Patterns architecturaux : CQRS et Event Sourcing en Go
Pour les modèles de domaine complexes, le CRUD classique s'avère souvent insuffisant. Les patterns CQRS (Command Query Responsibility Segregation) et Event Sourcing permettent de séparer les opérations d'écriture et de lecture, ainsi que de stocker l'historique des changements d'état.
Implémentation de CQRS en Go
Nous séparons le modèle en commandes (modification d'état) et requêtes (lecture). Prenons l'exemple d'un service de gestion de commandes.
// 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)}Pour Event Sourcing, utilisez la bibliothèque github.com/looplab/eventhorizon ou écrivez votre propre implémentation basée sur les canaux Go.
2. Pattern Saga : transactions distribuées
Dans le monde des microservices, les transactions ACID à travers plusieurs services sont impossibles. Le pattern Saga résout ce problème via une séquence de transactions locales avec des actions compensatoires.
Chorégraphie vs Orchestration
On distingue deux approches : la chorégraphie (les services communiquent via des événements) et l'orchestration (un coordinateur central). Pour les projets Go, la chorégraphie est souvent choisie en raison de sa décentralisation.
// 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 { // Compensation de toutes les étapes exécutées for i := len(executed) - 1; i >= 0; i-- { executed[i].Compensate(ctx) } return err } executed = append(executed, step) } return nil}
// Exemple d'utilisation :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)}Pour les courtiers de messages, utilisez RabbitMQ ou NATS — ils s'intègrent parfaitement avec Go via les paquets github.com/streadway/amqp et github.com/nats-io/nats.go.
3. gRPC et interaction inter-services
L'API REST devient souvent un goulot d'étranglement dans les microservices en raison du format texte et de n