Files
sa-lessons/modules/module8/sections/05-cloud-native-architecture.md
Alexander Abakumov 15e744da49 Initial commit: Complete Software Architecture course with 11 modules
- Added comprehensive course structure with 11 modules
- Included theoretical content, practical examples, and tasks
- Multi-language code examples (Java, Rust, Node.js, Python)
- Detailed analysis of architectural approaches and trade-offs
- Complete caching strategies documentation
- Architecture examples from real-world systems (Twitter, Netflix, Uber)
- Structured navigation and learning path
- Ready for educational use
2025-09-09 22:08:07 +03:00

19 KiB

Cloud-Native архитектура

Навигация


Принципы Cloud-Native

1. Microservices

  • Разбиение монолитных приложений на независимые сервисы
  • Каждый сервис отвечает за одну бизнес-функцию
  • Независимое развертывание и масштабирование
# Kubernetes Deployment для микросервиса
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
  labels:
    app: user-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
      - name: user-service
        image: user-service:v1.0.0
        ports:
        - containerPort: 8080
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: user-service-secrets
              key: database-url
        - name: REDIS_URL
          valueFrom:
            configMapKeyRef:
              name: user-service-config
              key: redis-url
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5

2. Containerization

  • Упаковка приложений в контейнеры
  • Изоляция зависимостей
  • Портабельность между средами
# Dockerfile для Node.js приложения
FROM node:18-alpine

# Установка рабочей директории
WORKDIR /app

# Копирование package.json и package-lock.json
COPY package*.json ./

# Установка зависимостей
RUN npm ci --only=production

# Копирование исходного кода
COPY . .

# Создание пользователя для безопасности
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

# Изменение владельца файлов
RUN chown -R nextjs:nodejs /app
USER nextjs

# Открытие порта
EXPOSE 3000

# Команда запуска
CMD ["npm", "start"]

3. Orchestration

  • Управление контейнерами в кластере
  • Автоматическое масштабирование
  • Отказоустойчивость
# Kubernetes Service
apiVersion: v1
kind: Service
metadata:
  name: user-service
  labels:
    app: user-service
spec:
  selector:
    app: user-service
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: ClusterIP

---
# Kubernetes Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: user-service-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  tls:
  - hosts:
    - api.example.com
    secretName: user-service-tls
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /users
        pathType: Prefix
        backend:
          service:
            name: user-service
            port:
              number: 80

4. API-First Design

  • Приоритет API в архитектуре
  • Версионирование API
  • Документирование через OpenAPI
# OpenAPI Specification
openapi: 3.0.0
info:
  title: User Service API
  version: 1.0.0
  description: API for managing users
servers:
  - url: https://api.example.com/v1
    description: Production server
paths:
  /users:
    get:
      summary: Get all users
      operationId: getUsers
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 10
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: List of users
          content:
            application/json:
              schema:
                type: object
                properties:
                  users:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                  total:
                    type: integer
    post:
      summary: Create a new user
      operationId: createUser
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserRequest'
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
          format: email
        name:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    CreateUserRequest:
      type: object
      required:
        - email
        - name
      properties:
        email:
          type: string
          format: email
        name:
          type: string
        password:
          type: string
          minLength: 8
    Error:
      type: object
      properties:
        code:
          type: string
        message:
          type: string
        details:
          type: string

5. Event-Driven Architecture

  • Асинхронная обработка событий
  • Loose coupling между сервисами
  • Event sourcing и CQRS
// Event-driven микросервис на Node.js
const express = require('express');
const { PubSub } = require('@google-cloud/pubsub');
const { v4: uuidv4 } = require('uuid');

const app = express();
const pubsub = new PubSub();
const topic = pubsub.topic('order-events');

app.use(express.json());

// Обработка создания заказа
app.post('/orders', async (req, res) => {
    try {
        const order = {
            id: uuidv4(),
            customerId: req.body.customerId,
            items: req.body.items,
            total: req.body.total,
            status: 'created',
            createdAt: new Date().toISOString()
        };

        // Сохранение заказа в базе данных
        await saveOrder(order);

        // Публикация события
        await topic.publishMessage({
            data: Buffer.from(JSON.stringify({
                type: 'OrderCreated',
                orderId: order.id,
                customerId: order.customerId,
                total: order.total,
                timestamp: order.createdAt
            }))
        });

        res.status(201).json(order);
    } catch (error) {
        console.error('Error creating order:', error);
        res.status(500).json({ error: 'Internal server error' });
    }
});

// Обработка событий
app.post('/events/order-created', async (req, res) => {
    try {
        const event = req.body;
        
        if (event.type === 'OrderCreated') {
            // Отправка email уведомления
            await sendOrderConfirmationEmail(event.customerId, event.orderId);
            
            // Обновление инвентаря
            await updateInventory(event.items);
            
            // Обновление статуса заказа
            await updateOrderStatus(event.orderId, 'confirmed');
        }

        res.status(200).json({ status: 'processed' });
    } catch (error) {
        console.error('Error processing event:', error);
        res.status(500).json({ error: 'Internal server error' });
    }
});

async function saveOrder(order) {
    // Логика сохранения заказа
}

async function sendOrderConfirmationEmail(customerId, orderId) {
    // Логика отправки email
}

async function updateInventory(items) {
    // Логика обновления инвентаря
}

async function updateOrderStatus(orderId, status) {
    // Логика обновления статуса заказа
}

app.listen(3000, () => {
    console.log('Order service listening on port 3000');
});

Cloud-Native Patterns

1. Circuit Breaker

  • Защита от каскадных сбоев
  • Автоматическое восстановление
  • Fallback механизмы
// Circuit Breaker implementation
class CircuitBreaker {
    constructor(service, options = {}) {
        this.service = service;
        this.failureThreshold = options.failureThreshold || 5;
        this.timeout = options.timeout || 60000;
        this.resetTimeout = options.resetTimeout || 30000;
        this.state = 'CLOSED';
        this.failureCount = 0;
        this.lastFailureTime = null;
    }

    async call(...args) {
        if (this.state === 'OPEN') {
            if (Date.now() - this.lastFailureTime > this.resetTimeout) {
                this.state = 'HALF_OPEN';
            } else {
                throw new Error('Circuit breaker is OPEN');
            }
        }

        try {
            const result = await this.service(...args);
            this.onSuccess();
            return result;
        } catch (error) {
            this.onFailure();
            throw error;
        }
    }

    onSuccess() {
        this.failureCount = 0;
        this.state = 'CLOSED';
    }

    onFailure() {
        this.failureCount++;
        this.lastFailureTime = Date.now();
        
        if (this.failureCount >= this.failureThreshold) {
            this.state = 'OPEN';
        }
    }
}

// Использование Circuit Breaker
const userService = async (userId) => {
    // Вызов внешнего сервиса
    const response = await fetch(`https://user-service/api/users/${userId}`);
    if (!response.ok) {
        throw new Error('User service error');
    }
    return response.json();
};

const circuitBreaker = new CircuitBreaker(userService, {
    failureThreshold: 3,
    resetTimeout: 30000
});

// Использование в API endpoint
app.get('/users/:id', async (req, res) => {
    try {
        const user = await circuitBreaker.call(req.params.id);
        res.json(user);
    } catch (error) {
        res.status(500).json({ error: 'Service unavailable' });
    }
});

2. Retry Pattern

  • Повторные попытки при временных сбоях
  • Exponential backoff
  • Jitter для избежания thundering herd
// Retry pattern implementation
class RetryPolicy {
    constructor(options = {}) {
        this.maxAttempts = options.maxAttempts || 3;
        this.baseDelay = options.baseDelay || 1000;
        this.maxDelay = options.maxDelay || 10000;
        this.backoffMultiplier = options.backoffMultiplier || 2;
        this.jitter = options.jitter || true;
    }

    async execute(operation) {
        let lastError;
        
        for (let attempt = 1; attempt <= this.maxAttempts; attempt++) {
            try {
                return await operation();
            } catch (error) {
                lastError = error;
                
                if (attempt === this.maxAttempts) {
                    throw error;
                }
                
                const delay = this.calculateDelay(attempt);
                await this.sleep(delay);
            }
        }
        
        throw lastError;
    }

    calculateDelay(attempt) {
        let delay = this.baseDelay * Math.pow(this.backoffMultiplier, attempt - 1);
        delay = Math.min(delay, this.maxDelay);
        
        if (this.jitter) {
            delay = delay * (0.5 + Math.random() * 0.5);
        }
        
        return delay;
    }

    sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}

// Использование Retry Policy
const retryPolicy = new RetryPolicy({
    maxAttempts: 3,
    baseDelay: 1000,
    maxDelay: 5000,
    backoffMultiplier: 2,
    jitter: true
});

app.get('/external-data', async (req, res) => {
    try {
        const data = await retryPolicy.execute(async () => {
            const response = await fetch('https://external-api.com/data');
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}`);
            }
            return response.json();
        });
        
        res.json(data);
    } catch (error) {
        res.status(500).json({ error: 'Failed to fetch external data' });
    }
});

3. Bulkhead Pattern

  • Изоляция ресурсов
  • Предотвращение каскадных сбоев
  • Независимое масштабирование
// Bulkhead pattern implementation
class BulkheadPool {
    constructor(options = {}) {
        this.maxConcurrency = options.maxConcurrency || 10;
        this.queue = [];
        this.active = 0;
    }

    async execute(operation) {
        return new Promise((resolve, reject) => {
            this.queue.push({ operation, resolve, reject });
            this.process();
        });
    }

    async process() {
        if (this.active >= this.maxConcurrency || this.queue.length === 0) {
            return;
        }

        this.active++;
        const { operation, resolve, reject } = this.queue.shift();

        try {
            const result = await operation();
            resolve(result);
        } catch (error) {
            reject(error);
        } finally {
            this.active--;
            this.process();
        }
    }
}

// Создание отдельных пулов для разных операций
const databasePool = new BulkheadPool({ maxConcurrency: 5 });
const externalApiPool = new BulkheadPool({ maxConcurrency: 3 });
const fileProcessingPool = new BulkheadPool({ maxConcurrency: 2 });

// Использование в API endpoints
app.post('/orders', async (req, res) => {
    try {
        // Использование database pool
        const order = await databasePool.execute(async () => {
            return await saveOrder(req.body);
        });

        // Использование external API pool
        const paymentResult = await externalApiPool.execute(async () => {
            return await processPayment(order.id, order.total);
        });

        res.json({ order, payment: paymentResult });
    } catch (error) {
        res.status(500).json({ error: 'Order processing failed' });
    }
});

Serverless Architecture

1. Function as a Service (FaaS)

  • Выполнение кода без управления серверами
  • Автоматическое масштабирование
  • Pay-per-execution модель
// AWS Lambda function
exports.handler = async (event, context) => {
    const { Records } = event;
    
    for (const record of Records) {
        if (record.eventSource === 'aws:s3') {
            await processS3Event(record);
        } else if (record.eventSource === 'aws:sqs') {
            await processSQSMessage(record);
        }
    }
    
    return { statusCode: 200, body: 'Processed successfully' };
};

async function processS3Event(record) {
    const bucket = record.s3.bucket.name;
    const key = record.s3.object.key;
    
    // Обработка файла из S3
    console.log(`Processing file: ${bucket}/${key}`);
    
    // Логика обработки файла
    // ...
}

async function processSQSMessage(record) {
    const body = JSON.parse(record.body);
    
    // Обработка сообщения из SQS
    console.log('Processing message:', body);
    
    // Логика обработки сообщения
    // ...
}

2. Event-Driven Serverless

  • Обработка событий через serverless функции
  • Интеграция с различными источниками событий
  • Асинхронная обработка
# Serverless Framework configuration
service: my-serverless-app

provider:
  name: aws
  runtime: nodejs18.x
  region: us-east-1
  environment:
    DATABASE_URL: ${env:DATABASE_URL}
    REDIS_URL: ${env:REDIS_URL}

functions:
  processOrder:
    handler: handlers/order.handler
    events:
      - http:
          path: /orders
          method: post
          cors: true
      - sqs:
          arn: !GetAtt OrderQueue.Arn
          batchSize: 10
    environment:
      QUEUE_URL: !Ref OrderQueue

  processPayment:
    handler: handlers/payment.handler
    events:
      - sns:
          topic: order-created
          filterPolicy:
            status: [created]
    environment:
      PAYMENT_API_URL: ${env:PAYMENT_API_URL}

  sendNotification:
    handler: handlers/notification.handler
    events:
      - sns:
          topic: order-processed
    environment:
      EMAIL_SERVICE_URL: ${env:EMAIL_SERVICE_URL}

resources:
  Resources:
    OrderQueue:
      Type: AWS::SQS::Queue
      Properties:
        QueueName: order-queue
        VisibilityTimeoutSeconds: 300
        MessageRetentionPeriod: 1209600

    OrderTopic:
      Type: AWS::SNS::Topic
      Properties:
        TopicName: order-created

Best Practices

1. Design for Failure

  • Предполагайте, что компоненты могут выйти из строя
  • Реализуйте graceful degradation
  • Используйте health checks и monitoring

2. Stateless Services

  • Не храните состояние в сервисах
  • Используйте внешние хранилища для состояния
  • Обеспечивайте горизонтальное масштабирование

3. Configuration Management

  • Выносите конфигурацию в переменные окружения
  • Используйте секреты для чувствительных данных
  • Применяйте принцип least privilege

4. Monitoring and Observability

  • Настройте comprehensive monitoring
  • Используйте structured logging
  • Реализуйте distributed tracing

5. Security

  • Применяйте defense in depth
  • Используйте service mesh для безопасности
  • Регулярно обновляйте зависимости