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,80 @@
|
||||
# Модуль 10: Производительность и оптимизация
|
||||
|
||||
## Навигация
|
||||
- [🏠 Главная страница курса](../../README.md)
|
||||
|
||||
---
|
||||
|
||||
## Описание модуля
|
||||
Этот модуль посвящен изучению принципов производительности и оптимизации систем. Студенты научатся анализировать производительность, выявлять узкие места, применять различные стратегии оптимизации и планировать ресурсы.
|
||||
|
||||
## Содержание модуля
|
||||
|
||||
### 1. [Основы производительности](sections/01-performance-fundamentals.md)
|
||||
- Метрики производительности (Throughput, Latency, Resource Utilization)
|
||||
- Производительность по уровням (Application, Database, Infrastructure)
|
||||
- Мониторинг и измерение производительности
|
||||
|
||||
### 2. [Профилирование и анализ](sections/02-profiling-analysis.md)
|
||||
- Инструменты профилирования (JProfiler, VisualVM, APM)
|
||||
- Анализ производительности и узких мест
|
||||
- Анализ памяти и утечек
|
||||
|
||||
### 3. [Оптимизация базы данных](sections/03-database-optimization.md)
|
||||
- Оптимизация запросов и индексов
|
||||
- Connection pooling и batch операции
|
||||
- Анализ планов выполнения запросов
|
||||
|
||||
### 4. [Кэширование](sections/04-caching.md)
|
||||
- Стратегии кэширования (Cache-Aside, Write-Through, Write-Behind)
|
||||
- Многоуровневое кэширование
|
||||
- Управление кэшем и метрики
|
||||
|
||||
### 5. [Оптимизация кода и минификация](sections/05-code-optimization-minification.md)
|
||||
- Минификация JavaScript/TypeScript, Java, Rust, Python
|
||||
- Оптимизация изображений и CSS
|
||||
- Оптимизация загрузки ресурсов
|
||||
|
||||
### 6. [Оптимизация сети](sections/06-network-optimization.md)
|
||||
- Connection pooling
|
||||
- Сжатие HTTP ответов
|
||||
- Интеграция с CDN
|
||||
|
||||
### 7. [Capacity Planning](sections/07-capacity-planning.md)
|
||||
- Анализ текущей производительности
|
||||
- Прогнозирование нагрузки
|
||||
- Планирование ресурсов
|
||||
|
||||
### 8. [Performance Testing](sections/08-performance-testing.md)
|
||||
- Типы тестов производительности (Load, Stress, Endurance)
|
||||
- Автоматизация тестов производительности
|
||||
- Анализ результатов тестирования
|
||||
|
||||
### 9. [Практические задания](sections/09-practical-tasks.md)
|
||||
- Задания по профилированию
|
||||
- Оптимизация базы данных
|
||||
- Performance testing
|
||||
|
||||
## Ключевые компетенции
|
||||
- Понимание принципов производительности систем
|
||||
- Умение анализировать и измерять производительность
|
||||
- Навыки профилирования и выявления узких мест
|
||||
- Знание стратегий оптимизации на разных уровнях
|
||||
- Умение планировать ресурсы и capacity planning
|
||||
- Навыки проведения тестов производительности
|
||||
|
||||
## Практические задачи
|
||||
1. **Профилирование приложения** - настройка инструментов профилирования и анализ производительности
|
||||
2. **Оптимизация базы данных** - анализ и оптимизация медленных запросов
|
||||
3. **Performance Testing** - создание и проведение тестов производительности
|
||||
|
||||
## Дополнительные ресурсы
|
||||
- **Инструменты**: JProfiler, VisualVM, New Relic, JMeter, Gatling
|
||||
- **Книги**: "Java Performance", "High Performance Browser Networking"
|
||||
- **Документация**: Spring Boot Performance, JVM Tuning Guide
|
||||
|
||||
## Критерии оценки
|
||||
- Понимание метрик производительности (25%)
|
||||
- Умение использовать инструменты профилирования (25%)
|
||||
- Навыки оптимизации кода и базы данных (25%)
|
||||
- Способность планировать ресурсы и проводить тестирование (25%)
|
||||
@@ -0,0 +1,363 @@
|
||||
# Основы производительности
|
||||
|
||||
## Навигация
|
||||
- [🏠 Главная страница курса](../../../README.md)
|
||||
- [📚 Модуль 10](../README.md)
|
||||
|
||||
---
|
||||
|
||||
## Что такое производительность
|
||||
|
||||
**Производительность** — это способность системы выполнять задачи за определенное время с использованием доступных ресурсов.
|
||||
|
||||
## Метрики производительности
|
||||
|
||||
### 1. Throughput (Пропускная способность)
|
||||
**Определение:** Количество операций, выполняемых за единицу времени.
|
||||
|
||||
**Технический пример - Advanced Performance Monitoring System:**
|
||||
|
||||
```java
|
||||
// Advanced Performance Metrics Collector
|
||||
@Component
|
||||
public class AdvancedPerformanceMetrics {
|
||||
|
||||
private final MeterRegistry meterRegistry;
|
||||
private final Counter requestCounter;
|
||||
private final Timer requestTimer;
|
||||
private final Gauge activeConnections;
|
||||
private final DistributionSummary responseSize;
|
||||
private final Counter errorCounter;
|
||||
|
||||
public AdvancedPerformanceMetrics(MeterRegistry meterRegistry) {
|
||||
this.meterRegistry = meterRegistry;
|
||||
|
||||
// Request metrics
|
||||
this.requestCounter = Counter.builder("requests.total")
|
||||
.description("Total number of requests")
|
||||
.tag("service", "user-service")
|
||||
.register(meterRegistry);
|
||||
|
||||
this.requestTimer = Timer.builder("request.duration")
|
||||
.description("Request processing time")
|
||||
.publishPercentiles(0.5, 0.95, 0.99)
|
||||
.publishPercentileHistogram()
|
||||
.register(meterRegistry);
|
||||
|
||||
// Connection metrics
|
||||
this.activeConnections = Gauge.builder("connections.active")
|
||||
.description("Number of active connections")
|
||||
.register(meterRegistry, this, AdvancedPerformanceMetrics::getActiveConnections);
|
||||
|
||||
// Response size metrics
|
||||
this.responseSize = DistributionSummary.builder("response.size")
|
||||
.description("Response size in bytes")
|
||||
.publishPercentiles(0.5, 0.95, 0.99)
|
||||
.register(meterRegistry);
|
||||
|
||||
// Error metrics
|
||||
this.errorCounter = Counter.builder("errors.total")
|
||||
.description("Total number of errors")
|
||||
.register(meterRegistry);
|
||||
}
|
||||
|
||||
public void recordRequest(Duration duration, int responseSizeBytes, boolean isError) {
|
||||
requestCounter.increment();
|
||||
requestTimer.record(duration);
|
||||
this.responseSize.record(responseSizeBytes);
|
||||
|
||||
if (isError) {
|
||||
errorCounter.increment();
|
||||
}
|
||||
}
|
||||
|
||||
public PerformanceReport generateReport() {
|
||||
return PerformanceReport.builder()
|
||||
.throughput(getThroughput())
|
||||
.averageLatency(getAverageLatency())
|
||||
.p95Latency(getP95Latency())
|
||||
.p99Latency(getP99Latency())
|
||||
.errorRate(getErrorRate())
|
||||
.activeConnections(getActiveConnections())
|
||||
.averageResponseSize(getAverageResponseSize())
|
||||
.timestamp(LocalDateTime.now())
|
||||
.build();
|
||||
}
|
||||
|
||||
public double getThroughput() {
|
||||
double totalTime = requestTimer.totalTime(TimeUnit.SECONDS);
|
||||
return totalTime > 0 ? requestCounter.count() / totalTime : 0;
|
||||
}
|
||||
|
||||
public double getAverageLatency() {
|
||||
return requestTimer.mean(TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public double getP95Latency() {
|
||||
return requestTimer.percentile(0.95, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public double getP99Latency() {
|
||||
return requestTimer.percentile(0.99, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public double getErrorRate() {
|
||||
double totalRequests = requestCounter.count();
|
||||
return totalRequests > 0 ? (errorCounter.count() / totalRequests) * 100 : 0;
|
||||
}
|
||||
|
||||
private double getActiveConnections() {
|
||||
return 0; // Placeholder
|
||||
}
|
||||
|
||||
public double getAverageResponseSize() {
|
||||
return responseSize.mean();
|
||||
}
|
||||
}
|
||||
|
||||
// Performance Optimization Service
|
||||
@Service
|
||||
public class PerformanceOptimizationService {
|
||||
|
||||
@Autowired
|
||||
private AdvancedPerformanceMetrics metrics;
|
||||
|
||||
@Autowired
|
||||
private DatabaseOptimizationService dbOptimizationService;
|
||||
|
||||
// Automatic performance optimization
|
||||
@Scheduled(fixedRate = 60000) // Every minute
|
||||
public void optimizePerformance() {
|
||||
PerformanceReport report = metrics.generateReport();
|
||||
|
||||
if (needsOptimization(report)) {
|
||||
log.warn("Performance optimization triggered: {}", report);
|
||||
|
||||
if (report.getAverageLatency() > 1000) {
|
||||
optimizeLatency();
|
||||
}
|
||||
|
||||
if (report.getErrorRate() > 5) {
|
||||
optimizeErrorHandling();
|
||||
}
|
||||
|
||||
if (report.getThroughput() < 100) {
|
||||
optimizeThroughput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean needsOptimization(PerformanceReport report) {
|
||||
return report.getAverageLatency() > 1000 ||
|
||||
report.getErrorRate() > 5 ||
|
||||
report.getThroughput() < 100 ||
|
||||
report.getP95Latency() > 2000;
|
||||
}
|
||||
|
||||
private void optimizeLatency() {
|
||||
log.info("Optimizing latency...");
|
||||
increaseConnectionPoolSize();
|
||||
enableCompression();
|
||||
optimizeJVMSettings();
|
||||
}
|
||||
|
||||
private void optimizeErrorHandling() {
|
||||
log.info("Optimizing error handling...");
|
||||
enableCircuitBreaker();
|
||||
enableRetryLogic();
|
||||
improveErrorLogging();
|
||||
}
|
||||
|
||||
private void optimizeThroughput() {
|
||||
log.info("Optimizing throughput...");
|
||||
increaseThreadPoolSize();
|
||||
enableAsyncProcessing();
|
||||
optimizeBatchProcessing();
|
||||
}
|
||||
|
||||
private void increaseConnectionPoolSize() {
|
||||
log.info("Increasing connection pool size");
|
||||
}
|
||||
|
||||
private void enableCompression() {
|
||||
log.info("Enabling compression");
|
||||
}
|
||||
|
||||
private void optimizeJVMSettings() {
|
||||
log.info("Optimizing JVM settings");
|
||||
}
|
||||
|
||||
private void enableCircuitBreaker() {
|
||||
log.info("Enabling circuit breaker");
|
||||
}
|
||||
|
||||
private void enableRetryLogic() {
|
||||
log.info("Enabling retry logic");
|
||||
}
|
||||
|
||||
private void improveErrorLogging() {
|
||||
log.info("Improving error logging");
|
||||
}
|
||||
|
||||
private void increaseThreadPoolSize() {
|
||||
log.info("Increasing thread pool size");
|
||||
}
|
||||
|
||||
private void enableAsyncProcessing() {
|
||||
log.info("Enabling async processing");
|
||||
}
|
||||
|
||||
private void optimizeBatchProcessing() {
|
||||
log.info("Optimizing batch processing");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Latency (Задержка)
|
||||
**Определение:** Время выполнения одной операции.
|
||||
|
||||
```java
|
||||
// Измерение latency
|
||||
@Service
|
||||
public class UserService {
|
||||
private final Timer requestTimer;
|
||||
|
||||
public UserService(MeterRegistry meterRegistry) {
|
||||
this.requestTimer = Timer.builder("user.service.duration")
|
||||
.register(meterRegistry);
|
||||
}
|
||||
|
||||
public User getUser(Long id) {
|
||||
return requestTimer.recordCallable(() -> {
|
||||
// бизнес-логика
|
||||
return userRepository.findById(id);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Resource Utilization (Использование ресурсов)
|
||||
**Определение:** Процент использования доступных ресурсов.
|
||||
|
||||
```java
|
||||
// Мониторинг ресурсов
|
||||
@Component
|
||||
public class ResourceMonitor {
|
||||
private final Gauge cpuUsage;
|
||||
private final Gauge memoryUsage;
|
||||
private final Gauge diskUsage;
|
||||
|
||||
public ResourceMonitor(MeterRegistry meterRegistry) {
|
||||
this.cpuUsage = Gauge.builder("system.cpu.usage")
|
||||
.register(meterRegistry, this, ResourceMonitor::getCpuUsage);
|
||||
this.memoryUsage = Gauge.builder("system.memory.usage")
|
||||
.register(meterRegistry, this, ResourceMonitor::getMemoryUsage);
|
||||
this.diskUsage = Gauge.builder("system.disk.usage")
|
||||
.register(meterRegistry, this, ResourceMonitor::getDiskUsage);
|
||||
}
|
||||
|
||||
private double getCpuUsage() {
|
||||
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
|
||||
return osBean.getProcessCpuLoad();
|
||||
}
|
||||
|
||||
private double getMemoryUsage() {
|
||||
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
|
||||
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
|
||||
return (double) heapUsage.getUsed() / heapUsage.getMax();
|
||||
}
|
||||
|
||||
private double getDiskUsage() {
|
||||
File root = new File("/");
|
||||
long totalSpace = root.getTotalSpace();
|
||||
long freeSpace = root.getFreeSpace();
|
||||
return (double) (totalSpace - freeSpace) / totalSpace;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Производительность по уровням
|
||||
|
||||
### 1. Application Level
|
||||
```java
|
||||
// Оптимизация на уровне приложения
|
||||
@Service
|
||||
public class OptimizedUserService {
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private UserCache userCache;
|
||||
|
||||
// Оптимизация: кэширование
|
||||
@Cacheable("users")
|
||||
public User getUser(Long id) {
|
||||
return userRepository.findById(id);
|
||||
}
|
||||
|
||||
// Оптимизация: batch операции
|
||||
public List<User> getUsers(List<Long> ids) {
|
||||
return userRepository.findByIdIn(ids);
|
||||
}
|
||||
|
||||
// Оптимизация: асинхронная обработка
|
||||
@Async
|
||||
public CompletableFuture<Void> processUserAsync(User user) {
|
||||
// асинхронная обработка
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Database Level
|
||||
```java
|
||||
// Оптимизация на уровне базы данных
|
||||
@Repository
|
||||
public class OptimizedUserRepository {
|
||||
|
||||
// Оптимизация: использование индексов
|
||||
@Query("SELECT u FROM User u WHERE u.email = :email")
|
||||
User findByEmail(@Param("email") String email);
|
||||
|
||||
// Оптимизация: пагинация
|
||||
@Query("SELECT u FROM User u")
|
||||
Page<User> findAllUsers(Pageable pageable);
|
||||
|
||||
// Оптимизация: batch операции
|
||||
@Modifying
|
||||
@Query("UPDATE User u SET u.lastLogin = :lastLogin WHERE u.id IN :ids")
|
||||
int updateLastLogin(@Param("ids") List<Long> ids, @Param("lastLogin") LocalDateTime lastLogin);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Infrastructure Level
|
||||
```yaml
|
||||
# Оптимизация на уровне инфраструктуры
|
||||
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
|
||||
resources:
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "1Gi"
|
||||
cpu: "500m"
|
||||
env:
|
||||
- name: JAVA_OPTS
|
||||
value: "-Xms512m -Xmx1g -XX:+UseG1GC"
|
||||
```
|
||||
@@ -0,0 +1,169 @@
|
||||
# Профилирование и анализ
|
||||
|
||||
## Навигация
|
||||
- [🏠 Главная страница курса](../../../README.md)
|
||||
- [📚 Модуль 10](../README.md)
|
||||
|
||||
---
|
||||
|
||||
## Инструменты профилирования
|
||||
|
||||
### 1. JProfiler
|
||||
```java
|
||||
// Профилирование с JProfiler
|
||||
@Service
|
||||
public class ProfiledUserService {
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
public User getUser(Long id) {
|
||||
// JProfiler покажет время выполнения этого метода
|
||||
return userRepository.findById(id);
|
||||
}
|
||||
|
||||
public List<User> searchUsers(String query) {
|
||||
// Профилирование покажет узкие места
|
||||
List<User> users = userRepository.findByNameContaining(query);
|
||||
|
||||
// Профилирование покажет время обработки
|
||||
return users.stream()
|
||||
.filter(user -> user.isActive())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. VisualVM
|
||||
```java
|
||||
// Мониторинг с VisualVM
|
||||
@Component
|
||||
public class PerformanceMonitor {
|
||||
private final MemoryMXBean memoryBean;
|
||||
private final ThreadMXBean threadBean;
|
||||
|
||||
public PerformanceMonitor() {
|
||||
this.memoryBean = ManagementFactory.getMemoryMXBean();
|
||||
this.threadBean = ManagementFactory.getThreadMXBean();
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 5000)
|
||||
public void logPerformanceMetrics() {
|
||||
// Мониторинг памяти
|
||||
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
|
||||
log.info("Heap usage: {} / {}", heapUsage.getUsed(), heapUsage.getMax());
|
||||
|
||||
// Мониторинг потоков
|
||||
int threadCount = threadBean.getThreadCount();
|
||||
log.info("Thread count: {}", threadCount);
|
||||
|
||||
// Мониторинг CPU
|
||||
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
|
||||
double cpuUsage = osBean.getProcessCpuLoad();
|
||||
log.info("CPU usage: {}%", cpuUsage * 100);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Application Performance Monitoring (APM)
|
||||
```java
|
||||
// APM интеграция
|
||||
@Service
|
||||
public class APMUserService {
|
||||
@Autowired
|
||||
private NewRelic newRelic;
|
||||
|
||||
public User getUser(Long id) {
|
||||
newRelic.addCustomParameter("user.id", id);
|
||||
|
||||
try {
|
||||
User user = userRepository.findById(id);
|
||||
newRelic.recordMetric("User/Found", 1);
|
||||
return user;
|
||||
} catch (Exception e) {
|
||||
newRelic.recordMetric("User/Error", 1);
|
||||
newRelic.recordException(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public List<User> searchUsers(String query) {
|
||||
newRelic.addCustomParameter("search.query", query);
|
||||
|
||||
List<User> users = userRepository.findByNameContaining(query);
|
||||
newRelic.recordMetric("User/SearchResults", users.size());
|
||||
|
||||
return users;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Анализ производительности
|
||||
|
||||
### 1. Bottleneck Analysis
|
||||
```java
|
||||
// Анализ узких мест
|
||||
@Service
|
||||
public class BottleneckAnalyzer {
|
||||
private final Timer databaseTimer;
|
||||
private final Timer cacheTimer;
|
||||
private final Timer networkTimer;
|
||||
|
||||
public BottleneckAnalyzer(MeterRegistry meterRegistry) {
|
||||
this.databaseTimer = Timer.builder("database.operation.duration")
|
||||
.register(meterRegistry);
|
||||
this.cacheTimer = Timer.builder("cache.operation.duration")
|
||||
.register(meterRegistry);
|
||||
this.networkTimer = Timer.builder("network.operation.duration")
|
||||
.register(meterRegistry);
|
||||
}
|
||||
|
||||
public User getUser(Long id) {
|
||||
// Анализ времени выполнения каждой операции
|
||||
User user = databaseTimer.recordCallable(() -> {
|
||||
return userRepository.findById(id);
|
||||
});
|
||||
|
||||
if (user != null) {
|
||||
cacheTimer.recordCallable(() -> {
|
||||
userCache.put(id, user);
|
||||
});
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Memory Analysis
|
||||
```java
|
||||
// Анализ памяти
|
||||
@Component
|
||||
public class MemoryAnalyzer {
|
||||
private final MemoryMXBean memoryBean;
|
||||
|
||||
public MemoryAnalyzer() {
|
||||
this.memoryBean = ManagementFactory.getMemoryMXBean();
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 10000)
|
||||
public void analyzeMemory() {
|
||||
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
|
||||
MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage();
|
||||
|
||||
log.info("Heap: {} / {} ({}%)",
|
||||
heapUsage.getUsed(),
|
||||
heapUsage.getMax(),
|
||||
(heapUsage.getUsed() * 100) / heapUsage.getMax());
|
||||
|
||||
log.info("Non-Heap: {} / {} ({}%)",
|
||||
nonHeapUsage.getUsed(),
|
||||
nonHeapUsage.getMax(),
|
||||
(nonHeapUsage.getUsed() * 100) / nonHeapUsage.getMax());
|
||||
|
||||
// Анализ утечек памяти
|
||||
if (heapUsage.getUsed() > heapUsage.getMax() * 0.8) {
|
||||
log.warn("High memory usage detected!");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,145 @@
|
||||
# Оптимизация базы данных
|
||||
|
||||
## Навигация
|
||||
- [🏠 Главная страница курса](../../../README.md)
|
||||
- [📚 Модуль 10](../README.md)
|
||||
|
||||
---
|
||||
|
||||
## Оптимизация запросов
|
||||
|
||||
### 1. Query Optimization
|
||||
```sql
|
||||
-- Оптимизация запросов
|
||||
-- Плохо: медленный запрос
|
||||
SELECT * FROM users u
|
||||
JOIN orders o ON u.id = o.user_id
|
||||
WHERE u.created_at > '2023-01-01'
|
||||
AND o.status = 'COMPLETED';
|
||||
|
||||
-- Хорошо: оптимизированный запрос
|
||||
SELECT u.id, u.name, u.email, COUNT(o.id) as order_count
|
||||
FROM users u
|
||||
JOIN orders o ON u.id = o.user_id
|
||||
WHERE u.created_at > '2023-01-01'
|
||||
AND o.status = 'COMPLETED'
|
||||
GROUP BY u.id, u.name, u.email;
|
||||
|
||||
-- Хорошо: использование индексов
|
||||
CREATE INDEX idx_user_created_at ON users(created_at);
|
||||
CREATE INDEX idx_order_status ON orders(status);
|
||||
CREATE INDEX idx_order_user_status ON orders(user_id, status);
|
||||
```
|
||||
|
||||
### 2. Connection Pooling
|
||||
```java
|
||||
// Настройка пула соединений
|
||||
@Configuration
|
||||
public class DatabaseConfig {
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setJdbcUrl("jdbc:postgresql://localhost:5432/mydb");
|
||||
config.setUsername("user");
|
||||
config.setPassword("password");
|
||||
|
||||
// Оптимизация пула соединений
|
||||
config.setMaximumPoolSize(20);
|
||||
config.setMinimumIdle(5);
|
||||
config.setConnectionTimeout(30000);
|
||||
config.setIdleTimeout(600000);
|
||||
config.setMaxLifetime(1800000);
|
||||
config.setLeakDetectionThreshold(60000);
|
||||
|
||||
return new HikariDataSource(config);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Batch Operations
|
||||
```java
|
||||
// Batch операции
|
||||
@Repository
|
||||
public class OptimizedUserRepository {
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
// Batch вставка
|
||||
public void saveUsers(List<User> users) {
|
||||
String sql = "INSERT INTO users (name, email, created_at) VALUES (?, ?, ?)";
|
||||
|
||||
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
|
||||
@Override
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
User user = users.get(i);
|
||||
ps.setString(1, user.getName());
|
||||
ps.setString(2, user.getEmail());
|
||||
ps.setTimestamp(3, Timestamp.valueOf(user.getCreatedAt()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBatchSize() {
|
||||
return users.size();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Batch обновление
|
||||
public void updateUsers(List<User> users) {
|
||||
String sql = "UPDATE users SET name = ?, email = ? WHERE id = ?";
|
||||
|
||||
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
|
||||
@Override
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
User user = users.get(i);
|
||||
ps.setString(1, user.getName());
|
||||
ps.setString(2, user.getEmail());
|
||||
ps.setLong(3, user.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBatchSize() {
|
||||
return users.size();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Настройка базы данных
|
||||
|
||||
### 1. Index Optimization
|
||||
```sql
|
||||
-- Оптимизация индексов
|
||||
-- Анализ использования индексов
|
||||
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'user@example.com';
|
||||
|
||||
-- Создание составных индексов
|
||||
CREATE INDEX idx_user_email_status ON users(email, status);
|
||||
|
||||
-- Создание частичных индексов
|
||||
CREATE INDEX idx_active_users ON users(email) WHERE status = 'ACTIVE';
|
||||
|
||||
-- Создание функциональных индексов
|
||||
CREATE INDEX idx_user_lower_email ON users(LOWER(email));
|
||||
```
|
||||
|
||||
### 2. Query Plan Analysis
|
||||
```sql
|
||||
-- Анализ планов выполнения
|
||||
EXPLAIN (ANALYZE, BUFFERS)
|
||||
SELECT u.name, COUNT(o.id) as order_count
|
||||
FROM users u
|
||||
LEFT JOIN orders o ON u.id = o.user_id
|
||||
WHERE u.created_at > '2023-01-01'
|
||||
GROUP BY u.id, u.name;
|
||||
|
||||
-- Анализ статистики
|
||||
ANALYZE users;
|
||||
ANALYZE orders;
|
||||
|
||||
-- Обновление статистики
|
||||
UPDATE pg_stat_user_tables
|
||||
SET n_tup_ins = 0, n_tup_upd = 0, n_tup_del = 0
|
||||
WHERE relname = 'users';
|
||||
```
|
||||
@@ -0,0 +1,310 @@
|
||||
# Кэширование
|
||||
|
||||
## Навигация
|
||||
- [🏠 Главная страница курса](../../../README.md)
|
||||
- [📚 Модуль 10](../README.md)
|
||||
|
||||
---
|
||||
|
||||
## Стратегии кэширования
|
||||
|
||||
### 1. Cache-Aside Pattern
|
||||
**Технический пример - Advanced Multi-Level Caching System:**
|
||||
|
||||
```java
|
||||
// Advanced Cache Management Service
|
||||
@Service
|
||||
public class AdvancedCacheService {
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
@Autowired
|
||||
private CacheMetricsService cacheMetricsService;
|
||||
|
||||
// Multi-level caching
|
||||
private final Map<String, Object> localCache = new ConcurrentHashMap<>();
|
||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
|
||||
|
||||
public <T> T get(String cacheKey, Class<T> type, Supplier<T> dataLoader) {
|
||||
// Level 1: Local cache
|
||||
T value = getFromLocalCache(cacheKey, type);
|
||||
if (value != null) {
|
||||
cacheMetricsService.recordCacheHit(cacheKey, CacheLevel.LOCAL);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Level 2: Redis cache
|
||||
value = getFromRedisCache(cacheKey, type);
|
||||
if (value != null) {
|
||||
putToLocalCache(cacheKey, value, Duration.ofMinutes(5));
|
||||
cacheMetricsService.recordCacheHit(cacheKey, CacheLevel.REDIS);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Level 3: Data source
|
||||
cacheMetricsService.recordCacheMiss(cacheKey);
|
||||
value = dataLoader.get();
|
||||
|
||||
if (value != null) {
|
||||
putToLocalCache(cacheKey, value, Duration.ofMinutes(5));
|
||||
putToRedisCache(cacheKey, value, Duration.ofMinutes(30));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public <T> CompletableFuture<T> getAsync(String cacheKey, Class<T> type, Supplier<T> dataLoader) {
|
||||
return CompletableFuture.supplyAsync(() -> get(cacheKey, type, dataLoader), scheduler);
|
||||
}
|
||||
|
||||
public <T> List<T> getBatch(List<String> cacheKeys, Class<T> type, Function<List<String>, List<T>> dataLoader) {
|
||||
List<T> results = new ArrayList<>();
|
||||
List<String> missingKeys = new ArrayList<>();
|
||||
|
||||
// Check local cache first
|
||||
for (String key : cacheKeys) {
|
||||
T value = getFromLocalCache(key, type);
|
||||
if (value != null) {
|
||||
results.add(value);
|
||||
cacheMetricsService.recordCacheHit(key, CacheLevel.LOCAL);
|
||||
} else {
|
||||
missingKeys.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (missingKeys.isEmpty()) {
|
||||
return results;
|
||||
}
|
||||
|
||||
// Check Redis cache
|
||||
List<T> redisValues = getFromRedisCacheBatch(missingKeys, type);
|
||||
List<String> stillMissingKeys = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < missingKeys.size(); i++) {
|
||||
String key = missingKeys.get(i);
|
||||
T value = redisValues.get(i);
|
||||
|
||||
if (value != null) {
|
||||
results.add(value);
|
||||
putToLocalCache(key, value, Duration.ofMinutes(5));
|
||||
cacheMetricsService.recordCacheHit(key, CacheLevel.REDIS);
|
||||
} else {
|
||||
stillMissingKeys.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
// Load missing data
|
||||
if (!stillMissingKeys.isEmpty()) {
|
||||
List<T> loadedData = dataLoader.apply(stillMissingKeys);
|
||||
|
||||
for (int i = 0; i < stillMissingKeys.size(); i++) {
|
||||
String key = stillMissingKeys.get(i);
|
||||
T value = loadedData.get(i);
|
||||
|
||||
if (value != null) {
|
||||
results.add(value);
|
||||
putToLocalCache(key, value, Duration.ofMinutes(5));
|
||||
putToRedisCache(key, value, Duration.ofMinutes(30));
|
||||
}
|
||||
|
||||
cacheMetricsService.recordCacheMiss(key);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public void put(String cacheKey, Object value) {
|
||||
putToLocalCache(cacheKey, value, Duration.ofMinutes(5));
|
||||
putToRedisCache(cacheKey, value, Duration.ofMinutes(30));
|
||||
cacheMetricsService.recordCachePut(cacheKey);
|
||||
}
|
||||
|
||||
public void evict(String cacheKey) {
|
||||
localCache.remove(cacheKey);
|
||||
redisTemplate.delete(cacheKey);
|
||||
cacheMetricsService.recordCacheEvict(cacheKey);
|
||||
}
|
||||
|
||||
public void evictPattern(String pattern) {
|
||||
localCache.entrySet().removeIf(entry -> entry.getKey().matches(pattern));
|
||||
|
||||
Set<String> keys = redisTemplate.keys(pattern);
|
||||
if (keys != null && !keys.isEmpty()) {
|
||||
redisTemplate.delete(keys);
|
||||
}
|
||||
|
||||
cacheMetricsService.recordCacheEvictPattern(pattern);
|
||||
}
|
||||
|
||||
// Cache warming
|
||||
public void warmCache(List<String> keys, Supplier<List<Object>> dataLoader) {
|
||||
log.info("Warming cache with {} keys", keys.size());
|
||||
|
||||
List<Object> data = dataLoader.get();
|
||||
|
||||
for (int i = 0; i < keys.size() && i < data.size(); i++) {
|
||||
String key = keys.get(i);
|
||||
Object value = data.get(i);
|
||||
|
||||
if (value != null) {
|
||||
putToLocalCache(key, value, Duration.ofMinutes(5));
|
||||
putToRedisCache(key, value, Duration.ofMinutes(30));
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Cache warming completed");
|
||||
}
|
||||
|
||||
private <T> T getFromLocalCache(String key, Class<T> type) {
|
||||
Object value = localCache.get(key);
|
||||
return type.cast(value);
|
||||
}
|
||||
|
||||
private <T> T getFromRedisCache(String key, Class<T> type) {
|
||||
try {
|
||||
Object value = redisTemplate.opsForValue().get(key);
|
||||
return type.cast(value);
|
||||
} catch (Exception e) {
|
||||
log.warn("Error getting from Redis cache: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> List<T> getFromRedisCacheBatch(List<String> keys, Class<T> type) {
|
||||
try {
|
||||
List<Object> values = redisTemplate.opsForValue().multiGet(keys);
|
||||
return values.stream()
|
||||
.map(type::cast)
|
||||
.collect(Collectors.toList());
|
||||
} catch (Exception e) {
|
||||
log.warn("Error getting batch from Redis cache: {}", e.getMessage());
|
||||
return keys.stream().map(k -> (T) null).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
private void putToLocalCache(String key, Object value, Duration ttl) {
|
||||
localCache.put(key, value);
|
||||
|
||||
scheduler.schedule(() -> localCache.remove(key), ttl.toMillis(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void putToRedisCache(String key, Object value, Duration ttl) {
|
||||
try {
|
||||
redisTemplate.opsForValue().set(key, value, ttl);
|
||||
} catch (Exception e) {
|
||||
log.warn("Error putting to Redis cache: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Write-Through Pattern
|
||||
```java
|
||||
// Write-Through реализация
|
||||
@Service
|
||||
public class WriteThroughUserService {
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<String, User> redisTemplate;
|
||||
|
||||
public void createUser(User user) {
|
||||
// Сохраняем в БД
|
||||
user = userRepository.save(user);
|
||||
|
||||
// Сохраняем в кэш
|
||||
String cacheKey = "user:" + user.getId();
|
||||
redisTemplate.opsForValue().set(cacheKey, user, Duration.ofMinutes(30));
|
||||
}
|
||||
|
||||
public void updateUser(User user) {
|
||||
// Обновляем БД
|
||||
user = userRepository.save(user);
|
||||
|
||||
// Обновляем кэш
|
||||
String cacheKey = "user:" + user.getId();
|
||||
redisTemplate.opsForValue().set(cacheKey, user, Duration.ofMinutes(30));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Write-Behind Pattern
|
||||
```java
|
||||
// Write-Behind реализация
|
||||
@Service
|
||||
public class WriteBehindUserService {
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<String, User> redisTemplate;
|
||||
|
||||
@Async
|
||||
public void createUser(User user) {
|
||||
// Сохраняем в кэш сразу
|
||||
String cacheKey = "user:" + user.getId();
|
||||
redisTemplate.opsForValue().set(cacheKey, user, Duration.ofMinutes(30));
|
||||
|
||||
// Сохраняем в БД асинхронно
|
||||
CompletableFuture.runAsync(() -> {
|
||||
userRepository.save(user);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Многоуровневое кэширование
|
||||
|
||||
### 1. L1 Cache (Application Level)
|
||||
```java
|
||||
// L1 кэш (в памяти приложения)
|
||||
@Service
|
||||
public class L1CacheUserService {
|
||||
private final Map<Long, User> localCache = new ConcurrentHashMap<>();
|
||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
public User getUser(Long id) {
|
||||
return localCache.computeIfAbsent(id, key -> {
|
||||
User user = userRepository.findById(key);
|
||||
if (user != null) {
|
||||
// Автоматическое удаление через 5 минут
|
||||
scheduler.schedule(() -> localCache.remove(key), 5, TimeUnit.MINUTES);
|
||||
}
|
||||
return user;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. L2 Cache (Distributed Cache)
|
||||
```java
|
||||
// L2 кэш (распределенный)
|
||||
@Service
|
||||
public class L2CacheUserService {
|
||||
@Autowired
|
||||
private RedisTemplate<String, User> redisTemplate;
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
public User getUser(Long id) {
|
||||
String cacheKey = "user:" + id;
|
||||
|
||||
User user = redisTemplate.opsForValue().get(cacheKey);
|
||||
if (user == null) {
|
||||
user = userRepository.findById(id);
|
||||
if (user != null) {
|
||||
redisTemplate.opsForValue().set(cacheKey, user, Duration.ofMinutes(30));
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,357 @@
|
||||
# Оптимизация кода и минификация
|
||||
|
||||
## Навигация
|
||||
- [🏠 Главная страница курса](../../../README.md)
|
||||
- [📚 Модуль 10](../README.md)
|
||||
|
||||
---
|
||||
|
||||
## Принципы оптимизации кода
|
||||
|
||||
### 1. Минификация JavaScript/TypeScript
|
||||
|
||||
**Цели минификации:**
|
||||
- Уменьшение размера файлов
|
||||
- Ускорение загрузки страниц
|
||||
- Снижение трафика
|
||||
- Улучшение производительности
|
||||
|
||||
**Инструменты минификации:**
|
||||
|
||||
```javascript
|
||||
// webpack.config.js - Конфигурация минификации
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
mode: 'production',
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_console: true, // Удаление console.log
|
||||
drop_debugger: true, // Удаление debugger
|
||||
pure_funcs: ['console.log'], // Удаление чистых функций
|
||||
dead_code: true, // Удаление мертвого кода
|
||||
unused: true, // Удаление неиспользуемых переменных
|
||||
},
|
||||
mangle: {
|
||||
toplevel: true, // Обфускация глобальных переменных
|
||||
properties: {
|
||||
regex: /^_/ // Обфускация приватных свойств
|
||||
}
|
||||
},
|
||||
format: {
|
||||
comments: false // Удаление комментариев
|
||||
}
|
||||
},
|
||||
extractComments: false
|
||||
}),
|
||||
new CssMinimizerPlugin({
|
||||
minimizerOptions: {
|
||||
preset: [
|
||||
'default',
|
||||
{
|
||||
discardComments: { removeAll: true },
|
||||
normalizeWhitespace: true,
|
||||
colormin: true,
|
||||
minifySelectors: true
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
],
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
cacheGroups: {
|
||||
vendor: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: 'vendors',
|
||||
chunks: 'all',
|
||||
},
|
||||
common: {
|
||||
name: 'common',
|
||||
minChunks: 2,
|
||||
chunks: 'all',
|
||||
enforce: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Java примеры - Оптимизация сборки:**
|
||||
|
||||
```gradle
|
||||
// build.gradle - Оптимизация Java приложения
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '3.0.0'
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(17)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs += [
|
||||
'-parameters', // Сохранение имен параметров
|
||||
'-Xlint:unchecked', // Предупреждения о небезопасных операциях
|
||||
'-Xlint:deprecation' // Предупреждения об устаревших API
|
||||
]
|
||||
}
|
||||
|
||||
// Оптимизация JAR файла
|
||||
jar {
|
||||
enabled = false
|
||||
archiveClassifier = ''
|
||||
}
|
||||
|
||||
bootJar {
|
||||
enabled = true
|
||||
archiveClassifier = ''
|
||||
|
||||
// Исключение ненужных файлов
|
||||
exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA'
|
||||
|
||||
// Оптимизация манифеста
|
||||
manifest {
|
||||
attributes(
|
||||
'Main-Class': 'com.example.Application',
|
||||
'Implementation-Version': project.version,
|
||||
'Built-By': System.getProperty('user.name'),
|
||||
'Built-Date': new Date().toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Rust примеры - Оптимизация компиляции:**
|
||||
|
||||
```toml
|
||||
# Cargo.toml - Оптимизация Rust приложения
|
||||
[package]
|
||||
name = "my-app"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[profile.release]
|
||||
# Максимальная оптимизация
|
||||
opt-level = 3
|
||||
# Оптимизация размера
|
||||
lto = true
|
||||
# Удаление отладочной информации
|
||||
debug = false
|
||||
# Оптимизация кода
|
||||
codegen-units = 1
|
||||
# Оптимизация паники
|
||||
panic = "abort"
|
||||
# Оптимизация размера
|
||||
strip = true
|
||||
|
||||
[profile.release.package."*"]
|
||||
# Оптимизация всех зависимостей
|
||||
opt-level = 3
|
||||
|
||||
# Дополнительные флаги компиляции
|
||||
[build]
|
||||
rustflags = [
|
||||
"-C", "target-cpu=native", # Оптимизация под текущий CPU
|
||||
"-C", "link-arg=-s", # Удаление символов
|
||||
"-C", "opt-level=3", # Максимальная оптимизация
|
||||
"-C", "lto=fat", # Link Time Optimization
|
||||
]
|
||||
```
|
||||
|
||||
**Python примеры - Оптимизация:**
|
||||
|
||||
```python
|
||||
# Оптимизация Python приложения
|
||||
import sys
|
||||
from typing import List, Dict, Optional
|
||||
from dataclasses import dataclass
|
||||
from functools import lru_cache
|
||||
import asyncio
|
||||
import aiohttp
|
||||
|
||||
# Оптимизированная структура данных
|
||||
@dataclass(frozen=True, slots=True) # slots для экономии памяти
|
||||
class OptimizedUser:
|
||||
id: int
|
||||
name: str
|
||||
email: str
|
||||
status: int # 1 = active, 0 = inactive
|
||||
|
||||
def is_active(self) -> bool:
|
||||
return self.status == 1
|
||||
|
||||
# Кэширование для оптимизации
|
||||
class OptimizedUserService:
|
||||
def __init__(self):
|
||||
self._users_cache: Dict[int, OptimizedUser] = {}
|
||||
self._session: Optional[aiohttp.ClientSession] = None
|
||||
|
||||
async def __aenter__(self):
|
||||
self._session = aiohttp.ClientSession(
|
||||
connector=aiohttp.TCPConnector(
|
||||
limit=100, # Пул соединений
|
||||
limit_per_host=30,
|
||||
ttl_dns_cache=300,
|
||||
use_dns_cache=True,
|
||||
),
|
||||
timeout=aiohttp.ClientTimeout(total=30)
|
||||
)
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||
if self._session:
|
||||
await self._session.close()
|
||||
|
||||
# LRU кэш для часто используемых методов
|
||||
@lru_cache(maxsize=1000)
|
||||
def get_user_by_id_cached(self, user_id: int) -> Optional[OptimizedUser]:
|
||||
return self._users_cache.get(user_id)
|
||||
|
||||
# Batch операции
|
||||
async def get_users_batch(self, user_ids: List[int]) -> List[OptimizedUser]:
|
||||
tasks = [self._fetch_user_async(user_id) for user_id in user_ids]
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
|
||||
users = []
|
||||
for result in results:
|
||||
if isinstance(result, OptimizedUser):
|
||||
users.append(result)
|
||||
|
||||
return users
|
||||
```
|
||||
|
||||
### 2. Оптимизация изображений
|
||||
|
||||
```javascript
|
||||
// webpack.config.js - Оптимизация изображений
|
||||
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(jpe?g|png|gif|svg)$/i,
|
||||
type: 'asset',
|
||||
parser: {
|
||||
dataUrlCondition: {
|
||||
maxSize: 8 * 1024 // 8kb
|
||||
}
|
||||
},
|
||||
generator: {
|
||||
filename: 'images/[name].[hash:8][ext]'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new ImageMinimizerPlugin({
|
||||
minimizer: {
|
||||
implementation: ImageMinimizerPlugin.imageminMinify,
|
||||
options: {
|
||||
plugins: [
|
||||
['gifsicle', { interlaced: true }],
|
||||
['jpegtran', { progressive: true }],
|
||||
['optipng', { optimizationLevel: 5 }],
|
||||
[
|
||||
'svgo',
|
||||
{
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
removeViewBox: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Оптимизация CSS
|
||||
|
||||
```css
|
||||
/* Оптимизированный CSS */
|
||||
/* Удаление неиспользуемых стилей */
|
||||
/* Минификация селекторов */
|
||||
/* Объединение правил */
|
||||
|
||||
/* До оптимизации */
|
||||
.header {
|
||||
background-color: #ffffff;
|
||||
padding: 20px;
|
||||
margin: 0;
|
||||
border: 1px solid #cccccc;
|
||||
}
|
||||
|
||||
.header .title {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
/* После оптимизации */
|
||||
.header{background:#fff;padding:20px;margin:0;border:1px solid #ccc}
|
||||
.header .title{font:bold 24px/1 sans-serif;color:#333}
|
||||
```
|
||||
|
||||
### 4. Оптимизация загрузки ресурсов
|
||||
|
||||
```html
|
||||
<!-- Lazy loading изображений -->
|
||||
<img src="placeholder.jpg"
|
||||
data-src="large-image.jpg"
|
||||
loading="lazy"
|
||||
alt="Описание">
|
||||
|
||||
<!-- Preload критических ресурсов -->
|
||||
<link rel="preload" href="critical.css" as="style">
|
||||
<link rel="preload" href="app.js" as="script">
|
||||
|
||||
<!-- Prefetch для будущих ресурсов -->
|
||||
<link rel="prefetch" href="next-page.js">
|
||||
<link rel="prefetch" href="next-page.css">
|
||||
|
||||
<!-- DNS prefetch -->
|
||||
<link rel="dns-prefetch" href="//fonts.googleapis.com">
|
||||
<link rel="dns-prefetch" href="//cdn.example.com">
|
||||
```
|
||||
|
||||
### 5. Оптимизация базы данных
|
||||
|
||||
```sql
|
||||
-- Оптимизация запросов
|
||||
-- Использование индексов
|
||||
CREATE INDEX idx_user_email ON users(email);
|
||||
CREATE INDEX idx_order_date ON orders(created_at);
|
||||
|
||||
-- Оптимизация JOIN
|
||||
SELECT u.id, u.name, COUNT(o.id) as order_count
|
||||
FROM users u
|
||||
LEFT JOIN orders o ON u.id = o.user_id
|
||||
WHERE u.created_at > '2023-01-01'
|
||||
GROUP BY u.id, u.name;
|
||||
|
||||
-- Партиционирование таблиц
|
||||
CREATE TABLE orders_2023 PARTITION OF orders
|
||||
FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');
|
||||
```
|
||||
@@ -0,0 +1,102 @@
|
||||
# Оптимизация сети
|
||||
|
||||
## Навигация
|
||||
- [🏠 Главная страница курса](../../../README.md)
|
||||
- [📚 Модуль 10](../README.md)
|
||||
|
||||
---
|
||||
|
||||
## Оптимизация сети
|
||||
|
||||
### 1. Connection Pooling
|
||||
```java
|
||||
// Оптимизация HTTP соединений
|
||||
@Configuration
|
||||
public class HttpClientConfig {
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
HttpComponentsClientHttpRequestFactory factory =
|
||||
new HttpComponentsClientHttpRequestFactory();
|
||||
|
||||
// Настройка пула соединений
|
||||
PoolingHttpClientConnectionManager connectionManager =
|
||||
new PoolingHttpClientConnectionManager();
|
||||
connectionManager.setMaxTotal(100);
|
||||
connectionManager.setDefaultMaxPerRoute(20);
|
||||
|
||||
CloseableHttpClient httpClient = HttpClients.custom()
|
||||
.setConnectionManager(connectionManager)
|
||||
.setDefaultRequestConfig(RequestConfig.custom()
|
||||
.setConnectTimeout(5000)
|
||||
.setSocketTimeout(10000)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
factory.setHttpClient(httpClient);
|
||||
return new RestTemplate(factory);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Compression
|
||||
```java
|
||||
// Сжатие HTTP ответов
|
||||
@Configuration
|
||||
public class CompressionConfig {
|
||||
@Bean
|
||||
public FilterRegistrationBean<CompressionFilter> compressionFilter() {
|
||||
FilterRegistrationBean<CompressionFilter> registration =
|
||||
new FilterRegistrationBean<>();
|
||||
registration.setFilter(new CompressionFilter());
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("compressionFilter");
|
||||
registration.setOrder(1);
|
||||
return registration;
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
public class CompressionFilter implements Filter {
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
|
||||
String acceptEncoding = httpRequest.getHeader("Accept-Encoding");
|
||||
if (acceptEncoding != null && acceptEncoding.contains("gzip")) {
|
||||
httpResponse.setHeader("Content-Encoding", "gzip");
|
||||
GzipResponseWrapper gzipResponse = new GzipResponseWrapper(httpResponse);
|
||||
chain.doFilter(request, gzipResponse);
|
||||
gzipResponse.finish();
|
||||
} else {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. CDN Integration
|
||||
```java
|
||||
// Интеграция с CDN
|
||||
@Service
|
||||
public class CDNService {
|
||||
@Value("${cdn.base-url}")
|
||||
private String cdnBaseUrl;
|
||||
|
||||
public String getCDNUrl(String path) {
|
||||
return cdnBaseUrl + "/" + path;
|
||||
}
|
||||
|
||||
public void uploadToCDN(String path, byte[] content) {
|
||||
// Загрузка контента в CDN
|
||||
// Реализация зависит от выбранного CDN провайдера
|
||||
}
|
||||
|
||||
public void invalidateCDNCache(String path) {
|
||||
// Инвалидация кэша CDN
|
||||
// Реализация зависит от выбранного CDN провайдера
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,116 @@
|
||||
# Capacity Planning
|
||||
|
||||
## Навигация
|
||||
- [🏠 Главная страница курса](../../../README.md)
|
||||
- [📚 Модуль 10](../README.md)
|
||||
|
||||
---
|
||||
|
||||
## Процесс планирования мощности
|
||||
|
||||
### 1. Current Capacity Analysis
|
||||
```java
|
||||
// Анализ текущей производительности
|
||||
@Component
|
||||
public class CapacityAnalyzer {
|
||||
private final MeterRegistry meterRegistry;
|
||||
|
||||
public CapacityAnalyzer(MeterRegistry meterRegistry) {
|
||||
this.meterRegistry = meterRegistry;
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 60000) // каждую минуту
|
||||
public void analyzeCapacity() {
|
||||
// Анализ CPU
|
||||
double cpuUsage = getCpuUsage();
|
||||
log.info("CPU usage: {}%", cpuUsage * 100);
|
||||
|
||||
// Анализ памяти
|
||||
double memoryUsage = getMemoryUsage();
|
||||
log.info("Memory usage: {}%", memoryUsage * 100);
|
||||
|
||||
// Анализ пропускной способности
|
||||
double throughput = getThroughput();
|
||||
log.info("Throughput: {} RPS", throughput);
|
||||
|
||||
// Анализ задержки
|
||||
double latency = getLatency();
|
||||
log.info("Latency: {} ms", latency);
|
||||
|
||||
// Предупреждения
|
||||
if (cpuUsage > 0.8) {
|
||||
log.warn("High CPU usage detected!");
|
||||
}
|
||||
if (memoryUsage > 0.8) {
|
||||
log.warn("High memory usage detected!");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Load Forecasting
|
||||
```java
|
||||
// Прогнозирование нагрузки
|
||||
@Service
|
||||
public class LoadForecaster {
|
||||
@Autowired
|
||||
private MetricsRepository metricsRepository;
|
||||
|
||||
public LoadForecast forecastLoad(int days) {
|
||||
// Получаем исторические данные
|
||||
List<MetricData> historicalData = metricsRepository
|
||||
.findByDateRange(LocalDateTime.now().minusDays(30), LocalDateTime.now());
|
||||
|
||||
// Анализируем тренды
|
||||
double growthRate = calculateGrowthRate(historicalData);
|
||||
|
||||
// Прогнозируем нагрузку
|
||||
double currentLoad = getCurrentLoad();
|
||||
double forecastedLoad = currentLoad * Math.pow(1 + growthRate, days);
|
||||
|
||||
return new LoadForecast(forecastedLoad, growthRate, days);
|
||||
}
|
||||
|
||||
private double calculateGrowthRate(List<MetricData> data) {
|
||||
// Простой расчет темпа роста
|
||||
if (data.size() < 2) return 0.0;
|
||||
|
||||
double firstValue = data.get(0).getValue();
|
||||
double lastValue = data.get(data.size() - 1).getValue();
|
||||
|
||||
return (lastValue - firstValue) / firstValue / data.size();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Resource Planning
|
||||
```yaml
|
||||
# Планирование ресурсов
|
||||
capacity_planning:
|
||||
current_capacity:
|
||||
cpu: "4 cores"
|
||||
memory: "8 GB"
|
||||
storage: "100 GB"
|
||||
network: "1 Gbps"
|
||||
|
||||
forecasted_load:
|
||||
peak_rps: 1000
|
||||
average_rps: 500
|
||||
growth_rate: "20% per month"
|
||||
|
||||
resource_requirements:
|
||||
cpu:
|
||||
current: "80% utilization"
|
||||
target: "70% utilization"
|
||||
required: "6 cores"
|
||||
|
||||
memory:
|
||||
current: "75% utilization"
|
||||
target: "65% utilization"
|
||||
required: "12 GB"
|
||||
|
||||
storage:
|
||||
current: "60% utilization"
|
||||
target: "50% utilization"
|
||||
required: "150 GB"
|
||||
```
|
||||
@@ -0,0 +1,174 @@
|
||||
# Performance Testing
|
||||
|
||||
## Навигация
|
||||
- [🏠 Главная страница курса](../../../README.md)
|
||||
- [📚 Модуль 10](../README.md)
|
||||
|
||||
---
|
||||
|
||||
## Типы тестов производительности
|
||||
|
||||
### 1. Load Testing
|
||||
```java
|
||||
// Load тестирование с JMeter
|
||||
@Component
|
||||
public class LoadTestRunner {
|
||||
public void runLoadTest() {
|
||||
// Настройка JMeter теста
|
||||
JMeterEngine engine = new StandardJMeterEngine();
|
||||
|
||||
// Загрузка тестового плана
|
||||
HashTree testPlanTree = new HashTree();
|
||||
TestPlan testPlan = new TestPlan();
|
||||
testPlan.setName("User Service Load Test");
|
||||
|
||||
// Настройка потока
|
||||
ThreadGroup threadGroup = new ThreadGroup();
|
||||
threadGroup.setName("Users");
|
||||
threadGroup.setNumThreads(100);
|
||||
threadGroup.setRampUp(60);
|
||||
threadGroup.setDuration(300); // 5 минут
|
||||
|
||||
// Настройка HTTP запроса
|
||||
HTTPSamplerProxy httpSampler = new HTTPSamplerProxy();
|
||||
httpSampler.setDomain("localhost");
|
||||
httpSampler.setPort(8080);
|
||||
httpSampler.setPath("/api/users");
|
||||
httpSampler.setMethod("GET");
|
||||
|
||||
// Добавление элементов в тест
|
||||
testPlanTree.add(testPlan);
|
||||
testPlanTree.add(testPlan, threadGroup);
|
||||
testPlanTree.add(threadGroup, httpSampler);
|
||||
|
||||
// Запуск теста
|
||||
engine.configure(testPlanTree);
|
||||
engine.run();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Stress Testing
|
||||
```java
|
||||
// Stress тестирование
|
||||
@Service
|
||||
public class StressTestService {
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
public void runStressTest() {
|
||||
int numberOfThreads = 200;
|
||||
int requestsPerThread = 1000;
|
||||
|
||||
ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
|
||||
CountDownLatch latch = new CountDownLatch(numberOfThreads);
|
||||
|
||||
for (int i = 0; i < numberOfThreads; i++) {
|
||||
executor.submit(() -> {
|
||||
try {
|
||||
for (int j = 0; j < requestsPerThread; j++) {
|
||||
// Выполняем запрос
|
||||
userService.getUser((long) (Math.random() * 1000));
|
||||
|
||||
// Небольшая задержка
|
||||
Thread.sleep(10);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Stress test error", e);
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Endurance Testing
|
||||
```java
|
||||
// Endurance тестирование
|
||||
@Component
|
||||
public class EnduranceTestRunner {
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Scheduled(fixedRate = 1000) // каждую секунду
|
||||
public void runEnduranceTest() {
|
||||
try {
|
||||
// Выполняем запрос
|
||||
userService.getUser(1L);
|
||||
|
||||
// Логируем метрики
|
||||
log.info("Endurance test - request completed");
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Endurance test error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Автоматизация тестов производительности
|
||||
|
||||
### 1. Automated Performance Tests
|
||||
```java
|
||||
// Автоматизированные performance тесты
|
||||
@SpringBootTest
|
||||
@TestPropertySource(properties = {
|
||||
"spring.datasource.url=jdbc:h2:mem:testdb",
|
||||
"spring.jpa.hibernate.ddl-auto=create-drop"
|
||||
})
|
||||
public class PerformanceTestSuite {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Test
|
||||
public void testUserServicePerformance() {
|
||||
// Подготовка данных
|
||||
List<User> users = createTestUsers(1000);
|
||||
|
||||
// Измерение времени выполнения
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
for (User user : users) {
|
||||
userService.createUser(user);
|
||||
}
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
long duration = endTime - startTime;
|
||||
|
||||
// Проверка производительности
|
||||
assertThat(duration).isLessThan(5000); // менее 5 секунд
|
||||
|
||||
// Проверка пропускной способности
|
||||
double throughput = (double) users.size() / duration * 1000;
|
||||
assertThat(throughput).isGreaterThan(100); // более 100 RPS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDatabaseQueryPerformance() {
|
||||
// Подготовка данных
|
||||
createTestUsers(10000);
|
||||
|
||||
// Измерение времени выполнения запроса
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
List<User> users = userService.findUsersByName("Test");
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
long duration = endTime - startTime;
|
||||
|
||||
// Проверка производительности
|
||||
assertThat(duration).isLessThan(1000); // менее 1 секунды
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,24 @@
|
||||
# Практические задания
|
||||
|
||||
## Навигация
|
||||
- [🏠 Главная страница курса](../../../README.md)
|
||||
- [📚 Модуль 10](../README.md)
|
||||
|
||||
---
|
||||
|
||||
### Задание 1: Профилирование
|
||||
1. Настройте профилирование приложения
|
||||
2. Проведите анализ производительности
|
||||
3. Выявите узкие места
|
||||
|
||||
### Задание 2: Оптимизация базы данных
|
||||
1. Проанализируйте медленные запросы
|
||||
2. Оптимизируйте индексы
|
||||
3. Настройте пул соединений
|
||||
|
||||
### Задание 3: Performance Testing
|
||||
1. Создайте load тесты
|
||||
2. Проведите stress тестирование
|
||||
3. Проанализируйте результаты
|
||||
|
||||
---
|
||||
@@ -0,0 +1,42 @@
|
||||
# Практические задания
|
||||
|
||||
## Навигация
|
||||
- [🏠 Главная страница курса](../../../README.md)
|
||||
- [📚 Модуль 10](../README.md)
|
||||
|
||||
---
|
||||
|
||||
## Задание 1: Профилирование
|
||||
1. Настройте профилирование приложения
|
||||
2. Проведите анализ производительности
|
||||
3. Выявите узкие места
|
||||
|
||||
## Задание 2: Оптимизация базы данных
|
||||
1. Проанализируйте медленные запросы
|
||||
2. Оптимизируйте индексы
|
||||
3. Настройте пул соединений
|
||||
|
||||
## Задание 3: Performance Testing
|
||||
1. Создайте load тесты
|
||||
2. Проведите stress тестирование
|
||||
3. Проанализируйте результаты
|
||||
|
||||
## Дополнительные ресурсы
|
||||
|
||||
### Инструменты
|
||||
- **Profiling**: JProfiler, VisualVM, YourKit
|
||||
- **APM**: New Relic, AppDynamics, Datadog
|
||||
- **Load Testing**: JMeter, Gatling, K6
|
||||
- **Database**: pgAdmin, MySQL Workbench, MongoDB Compass
|
||||
|
||||
### Книги
|
||||
- "Java Performance" by Scott Oaks
|
||||
- "High Performance Browser Networking" by Ilya Grigorik
|
||||
- "Web Performance in Action" by Jeremy Wagner
|
||||
|
||||
## Контрольные вопросы
|
||||
1. Какие метрики производительности наиболее важны?
|
||||
2. Как определить узкие места в приложении?
|
||||
3. Какие стратегии кэширования вы знаете?
|
||||
4. Как оптимизировать базу данных?
|
||||
5. Что такое capacity planning?
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user