- 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
64 KiB
64 KiB
Модуль 10: Производительность и оптимизация
Содержание модуля
- Основы производительности
- Профилирование и анализ
- Оптимизация базы данных
- Кэширование
- Оптимизация кода и минификация
- Оптимизация сети
- Capacity Planning
- 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: Профилирование
- Настройте профилирование приложения
- Проведите анализ производительности
- Выявите узкие места
Задание 2: Оптимизация базы данных
- Проанализируйте медленные запросы
- Оптимизируйте индексы
- Настройте пул соединений
Задание 3: Performance Testing
- Создайте load тесты
- Проведите stress тестирование
- Проанализируйте результаты
Дополнительные ресурсы
Инструменты
- 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
Контрольные вопросы
- Какие метрики производительности вы знаете?
- Как проводить профилирование приложения?
- Как оптимизировать базу данных?
- Какие стратегии кэширования существуют?
- Как оптимизировать сетевые запросы?
- Что такое Capacity Planning?
- Какие типы performance тестов вы знаете?
- Как автоматизировать performance тестирование?