Microservices Architecture

লেসন ৪৯ / ৫০

Microservices কী?

Monolith vs Microservices — একটি বড় app-কে অনেক ছোট, independent service-এ ভাগ করা। প্রতিটি service আলাদা DB, deploy, team।

Service Decomposition

E-commerce মোনোলিথ →

Catalog Service     (Products, Categories)
Order Service       (Orders, Cart)
Payment Service     (Stripe integration)
Shipping Service    (Courier API)
Notification Service(Email, SMS)
Identity Service    (Auth, JWT)

Communication Patterns

  • Synchronous — HTTP/REST, gRPC (immediate response)
  • Asynchronous — Message broker (RabbitMQ, Kafka, Azure Service Bus)

HttpClient Factory (Sync)

// Program.cs
builder.Services.AddHttpClient<ICatalogClient, CatalogClient>(c => {
    c.BaseAddress = new Uri("http://catalog-service");
}).AddPolicyHandler(GetRetryPolicy());

// Polly retry
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() =>
    HttpPolicyExtensions.HandleTransientHttpError()
        .WaitAndRetryAsync(3, attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)));

// Client
public class CatalogClient : ICatalogClient {
    private readonly HttpClient _http;
    public CatalogClient(HttpClient http) => _http = http;
    public async Task<ProductDto?> GetAsync(int id) =>
        await _http.GetFromJsonAsync<ProductDto>($"/api/products/{id}");
}

RabbitMQ + MassTransit (Async) ⭐

dotnet add package MassTransit.RabbitMQ

// Program.cs
builder.Services.AddMassTransit(x => {
    x.AddConsumer<OrderCreatedConsumer>();
    x.UsingRabbitMq((ctx, cfg) => {
        cfg.Host("rabbitmq://localhost", h => {
            h.Username("guest"); h.Password("guest");
        });
        cfg.ReceiveEndpoint("order-created", e => e.ConfigureConsumer<OrderCreatedConsumer>(ctx));
    });
});

// Event
public record OrderCreated(int OrderId, decimal Total, string Email);

// Publish (Order Service)
public class OrderService {
    private readonly IPublishEndpoint _publish;
    public async Task PlaceOrder(...) {
        // Save order
        await _publish.Publish(new OrderCreated(order.Id, order.Total, user.Email));
    }
}

// Consume (Notification Service)
public class OrderCreatedConsumer : IConsumer<OrderCreated> {
    public async Task Consume(ConsumeContext<OrderCreated> ctx) {
        await SendEmail(ctx.Message.Email, $"Order {ctx.Message.OrderId} placed");
    }
}

API Gateway (YARP / Ocelot)

# YARP appsettings.json
{
  "ReverseProxy": {
    "Routes": {
      "catalog": { "ClusterId": "catalog", "Match": { "Path": "/api/products/{**catch-all}" } },
      "orders":  { "ClusterId": "orders",  "Match": { "Path": "/api/orders/{**catch-all}" } }
    },
    "Clusters": {
      "catalog": { "Destinations": { "d1": { "Address": "http://catalog-service" } } },
      "orders":  { "Destinations": { "d1": { "Address": "http://order-service" } } }
    }
  }
}

// Program.cs
builder.Services.AddReverseProxy().LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
app.MapReverseProxy();

Service Discovery

  • Consul — service registry + health
  • Kubernetes — built-in DNS-based discovery
  • Eureka — Netflix OSS

Distributed Tracing

// OpenTelemetry
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Exporter.Jaeger

builder.Services.AddOpenTelemetry()
    .WithTracing(t => t
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddJaegerExporter());

Patterns

  • Saga — distributed transaction coordination
  • Outbox — DB + message atomic publish
  • Circuit Breaker — Polly
  • Bulkhead — resource isolation
  • CQRS + Event Sourcing

Drawbacks

Network latency, distributed transaction complexity, monitoring overhead, data consistency challenges। Small team-এ monolith first।