Files
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

440 lines
13 KiB
Markdown

# Основы масштабируемости
## Навигация
- [🏠 Главная страница курса](../../../README.md)
- [📚 Модуль 4](../README.md)
---
## Что такое масштабируемость
**Масштабируемость** — способность системы обрабатывать увеличение нагрузки путем добавления ресурсов.
## Типы масштабирования
### 1. Вертикальное масштабирование (Scale Up)
**Определение:** Увеличение мощности существующих серверов.
**Преимущества:**
- Простота реализации
- Нет изменений в архитектуре
- Быстрое внедрение
**Недостатки:**
- Ограниченность ресурсов
- Высокая стоимость
- Точка отказа
**Пример:**
```
Сервер: 4 CPU, 8GB RAM → 8 CPU, 16GB RAM
```
### 2. Горизонтальное масштабирование (Scale Out)
**Определение:** Добавление новых серверов в систему.
**Преимущества:**
- Теоретически неограниченное масштабирование
- Отказоустойчивость
- Экономическая эффективность
**Недостатки:**
- Сложность архитектуры
- Проблемы с данными
- Сетевые задержки
**Пример:**
```
1 сервер → 2 сервера → 4 сервера → 8 серверов
```
## Метрики масштабируемости
### 1. Throughput (Пропускная способность)
- Запросов в секунду (RPS)
- Транзакций в секунду (TPS)
- Байт в секунду
### 2. Latency (Задержка)
- Время отклика
- Время обработки
- Время ожидания
### 3. Resource Utilization (Использование ресурсов)
- CPU utilization
- Memory usage
- Disk I/O
- Network bandwidth
## Закон Амдала
**Формула:** `Speedup = 1 / (P + (1-P)/N)`
Где:
- P — доля последовательного кода
- N — количество процессоров
**Вывод:** Параллелизация эффективна только при малой доле последовательного кода.
## Принципы проектирования масштабируемых систем
### 1. Stateless Services (Бессостоятельные сервисы)
**Принцип:** Сервисы не должны хранить состояние между запросами.
**Преимущества:**
- Легкое горизонтальное масштабирование
- Отказоустойчивость
- Простота балансировки нагрузки
**Реализация:**
```java
// Плохо: Stateful сервис
@Service
public class StatefulUserService {
private Map<String, User> userCache = new HashMap<>();
public User getUser(String id) {
// Состояние хранится в памяти сервиса
return userCache.get(id);
}
}
// Хорошо: Stateless сервис
@Service
public class StatelessUserService {
@Autowired
private UserRepository userRepository;
@Autowired
private RedisTemplate<String, User> redisTemplate;
public User getUser(String id) {
// Состояние хранится во внешнем хранилище
User cached = redisTemplate.opsForValue().get("user:" + id);
if (cached != null) {
return cached;
}
User user = userRepository.findById(id);
redisTemplate.opsForValue().set("user:" + id, user, Duration.ofMinutes(30));
return user;
}
}
```
### 2. Database Sharding (Шардирование базы данных)
**Принцип:** Разделение данных на несколько независимых баз данных.
**Стратегии шардирования:**
```java
// Стратегия шардирования по пользователю
@Service
public class ShardedUserService {
@Autowired
private List<DataSource> shardDataSources;
public DataSource getShardDataSource(String userId) {
int shardIndex = Math.abs(userId.hashCode()) % shardDataSources.size();
return shardDataSources.get(shardIndex);
}
public User saveUser(User user) {
DataSource shard = getShardDataSource(user.getId());
JdbcTemplate template = new JdbcTemplate(shard);
String sql = "INSERT INTO users (id, name, email) VALUES (?, ?, ?)";
template.update(sql, user.getId(), user.getName(), user.getEmail());
return user;
}
public User getUser(String userId) {
DataSource shard = getShardDataSource(userId);
JdbcTemplate template = new JdbcTemplate(shard);
String sql = "SELECT * FROM users WHERE id = ?";
return template.queryForObject(sql, new Object[]{userId}, new UserRowMapper());
}
}
```
### 3. Read Replicas (Реплики для чтения)
**Принцип:** Использование отдельных реплик для операций чтения.
```java
@Configuration
public class DatabaseConfig {
@Bean
@Primary
public DataSource masterDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://master-db:5432/mydb");
config.setUsername("master_user");
config.setPassword("master_password");
return new HikariDataSource(config);
}
@Bean
public DataSource readOnlyDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://replica-db:5432/mydb");
config.setUsername("readonly_user");
config.setPassword("readonly_password");
return new HikariDataSource(config);
}
}
@Service
public class ReadWriteUserService {
@Autowired
@Qualifier("masterDataSource")
private DataSource masterDataSource;
@Autowired
@Qualifier("readOnlyDataSource")
private DataSource readOnlyDataSource;
public User saveUser(User user) {
// Запись в master
JdbcTemplate masterTemplate = new JdbcTemplate(masterDataSource);
String sql = "INSERT INTO users (id, name, email) VALUES (?, ?, ?)";
masterTemplate.update(sql, user.getId(), user.getName(), user.getEmail());
return user;
}
public User getUser(String userId) {
// Чтение из replica
JdbcTemplate replicaTemplate = new JdbcTemplate(readOnlyDataSource);
String sql = "SELECT * FROM users WHERE id = ?";
return replicaTemplate.queryForObject(sql, new Object[]{userId}, new UserRowMapper());
}
}
```
### 4. Caching Strategies (Стратегии кэширования)
**Cache-Aside Pattern:**
```java
@Service
public class CacheAsideUserService {
@Autowired
private UserRepository userRepository;
@Autowired
private RedisTemplate<String, User> redisTemplate;
public User getUser(String userId) {
// 1. Проверка кэша
User cached = redisTemplate.opsForValue().get("user:" + userId);
if (cached != null) {
return cached;
}
// 2. Загрузка из БД
User user = userRepository.findById(userId);
// 3. Сохранение в кэш
if (user != null) {
redisTemplate.opsForValue().set("user:" + userId, user, Duration.ofMinutes(30));
}
return user;
}
public User updateUser(User user) {
// 1. Обновление в БД
User updated = userRepository.save(user);
// 2. Обновление кэша
redisTemplate.opsForValue().set("user:" + user.getId(), updated, Duration.ofMinutes(30));
return updated;
}
public void deleteUser(String userId) {
// 1. Удаление из БД
userRepository.deleteById(userId);
// 2. Удаление из кэша
redisTemplate.delete("user:" + userId);
}
}
```
## Архитектурные принципы масштабируемости
### 1. Microservices Architecture
**Принципы:**
- Разделение по бизнес-доменам
- Независимое развертывание
- Слабая связанность
- Высокая когезия
```java
// Пример микросервиса пользователей
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable String id) {
User user = userService.getUser(id);
return ResponseEntity.ok(user);
}
@PostMapping
public ResponseEntity<User> createUser(@RequestBody CreateUserRequest request) {
User user = userService.createUser(request);
return ResponseEntity.status(HttpStatus.CREATED).body(user);
}
}
```
### 2. Event-Driven Architecture
**Принципы:**
- События как основной способ коммуникации
- Асинхронная обработка
- Слабая связанность сервисов
```java
// Event Publisher
@Component
public class UserEventPublisher {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void publishUserCreated(User user) {
UserCreatedEvent event = new UserCreatedEvent(user);
eventPublisher.publishEvent(event);
}
}
// Event Listener
@Component
public class UserEventListener {
@Autowired
private NotificationService notificationService;
@EventListener
@Async
public void handleUserCreated(UserCreatedEvent event) {
User user = event.getUser();
// Отправка приветственного email
notificationService.sendWelcomeEmail(user);
}
}
```
### 3. API Gateway Pattern
**Функции API Gateway:**
- Маршрутизация запросов
- Аутентификация и авторизация
- Rate limiting
- Мониторинг и логирование
- Кэширование ответов
```java
// Spring Cloud Gateway конфигурация
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("user-service", r -> r.path("/api/users/**")
.filters(f -> f
.stripPrefix(1)
.addRequestHeader("X-Service", "user-service")
.circuitBreaker(config -> config
.setName("user-service-cb")
.setFallbackUri("forward:/fallback/user-service")))
.uri("lb://user-service"))
.build();
}
}
```
## Метрики и мониторинг масштабируемости
### 1. Ключевые метрики
```java
@Component
public class ScalabilityMetrics {
private final MeterRegistry meterRegistry;
private final Counter requestCounter;
private final Timer responseTimer;
public ScalabilityMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.requestCounter = Counter.builder("requests.total")
.description("Total number of requests")
.register(meterRegistry);
this.responseTimer = Timer.builder("response.time")
.description("Response time")
.register(meterRegistry);
}
public void recordRequest(String service, String method) {
requestCounter.increment(
Tags.of("service", service, "method", method)
);
}
public void recordResponseTime(String service, Duration duration) {
responseTimer.record(duration, TimeUnit.MILLISECONDS);
}
}
```
### 2. Автоматическое масштабирование
```yaml
# Kubernetes HPA конфигурация
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: user-service-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: user-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
```