- 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
722 lines
19 KiB
Markdown
722 lines
19 KiB
Markdown
# Cloud-Native архитектура
|
|
|
|
## Навигация
|
|
- [🏠 Главная страница курса](../../../README.md)
|
|
- [📚 Модуль 8](../README.md)
|
|
|
|
---
|
|
|
|
## Принципы Cloud-Native
|
|
|
|
### 1. Microservices
|
|
- Разбиение монолитных приложений на независимые сервисы
|
|
- Каждый сервис отвечает за одну бизнес-функцию
|
|
- Независимое развертывание и масштабирование
|
|
|
|
```yaml
|
|
# 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
|
|
# 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
|
|
- Управление контейнерами в кластере
|
|
- Автоматическое масштабирование
|
|
- Отказоустойчивость
|
|
|
|
```yaml
|
|
# 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
|
|
|
|
```yaml
|
|
# 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
|
|
|
|
```javascript
|
|
// 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 механизмы
|
|
|
|
```javascript
|
|
// 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
|
|
|
|
```javascript
|
|
// 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
|
|
- Изоляция ресурсов
|
|
- Предотвращение каскадных сбоев
|
|
- Независимое масштабирование
|
|
|
|
```javascript
|
|
// 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 модель
|
|
|
|
```javascript
|
|
// 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 функции
|
|
- Интеграция с различными источниками событий
|
|
- Асинхронная обработка
|
|
|
|
```yaml
|
|
# 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 для безопасности
|
|
- Регулярно обновляйте зависимости
|