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

64 KiB
Raw Permalink Blame History

Модуль 10: Производительность и оптимизация

Содержание модуля

  1. Основы производительности
  2. Профилирование и анализ
  3. Оптимизация базы данных
  4. Кэширование
  5. Оптимизация кода и минификация
  6. Оптимизация сети
  7. Capacity Planning
  8. Performance Testing

Основы производительности

Что такое производительность

Производительность — это способность системы выполнять задачи за определенное время с использованием доступных ресурсов.

Метрики производительности

1. Throughput (Пропускная способность)

Определение: Количество операций, выполняемых за единицу времени.

Технический пример - Advanced Performance Monitoring System:

// 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 (Задержка)

Определение: Время выполнения одной операции.

// Измерение 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 (Использование ресурсов)

Определение: Процент использования доступных ресурсов.

// Мониторинг ресурсов
@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

// Оптимизация на уровне приложения
@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

-- Оптимизация запросов
-- Плохо: N+1 проблема
SELECT * FROM users;
SELECT * FROM orders WHERE user_id = 1;
SELECT * FROM orders WHERE user_id = 2;
-- ... для каждого пользователя

-- Хорошо: JOIN запрос
SELECT u.*, o.* 
FROM users u 
LEFT JOIN orders o ON u.id = o.user_id;

-- Хорошо: индексы
CREATE INDEX idx_user_email ON users(email);
CREATE INDEX idx_order_user_id ON orders(user_id);
CREATE INDEX idx_order_status ON orders(status);

3. Infrastructure Level

# Оптимизация инфраструктуры
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: user-service
        image: user-service:latest
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        env:
        - name: JAVA_OPTS
          value: "-Xms256m -Xmx512m -XX:+UseG1GC"

Профилирование и анализ

Инструменты профилирования

1. JProfiler

// Профилирование с 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

// Мониторинг с 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)

// 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

// Анализ узких мест
@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

// Анализ памяти
@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!");
        }
    }
}

Оптимизация базы данных

Оптимизация запросов

1. Query Optimization

-- Оптимизация запросов
-- Плохо: медленный запрос
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

// Настройка пула соединений
@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

// 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

-- Оптимизация индексов
-- Анализ использования индексов
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

-- Анализ планов выполнения
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';

Кэширование

Стратегии кэширования

1. Cache-Aside Pattern

Технический пример - Advanced Multi-Level Caching System:

// 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());
        }
    }
}

// Cache Metrics Service
@Service
public class CacheMetricsService {
    
    private final MeterRegistry meterRegistry;
    private final Map<String, CacheMetrics> metrics = new ConcurrentHashMap<>();
    
    public CacheMetricsService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }
    
    public void recordCacheHit(String cacheKey, CacheLevel level) {
        String cacheName = extractCacheName(cacheKey);
        CacheMetrics cacheMetrics = getOrCreateMetrics(cacheName);
        cacheMetrics.recordHit(level);
        
        Counter.builder("cache.hits")
            .tag("cache", cacheName)
            .tag("level", level.name())
            .register(meterRegistry)
            .increment();
    }
    
    public void recordCacheMiss(String cacheKey) {
        String cacheName = extractCacheName(cacheKey);
        CacheMetrics cacheMetrics = getOrCreateMetrics(cacheName);
        cacheMetrics.recordMiss();
        
        Counter.builder("cache.misses")
            .tag("cache", cacheName)
            .register(meterRegistry)
            .increment();
    }
    
    public void recordCachePut(String cacheKey) {
        String cacheName = extractCacheName(cacheKey);
        
        Counter.builder("cache.puts")
            .tag("cache", cacheName)
            .register(meterRegistry)
            .increment();
    }
    
    public void recordCacheEvict(String cacheKey) {
        String cacheName = extractCacheName(cacheKey);
        
        Counter.builder("cache.evicts")
            .tag("cache", cacheName)
            .register(meterRegistry)
            .increment();
    }
    
    public void recordCacheEvictPattern(String pattern) {
        Counter.builder("cache.evicts.pattern")
            .tag("pattern", pattern)
            .register(meterRegistry)
            .increment();
    }
    
    public double getHitRate(String cacheName) {
        CacheMetrics cacheMetrics = metrics.get(cacheName);
        return cacheMetrics != null ? cacheMetrics.getHitRate() : 0.0;
    }
    
    public double getMissRate(String cacheName) {
        CacheMetrics cacheMetrics = metrics.get(cacheName);
        return cacheMetrics != null ? cacheMetrics.getMissRate() : 0.0;
    }
    
    public double getAverageAccessTime(String cacheName) {
        CacheMetrics cacheMetrics = metrics.get(cacheName);
        return cacheMetrics != null ? cacheMetrics.getAverageAccessTime() : 0.0;
    }
    
    private CacheMetrics getOrCreateMetrics(String cacheName) {
        return metrics.computeIfAbsent(cacheName, k -> new CacheMetrics());
    }
    
    private String extractCacheName(String cacheKey) {
        if (cacheKey.contains(":")) {
            return cacheKey.split(":")[0];
        }
        return "default";
    }
}

// Cache Level Enum
public enum CacheLevel {
    LOCAL, REDIS, DATABASE
}

// Cache Metrics
public class CacheMetrics {
    private final AtomicLong hits = new AtomicLong(0);
    private final AtomicLong misses = new AtomicLong(0);
    private final AtomicLong puts = new AtomicLong(0);
    private final AtomicLong evicts = new AtomicLong(0);
    private final AtomicLong totalAccessTime = new AtomicLong(0);
    private final AtomicLong accessCount = new AtomicLong(0);
    
    public void recordHit(CacheLevel level) {
        hits.incrementAndGet();
        recordAccessTime();
    }
    
    public void recordMiss() {
        misses.incrementAndGet();
        recordAccessTime();
    }
    
    public void recordPut() {
        puts.incrementAndGet();
    }
    
    public void recordEvict() {
        evicts.incrementAndGet();
    }
    
    private void recordAccessTime() {
        long startTime = System.nanoTime();
        accessCount.incrementAndGet();
        totalAccessTime.addAndGet(System.nanoTime() - startTime);
    }
    
    public double getHitRate() {
        long total = hits.get() + misses.get();
        return total > 0 ? (double) hits.get() / total : 0.0;
    }
    
    public double getMissRate() {
        long total = hits.get() + misses.get();
        return total > 0 ? (double) misses.get() / total : 0.0;
    }
    
    public double getAverageAccessTime() {
        long count = accessCount.get();
        return count > 0 ? (double) totalAccessTime.get() / count : 0.0;
    }
}

2. Write-Through Pattern

// 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

// 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)

// L1 кэш (в памяти приложения)
@Service
public class L1CacheUserService {
    private final Map<Long, User> localCache = new ConcurrentHashMap<>();
    private final Timer cacheTimer;
    
    public L1CacheUserService(MeterRegistry meterRegistry) {
        this.cacheTimer = Timer.builder("l1.cache.duration")
            .register(meterRegistry);
    }
    
    public User getUser(Long id) {
        return cacheTimer.recordCallable(() -> {
            // Проверяем L1 кэш
            User user = localCache.get(id);
            if (user != null) {
                return user;
            }
            
            // Загружаем из L2 кэша или БД
            user = loadUserFromL2OrDatabase(id);
            if (user != null) {
                localCache.put(id, user);
            }
            
            return user;
        });
    }
}

2. L2 Cache (Distributed Cache)

// L2 кэш (распределенный)
@Service
public class L2CacheUserService {
    @Autowired
    private RedisTemplate<String, User> redisTemplate;
    
    @Autowired
    private UserRepository userRepository;
    
    public User getUser(Long id) {
        String cacheKey = "user:" + id;
        
        // Проверяем L2 кэш
        User user = redisTemplate.opsForValue().get(cacheKey);
        if (user != null) {
            return user;
        }
        
        // Загружаем из БД
        user = userRepository.findById(id);
        if (user != null) {
            // Сохраняем в L2 кэш
            redisTemplate.opsForValue().set(cacheKey, user, Duration.ofMinutes(30));
        }
        
        return user;
    }
}

Оптимизация кода и минификация

Принципы оптимизации кода

1. Минификация JavaScript/TypeScript

Цели минификации:

  • Уменьшение размера файлов
  • Ускорение загрузки страниц
  • Снижение трафика
  • Улучшение производительности

Инструменты минификации:

// 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 примеры - Оптимизация сборки:

// 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()
        )
    }
}

// ProGuard для обфускации и минификации
buildscript {
    dependencies {
        classpath 'com.guardsquare:proguard-gradle:7.2.2'
    }
}

apply plugin: 'com.guardsquare.proguard'

proguard {
    configurations {
        release {
            defaultConfiguration 'proguard-android-optimize.txt'
            
            // Правила для Spring Boot
            configuration '''
                -keep class org.springframework.** { *; }
                -keep class com.example.** { *; }
                -dontwarn org.springframework.**
                -dontwarn javax.annotation.**
                
                # Оптимизация
                -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
                -optimizationpasses 5
                -allowaccessmodification
                -repackageclasses ''
            '''
        }
    }
}

Rust примеры - Оптимизация компиляции:

# 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
]
// main.rs - Оптимизированный код
#![allow(dead_code)]

use std::sync::Arc;
use tokio::sync::RwLock;

// Оптимизированная структура данных
#[derive(Debug, Clone)]
pub struct OptimizedUser {
    id: u64,
    name: String,
    email: String,
    // Использование более компактных типов
    status: u8,  // вместо enum
    created_at: u32,  // timestamp как u32
}

impl OptimizedUser {
    pub fn new(id: u64, name: String, email: String) -> Self {
        Self {
            id,
            name,
            email,
            status: 1, // ACTIVE
            created_at: chrono::Utc::now().timestamp() as u32,
        }
    }
    
    // Inline функции для критического пути
    #[inline(always)]
    pub fn is_active(&self) -> bool {
        self.status == 1
    }
    
    #[inline(always)]
    pub fn get_id(&self) -> u64 {
        self.id
    }
}

// Оптимизированный сервис с пулом соединений
pub struct OptimizedUserService {
    users: Arc<RwLock<Vec<OptimizedUser>>>,
    // Предварительно выделенная память
    capacity: usize,
}

impl OptimizedUserService {
    pub fn new(capacity: usize) -> Self {
        Self {
            users: Arc::new(RwLock::new(Vec::with_capacity(capacity))),
            capacity,
        }
    }
    
    // Batch операции для оптимизации
    pub async fn add_users_batch(&self, users: Vec<OptimizedUser>) {
        let mut user_list = self.users.write().await;
        user_list.reserve(users.len());
        user_list.extend(users);
    }
    
    // Оптимизированный поиск
    pub async fn find_user_by_id(&self, id: u64) -> Option<OptimizedUser> {
        let user_list = self.users.read().await;
        user_list.iter().find(|u| u.id == id).cloned()
    }
}

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
    
    async def _fetch_user_async(self, user_id: int) -> Optional[OptimizedUser]:
        if user_id in self._users_cache:
            return self._users_cache[user_id]
        
        # Асинхронный запрос к API
        if self._session:
            async with self._session.get(f'/api/users/{user_id}') as response:
                if response.status == 200:
                    data = await response.json()
                    user = OptimizedUser(
                        id=data['id'],
                        name=data['name'],
                        email=data['email'],
                        status=data['status']
                    )
                    self._users_cache[user_id] = user
                    return user
        
        return None

# Оптимизация с помощью Cython
# user_service.pyx
cdef class FastUserService:
    cdef dict _users_cache
    cdef int _max_cache_size
    
    def __init__(self, max_cache_size: int = 1000):
        self._users_cache = {}
        self._max_cache_size = max_cache_size
    
    cdef OptimizedUser _get_user_fast(self, int user_id):
        return self._users_cache.get(user_id)
    
    def get_user(self, user_id: int) -> Optional[OptimizedUser]:
        return self._get_user_fast(user_id)

2. Оптимизация изображений

// 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 переменных */
:root {
  --primary-color: #007bff;
  --secondary-color: #6c757d;
  --font-size-base: 1rem;
  --line-height-base: 1.5;
}

/* Минимизация селекторов */
.btn {
  display: inline-block;
  padding: 0.375rem 0.75rem;
  font-size: var(--font-size-base);
  line-height: var(--line-height-base);
  border: 1px solid transparent;
  border-radius: 0.25rem;
  cursor: pointer;
  transition: all 0.15s ease-in-out;
}

.btn-primary {
  color: #fff;
  background-color: var(--primary-color);
  border-color: var(--primary-color);
}

.btn-primary:hover {
  background-color: #0056b3;
  border-color: #004085;
}

/* Критический CSS */
.critical {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  color: #333;
}

4. Оптимизация загрузки ресурсов

<!-- Оптимизированная загрузка ресурсов -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Optimized App</title>
    
    <!-- Preload критических ресурсов -->
    <link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
    <link rel="preload" href="/css/critical.css" as="style">
    <link rel="preload" href="/js/main.js" as="script">
    
    <!-- DNS prefetch для внешних ресурсов -->
    <link rel="dns-prefetch" href="//fonts.googleapis.com">
    <link rel="dns-prefetch" href="//api.example.com">
    
    <!-- Preconnect для важных доменов -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://api.example.com">
    
    <!-- Критический CSS inline -->
    <style>
        /* Critical CSS */
        body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
        .header { background: #007bff; color: white; padding: 1rem; }
        .main { padding: 2rem; }
    </style>
    
    <!-- Lazy load остального CSS -->
    <link rel="stylesheet" href="/css/main.css" media="print" onload="this.media='all'">
    <noscript><link rel="stylesheet" href="/css/main.css"></noscript>
</head>
<body>
    <header class="header">
        <h1>Optimized App</h1>
    </header>
    
    <main class="main">
        <div id="app"></div>
    </main>
    
    <!-- Lazy load JavaScript -->
    <script>
        // Lazy load non-critical scripts
        function loadScript(src) {
            const script = document.createElement('script');
            script.src = src;
            script.async = true;
            document.head.appendChild(script);
        }
        
        // Load after page load
        window.addEventListener('load', function() {
            loadScript('/js/main.js');
            loadScript('/js/analytics.js');
        });
    </script>
</body>
</html>

5. Оптимизация базы данных

// Оптимизация запросов к БД
@Repository
public class OptimizedUserRepository {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    // Batch операции для оптимизации
    public void saveUsersBatch(List<User> users) {
        String sql = "INSERT INTO users (name, email, created_at) VALUES (?, ?, ?)";
        
        List<Object[]> batchArgs = users.stream()
            .map(user -> new Object[]{user.getName(), user.getEmail(), user.getCreatedAt()})
            .collect(Collectors.toList());
        
        jdbcTemplate.batchUpdate(sql, batchArgs);
    }
    
    // Оптимизированный поиск с индексами
    public List<User> findUsersByEmailDomain(String domain) {
        String sql = "SELECT * FROM users WHERE email LIKE ? ORDER BY created_at DESC LIMIT 100";
        return jdbcTemplate.query(sql, new Object[]{"%" + domain}, new UserRowMapper());
    }
    
    // Использование prepared statements
    public Optional<User> findUserById(Long id) {
        String sql = "SELECT * FROM users WHERE id = ?";
        try {
            User user = jdbcTemplate.queryForObject(sql, new Object[]{id}, new UserRowMapper());
            return Optional.ofNullable(user);
        } catch (EmptyResultDataAccessException e) {
            return Optional.empty();
        }
    }
    
    // Оптимизация с помощью кэширования
    @Cacheable(value = "users", key = "#id")
    public User findUserByIdCached(Long id) {
        return findUserById(id).orElse(null);
    }
}

Оптимизация сети

Оптимизация сети

1. Connection Pooling

// Оптимизация 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

// Сжатие 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

// Интеграция с 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 провайдера
    }
}

Capacity Planning

Процесс планирования мощности

1. Current Capacity Analysis

// Анализ текущей производительности
@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

// Прогнозирование нагрузки
@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

# Планирование ресурсов
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"

Performance Testing

Типы тестов производительности

1. Load Testing

// 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

// 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

// 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

// Автоматизированные 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 секунды
    }
}

Практические задания

Задание 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 MySQL" by Baron Schwartz
  • "Systems Performance" by Brendan Gregg

Контрольные вопросы

  1. Какие метрики производительности вы знаете?
  2. Как проводить профилирование приложения?
  3. Как оптимизировать базу данных?
  4. Какие стратегии кэширования существуют?
  5. Как оптимизировать сетевые запросы?
  6. Что такое Capacity Planning?
  7. Какие типы performance тестов вы знаете?
  8. Как автоматизировать performance тестирование?