microservices-architecture

安装量: 154
排名: #5608

安装

npx skills add https://github.com/aj-geddes/useful-ai-prompts --skill microservices-architecture

Microservices Architecture Overview

Comprehensive guide to designing, implementing, and maintaining microservices architectures. Covers service decomposition, communication patterns, data management, deployment strategies, and observability for distributed systems.

When to Use Designing new microservices architectures Decomposing monolithic applications Implementing service-to-service communication Setting up API gateways and service mesh Implementing service discovery Managing distributed transactions Designing inter-service data consistency Scaling independent services Instructions 1. Service Boundary Design Domain-Driven Design (DDD) Approach Bounded Contexts: ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Order Service │ │ User Service │ │ Payment Service │ │ │ │ │ │ │ │ - Create Order │ │ - User Profile │ │ - Process Pay │ │ - Order Status │ │ - Auth │ │ - Refund │ │ - Order History │ │ - Preferences │ │ - Transactions │ └─────────────────┘ └─────────────────┘ └─────────────────┘

Decomposition Strategies:

By Business Capability E-commerce System: - Product Catalog Service - Shopping Cart Service - Order Management Service - Payment Service - Inventory Service - Shipping Service - User Account Service

By Subdomain Healthcare System: - Patient Management (Core Domain) - Appointment Scheduling (Core Domain) - Billing (Supporting Domain) - Notifications (Generic Domain) - Reporting (Generic Domain)

Service Design Example // order-service/src/domain/order.ts export class OrderService { constructor( private orderRepository: OrderRepository, private eventBus: EventBus, private paymentClient: PaymentClient, private inventoryClient: InventoryClient ) {}

async createOrder(request: CreateOrderRequest): Promise { // 1. Validate order const order = Order.create(request);

// 2. Check inventory (synchronous call)
const available = await this.inventoryClient.checkAvailability(
  order.items
);
if (!available) {
  throw new InsufficientInventoryError();
}

// 3. Save order
await this.orderRepository.save(order);

// 4. Publish event (asynchronous)
await this.eventBus.publish(new OrderCreatedEvent(order));

return order;

} }

  1. Communication Patterns Synchronous Communication (REST/gRPC)

REST API Example:

// user-service/src/api/user.controller.ts import express from 'express';

const router = express.Router();

// Get user profile router.get('/users/:id', async (req, res) => { try { const user = await userService.findById(req.params.id); res.json(user); } catch (error) { if (error instanceof UserNotFoundError) { res.status(404).json({ error: 'User not found' }); } else { res.status(500).json({ error: 'Internal server error' }); } } });

// Service-to-service call with circuit breaker import axios from 'axios'; import CircuitBreaker from 'opossum';

const options = { timeout: 3000, errorThresholdPercentage: 50, resetTimeout: 30000 };

const breaker = new CircuitBreaker( async (userId: string) => { const response = await axios.get( http://user-service/users/${userId}, { timeout: 2000 } ); return response.data; }, options );

breaker.fallback(() => ({ id: userId, name: 'Unknown User' }));

gRPC Example:

// proto/user.proto syntax = "proto3";

package user;

service UserService { rpc GetUser (GetUserRequest) returns (UserResponse); rpc ListUsers (ListUsersRequest) returns (stream UserResponse); }

message GetUserRequest { string user_id = 1; }

message UserResponse { string user_id = 1; string email = 2; string name = 3; }

// Implementation import * as grpc from '@grpc/grpc-js'; import * as protoLoader from '@grpc/proto-loader';

const packageDefinition = protoLoader.loadSync('proto/user.proto'); const userProto = grpc.loadPackageDefinition(packageDefinition).user;

// Server function getUser(call, callback) { const userId = call.request.user_id; const user = await userService.findById(userId); callback(null, user); }

const server = new grpc.Server(); server.addService(userProto.UserService.service, { getUser }); server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());

Asynchronous Communication (Message Queue)

Event-Driven with RabbitMQ:

// order-service/src/events/publisher.ts import amqp from 'amqplib';

export class EventPublisher { private connection: amqp.Connection; private channel: amqp.Channel;

async connect() { this.connection = await amqp.connect('amqp://localhost'); this.channel = await this.connection.createChannel(); await this.channel.assertExchange('orders', 'topic', { durable: true }); }

async publishOrderCreated(order: Order) { const event = { eventType: 'OrderCreated', timestamp: new Date(), data: order };

this.channel.publish(
  'orders',
  'order.created',
  Buffer.from(JSON.stringify(event)),
  { persistent: true }
);

} }

// inventory-service/src/events/consumer.ts export class OrderEventConsumer { async subscribe() { const connection = await amqp.connect('amqp://localhost'); const channel = await connection.createChannel();

await channel.assertExchange('orders', 'topic', { durable: true });
const q = await channel.assertQueue('inventory-order-events', {
  durable: true
});

await channel.bindQueue(q.queue, 'orders', 'order.created');

channel.consume(q.queue, async (msg) => {
  if (msg) {
    const event = JSON.parse(msg.content.toString());
    await this.handleOrderCreated(event.data);
    channel.ack(msg);
  }
});

}

private async handleOrderCreated(order: Order) { // Reserve inventory await inventoryService.reserveItems(order.items); } }

Kafka Event Streaming:

// event-streaming/kafka-producer.ts import { Kafka } from 'kafkajs';

const kafka = new Kafka({ clientId: 'order-service', brokers: ['kafka:9092'] });

const producer = kafka.producer();

export async function publishEvent(topic: string, event: any) { await producer.connect(); await producer.send({ topic, messages: [ { key: event.aggregateId, value: JSON.stringify(event), headers: { 'event-type': event.type, 'correlation-id': event.correlationId } } ] }); }

// Consumer const consumer = kafka.consumer({ groupId: 'inventory-service' });

await consumer.subscribe({ topic: 'order-events', fromBeginning: false });

await consumer.run({ eachMessage: async ({ topic, partition, message }) => { const event = JSON.parse(message.value.toString()); await eventHandler.handle(event); } });

  1. API Gateway Pattern // api-gateway/src/gateway.ts import express from 'express'; import httpProxy from 'http-proxy-middleware'; import jwt from 'jsonwebtoken'; import rateLimit from 'express-rate-limit';

const app = express();

// Rate limiting const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100 });

app.use(limiter);

// Authentication middleware const authenticateToken = (req, res, next) => { const token = req.headers['authorization']?.split(' ')[1]; if (!token) return res.sendStatus(401);

jwt.verify(token, process.env.JWT_SECRET, (err, user) => { if (err) return res.sendStatus(403); req.user = user; next(); }); };

// Route to services app.use('/api/users', authenticateToken, httpProxy.createProxyMiddleware({ target: 'http://user-service:3000', changeOrigin: true, pathRewrite: { '^/api/users': '/users' } }));

app.use('/api/orders', authenticateToken, httpProxy.createProxyMiddleware({ target: 'http://order-service:3000', changeOrigin: true, pathRewrite: { '^/api/orders': '/orders' } }));

app.use('/api/products', httpProxy.createProxyMiddleware({ target: 'http://product-service:3000', changeOrigin: true, pathRewrite: { '^/api/products': '/products' } }));

// Aggregation endpoint app.get('/api/order-details/:orderId', authenticateToken, async (req, res) => { const orderId = req.params.orderId;

// Parallel requests to multiple services const [order, user, products] = await Promise.all([ fetch(http://order-service:3000/orders/${orderId}).then(r => r.json()), fetch(http://user-service:3000/users/${req.user.id}).then(r => r.json()), fetch(http://product-service:3000/products?ids=${order.itemIds}).then(r => r.json()) ]);

res.json({ order, user, products }); });

  1. Service Discovery Consul Example // service-registry/consul-client.ts import Consul from 'consul';

export class ServiceRegistry { private consul: Consul.Consul;

constructor() { this.consul = new Consul({ host: 'consul', port: 8500 }); }

// Register service async register(serviceName: string, servicePort: number) { await this.consul.agent.service.register({ id: ${serviceName}-${process.env.HOSTNAME}, name: serviceName, address: process.env.SERVICE_IP, port: servicePort, check: { http: http://${process.env.SERVICE_IP}:${servicePort}/health, interval: '10s', timeout: '5s' } }); }

// Discover service async discover(serviceName: string): Promise { const result = await this.consul.health.service({ service: serviceName, passing: true });

if (result.length === 0) {
  throw new Error(`Service ${serviceName} not found`);
}

// Simple round-robin
const service = result[Math.floor(Math.random() * result.length)];
return `http://${service.Service.Address}:${service.Service.Port}`;

}

// Deregister on shutdown async deregister(serviceId: string) { await this.consul.agent.service.deregister(serviceId); } }

Kubernetes Service Discovery

user-service-deployment.yaml

apiVersion: v1 kind: Service metadata: name: user-service spec: selector: app: user-service ports: - protocol: TCP port: 80 targetPort: 3000 type: ClusterIP


apiVersion: apps/v1 kind: Deployment metadata: name: user-service spec: replicas: 3 selector: matchLabels: app: user-service template: metadata: labels: app: user-service spec: containers: - name: user-service image: user-service:latest ports: - containerPort: 3000 env: - name: SERVICE_NAME value: "user-service"

// Service call in Kubernetes const userServiceUrl = process.env.USER_SERVICE_URL || 'http://user-service'; const response = await fetch(${userServiceUrl}/users/${userId});

  1. Data Consistency Patterns Saga Pattern (Orchestration) // order-saga-orchestrator.ts export class OrderSagaOrchestrator { async createOrder(orderData: CreateOrderRequest) { const sagaId = uuidv4(); const saga = new SagaInstance(sagaId);

    try { // Step 1: Create order const order = await this.orderService.createOrder(orderData); saga.addCompensation(() => this.orderService.cancelOrder(order.id));

    // Step 2: Reserve inventory await this.inventoryService.reserveItems(order.items); saga.addCompensation(() => this.inventoryService.releaseReservation(order.id) );

    // Step 3: Process payment const payment = await this.paymentService.charge(order.total); saga.addCompensation(() => this.paymentService.refund(payment.id) );

    // Step 4: Confirm order await this.orderService.confirmOrder(order.id);

    return order; } catch (error) { // Compensate in reverse order await saga.compensate(); throw error; } } }

Event Sourcing Pattern // order-aggregate.ts export class OrderAggregate { private id: string; private status: OrderStatus; private items: OrderItem[]; private events: DomainEvent[] = [];

// Command handler createOrder(command: CreateOrderCommand) { // Validation if (this.id) throw new Error('Order already exists');

// Apply event
this.apply(new OrderCreatedEvent({
  orderId: command.orderId,
  userId: command.userId,
  items: command.items
}));

}

// Event handler private apply(event: DomainEvent) { switch (event.type) { case 'OrderCreated': this.id = event.orderId; this.items = event.items; this.status = OrderStatus.PENDING; break; case 'OrderConfirmed': this.status = OrderStatus.CONFIRMED; break; } this.events.push(event); }

getUncommittedEvents(): DomainEvent[] { return this.events; } }

  1. Service Mesh (Istio)

istio-config.yaml

apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: order-service spec: hosts: - order-service http: - match: - headers: user-type: exact: premium route: - destination: host: order-service subset: v2 weight: 100 - route: - destination: host: order-service subset: v1 weight: 90 - destination: host: order-service subset: v2 weight: 10


apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: order-service spec: host: order-service trafficPolicy: connectionPool: tcp: maxConnections: 100 http: http1MaxPendingRequests: 50 maxRequestsPerConnection: 2 outlierDetection: consecutiveErrors: 5 interval: 30s baseEjectionTime: 30s subsets: - name: v1 labels: version: v1 - name: v2 labels: version: v2

Best Practices ✅ DO Design services around business capabilities Use asynchronous communication where possible Implement circuit breakers for resilience Use API gateway for cross-cutting concerns Implement distributed tracing Use service mesh for service-to-service communication Design for failure (chaos engineering) Implement health checks for all services Use correlation IDs for request tracking Version your APIs Implement proper monitoring and alerting Use event-driven architecture for loose coupling Implement idempotent operations Use database per service pattern ❌ DON'T Share databases between services Create overly granular services (nanoservices) Use distributed transactions (two-phase commit) Ignore network latency and failures Share domain models between services Deploy all services as one unit Hardcode service URLs Forget to implement authentication/authorization Use synchronous calls for long-running operations Ignore backward compatibility Skip monitoring and logging Create circular dependencies between services Common Patterns Pattern 1: Backend for Frontend (BFF) // mobile-bff/src/api.ts - Optimized for mobile app.get('/api/home', async (req, res) => { const [featured, recommendations] = await Promise.all([ productService.getFeatured(5), recommendationService.getForUser(req.user.id, 10) ]); res.json({ featured, recommendations }); });

// web-bff/src/api.ts - More data for web app.get('/api/home', async (req, res) => { const [featured, recommendations, categories, promotions] = await Promise.all([ productService.getFeatured(20), recommendationService.getForUser(req.user.id, 50), categoryService.getAll(), promotionService.getActive() ]); res.json({ featured, recommendations, categories, promotions }); });

Pattern 2: Sidecar Pattern

Pod with sidecar

apiVersion: v1 kind: Pod metadata: name: app-with-sidecar spec: containers: - name: app image: my-app:latest - name: logging-sidecar image: fluentd:latest volumeMounts: - name: logs mountPath: /logs volumes: - name: logs emptyDir: {}

Tools & Resources Service Mesh: Istio, Linkerd, Consul Connect API Gateway: Kong, Apigee, AWS API Gateway Service Discovery: Consul, Eureka, Zookeeper Message Queue: RabbitMQ, Apache Kafka, AWS SQS Orchestration: Kubernetes, Docker Swarm, Nomad Monitoring: Prometheus, Grafana, Datadog Tracing: Jaeger, Zipkin, AWS X-Ray Circuit Breaker: Hystrix, Resilience4j, Polly

返回排行榜