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
This commit is contained in:
commit
15e744da49
107 files changed
+61762
No files matched your search
@@ -0,0 +1,439 @@
|
||||
# Основы масштабируемости
|
||||
|
||||
## Навигация
|
||||
- [🏠 Главная страница курса](../../../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
|
||||
```
|
||||
Reference in new issue
Block a user