8.1 JVM性能调优
JVM参数配置
# 生产环境JVM参数示例
java -server \
-Xms2g -Xmx2g \
-XX:NewRatio=3 \
-XX:SurvivorRatio=8 \
-XX:MetaspaceSize=256m \
-XX:MaxMetaspaceSize=512m \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:G1HeapRegionSize=16m \
-XX:+UseStringDeduplication \
-XX:+PrintGC \
-XX:+PrintGCDetails \
-XX:+PrintGCTimeStamps \
-XX:+PrintGCApplicationStoppedTime \
-Xloggc:/app/logs/gc.log \
-XX:+UseGCLogFileRotation \
-XX:NumberOfGCLogFiles=5 \
-XX:GCLogFileSize=100M \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/app/logs/heapdump.hprof \
-Djava.awt.headless=true \
-Dfile.encoding=UTF-8 \
-Duser.timezone=Asia/Shanghai \
-jar myapp.jar
GC调优配置类
@Component
@ConfigurationProperties(prefix = "app.jvm")
@Data
public class JvmConfig {
private Memory memory = new Memory();
private Gc gc = new Gc();
private Monitoring monitoring = new Monitoring();
@Data
public static class Memory {
private String heapSize = "2g";
private String newRatio = "3";
private String survivorRatio = "8";
private String metaspaceSize = "256m";
private String maxMetaspaceSize = "512m";
}
@Data
public static class Gc {
private String collector = "G1GC";
private int maxPauseMillis = 200;
private String regionSize = "16m";
private boolean stringDeduplication = true;
private boolean printGcDetails = true;
}
@Data
public static class Monitoring {
private boolean heapDumpOnOom = true;
private String heapDumpPath = "/app/logs/heapdump.hprof";
private String gcLogPath = "/app/logs/gc.log";
private int gcLogFiles = 5;
private String gcLogFileSize = "100M";
}
}
@Component
public class JvmMonitor {
private final MemoryMXBean memoryBean;
private final List<GarbageCollectorMXBean> gcBeans;
private final ThreadMXBean threadBean;
public JvmMonitor() {
this.memoryBean = ManagementFactory.getMemoryMXBean();
this.gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
this.threadBean = ManagementFactory.getThreadMXBean();
}
@EventListener
@Async
public void handleContextRefresh(ContextRefreshedEvent event) {
logJvmInfo();
startPeriodicMonitoring();
}
private void logJvmInfo() {
RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
log.info("JVM启动参数: {}", runtimeBean.getInputArguments());
log.info("JVM版本: {}", runtimeBean.getVmVersion());
log.info("可用处理器: {}", Runtime.getRuntime().availableProcessors());
}
@Scheduled(fixedRate = 60000) // 每分钟检查一次
public void monitorMemory() {
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage();
double heapUsedPercent = (double) heapUsage.getUsed() / heapUsage.getMax() * 100;
double nonHeapUsedPercent = (double) nonHeapUsage.getUsed() / nonHeapUsage.getMax() * 100;
log.debug("堆内存使用率: {:.2f}%, 非堆内存使用率: {:.2f}%",
heapUsedPercent, nonHeapUsedPercent);
// 内存使用率告警
if (heapUsedPercent > 80) {
log.warn("堆内存使用率过高: {:.2f}%", heapUsedPercent);
}
if (nonHeapUsedPercent > 90) {
log.warn("非堆内存使用率过高: {:.2f}%", nonHeapUsedPercent);
}
}
@Scheduled(fixedRate = 300000) // 每5分钟检查一次
public void monitorGc() {
for (GarbageCollectorMXBean gcBean : gcBeans) {
long collections = gcBean.getCollectionCount();
long time = gcBean.getCollectionTime();
if (collections > 0) {
double avgTime = (double) time / collections;
log.debug("GC统计 - {}: 次数={}, 总时间={}ms, 平均时间={:.2f}ms",
gcBean.getName(), collections, time, avgTime);
// GC时间告警
if (avgTime > 100) {
log.warn("GC平均时间过长: {:.2f}ms", avgTime);
}
}
}
}
@Scheduled(fixedRate = 120000) // 每2分钟检查一次
public void monitorThreads() {
int threadCount = threadBean.getThreadCount();
int peakThreadCount = threadBean.getPeakThreadCount();
log.debug("线程统计 - 当前: {}, 峰值: {}", threadCount, peakThreadCount);
// 线程数告警
if (threadCount > 500) {
log.warn("线程数过多: {}", threadCount);
}
}
private void startPeriodicMonitoring() {
// 启动定期监控任务
log.info("JVM监控已启动");
}
}
8.2 数据库性能优化
连接池优化
# application.yml
spring:
datasource:
hikari:
# 连接池配置
minimum-idle: 10
maximum-pool-size: 50
idle-timeout: 300000
max-lifetime: 1800000
connection-timeout: 30000
validation-timeout: 5000
# 连接测试
connection-test-query: SELECT 1
test-while-idle: true
test-on-borrow: false
test-on-return: false
# 性能配置
auto-commit: true
read-only: false
isolation-level: TRANSACTION_READ_COMMITTED
# 监控配置
register-mbeans: true
# 连接属性
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
useLocalSessionState: true
rewriteBatchedStatements: true
cacheResultSetMetadata: true
cacheServerConfiguration: true
elideSetAutoCommits: true
maintainTimeStats: false
jpa:
hibernate:
ddl-auto: none
properties:
hibernate:
# 查询优化
jdbc:
batch_size: 50
fetch_size: 50
# 缓存配置
cache:
use_second_level_cache: true
use_query_cache: true
region:
factory_class: org.hibernate.cache.jcache.JCacheRegionFactory
# SQL优化
show_sql: false
format_sql: false
use_sql_comments: false
# 统计信息
generate_statistics: true
# 连接释放模式
connection:
release_mode: after_transaction
查询优化服务
@Service
@Transactional(readOnly = true)
public class QueryOptimizationService {
@Autowired
private EntityManager entityManager;
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 批量查询优化
*/
public List<User> findUsersByIdsOptimized(List<Long> userIds) {
if (userIds.isEmpty()) {
return Collections.emptyList();
}
// 使用IN查询替代多次单独查询
String jpql = "SELECT u FROM User u WHERE u.id IN :ids";
return entityManager.createQuery(jpql, User.class)
.setParameter("ids", userIds)
.getResultList();
}
/**
* 分页查询优化
*/
public Page<User> findUsersOptimized(Pageable pageable, UserSearchCriteria criteria) {
// 构建动态查询
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> root = query.from(User.class);
List<Predicate> predicates = new ArrayList<>();
// 添加查询条件
if (StringUtils.hasText(criteria.getName())) {
predicates.add(cb.like(root.get("name"), "%" + criteria.getName() + "%"));
}
if (criteria.getStatus() != null) {
predicates.add(cb.equal(root.get("status"), criteria.getStatus()));
}
if (criteria.getCreateTimeStart() != null) {
predicates.add(cb.greaterThanOrEqualTo(root.get("createTime"), criteria.getCreateTimeStart()));
}
if (criteria.getCreateTimeEnd() != null) {
predicates.add(cb.lessThanOrEqualTo(root.get("createTime"), criteria.getCreateTimeEnd()));
}
query.where(predicates.toArray(new Predicate[0]));
// 添加排序
if (pageable.getSort().isSorted()) {
List<Order> orders = new ArrayList<>();
for (Sort.Order sortOrder : pageable.getSort()) {
if (sortOrder.isAscending()) {
orders.add(cb.asc(root.get(sortOrder.getProperty())));
} else {
orders.add(cb.desc(root.get(sortOrder.getProperty())));
}
}
query.orderBy(orders);
}
// 执行查询
TypedQuery<User> typedQuery = entityManager.createQuery(query);
typedQuery.setFirstResult((int) pageable.getOffset());
typedQuery.setMaxResults(pageable.getPageSize());
List<User> users = typedQuery.getResultList();
// 计算总数(优化:只在需要时计算)
long total = countUsersOptimized(criteria);
return new PageImpl<>(users, pageable, total);
}
/**
* 计数查询优化
*/
private long countUsersOptimized(UserSearchCriteria criteria) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
Root<User> root = countQuery.from(User.class);
countQuery.select(cb.count(root));
// 重用查询条件逻辑
List<Predicate> predicates = buildPredicates(cb, root, criteria);
countQuery.where(predicates.toArray(new Predicate[0]));
return entityManager.createQuery(countQuery).getSingleResult();
}
/**
* N+1查询问题解决
*/
public List<User> findUsersWithRolesOptimized() {
// 使用JOIN FETCH避免N+1问题
String jpql = "SELECT DISTINCT u FROM User u LEFT JOIN FETCH u.roles";
return entityManager.createQuery(jpql, User.class).getResultList();
}
/**
* 原生SQL查询优化
*/
public List<UserStatistics> getUserStatistics(LocalDate startDate, LocalDate endDate) {
String sql = """
SELECT
DATE(u.create_time) as date,
COUNT(*) as user_count,
COUNT(CASE WHEN u.status = 'ACTIVE' THEN 1 END) as active_count
FROM users u
WHERE u.create_time BETWEEN ? AND ?
GROUP BY DATE(u.create_time)
ORDER BY date
""";
return jdbcTemplate.query(sql,
(rs, rowNum) -> UserStatistics.builder()
.date(rs.getDate("date").toLocalDate())
.userCount(rs.getLong("user_count"))
.activeCount(rs.getLong("active_count"))
.build(),
startDate, endDate);
}
/**
* 批量操作优化
*/
@Transactional
public void batchUpdateUserStatus(List<Long> userIds, UserStatus status) {
String jpql = "UPDATE User u SET u.status = :status, u.updateTime = :updateTime WHERE u.id IN :ids";
int batchSize = 1000;
for (int i = 0; i < userIds.size(); i += batchSize) {
List<Long> batch = userIds.subList(i, Math.min(i + batchSize, userIds.size()));
entityManager.createQuery(jpql)
.setParameter("status", status)
.setParameter("updateTime", LocalDateTime.now())
.setParameter("ids", batch)
.executeUpdate();
}
}
private List<Predicate> buildPredicates(CriteriaBuilder cb, Root<User> root, UserSearchCriteria criteria) {
List<Predicate> predicates = new ArrayList<>();
if (StringUtils.hasText(criteria.getName())) {
predicates.add(cb.like(root.get("name"), "%" + criteria.getName() + "%"));
}
if (criteria.getStatus() != null) {
predicates.add(cb.equal(root.get("status"), criteria.getStatus()));
}
if (criteria.getCreateTimeStart() != null) {
predicates.add(cb.greaterThanOrEqualTo(root.get("createTime"), criteria.getCreateTimeStart()));
}
if (criteria.getCreateTimeEnd() != null) {
predicates.add(cb.lessThanOrEqualTo(root.get("createTime"), criteria.getCreateTimeEnd()));
}
return predicates;
}
}
@Data
@Builder
public class UserStatistics {
private LocalDate date;
private Long userCount;
private Long activeCount;
}
@Data
public class UserSearchCriteria {
private String name;
private UserStatus status;
private LocalDateTime createTimeStart;
private LocalDateTime createTimeEnd;
}
8.3 缓存优化
多级缓存配置
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
@Primary
public CacheManager cacheManager() {
CompositeCacheManager compositeCacheManager = new CompositeCacheManager();
// L1缓存:本地缓存(Caffeine)
CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
caffeineCacheManager.setCaffeine(Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(Duration.ofMinutes(10))
.recordStats());
// L2缓存:分布式缓存(Redis)
RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory())
.cacheDefaults(redisCacheConfiguration())
.build();
compositeCacheManager.setCacheManagers(Arrays.asList(
caffeineCacheManager,
redisCacheManager
));
compositeCacheManager.setFallbackToNoOpCache(false);
return compositeCacheManager;
}
@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1))
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.disableCachingNullValues();
}
@Bean
public RedisConnectionFactory redisConnectionFactory() {
LettuceConnectionFactory factory = new LettuceConnectionFactory(
new RedisStandaloneConfiguration("localhost", 6379));
factory.setValidateConnection(true);
return factory;
}
}
@Service
public class CacheOptimizationService {
@Autowired
private UserRepository userRepository;
@Autowired
private CacheManager cacheManager;
/**
* 缓存穿透防护
*/
@Cacheable(value = "users", key = "#id", unless = "#result == null")
public Optional<User> findUserById(Long id) {
if (id == null || id <= 0) {
return Optional.empty();
}
return userRepository.findById(id);
}
/**
* 缓存雪崩防护(随机TTL)
*/
@Cacheable(value = "user-list", key = "#criteria.hashCode()")
public List<User> findUsersByCriteria(UserSearchCriteria criteria) {
// 添加随机延迟,防止缓存雪崩
String cacheKey = "user-list::" + criteria.hashCode();
Cache cache = cacheManager.getCache("user-list");
if (cache != null) {
// 设置随机TTL(基础TTL + 随机时间)
long randomTtl = 3600 + new Random().nextInt(600); // 1小时 + 0-10分钟随机
// 这里需要根据具体缓存实现来设置TTL
}
return userRepository.findByCriteria(criteria);
}
/**
* 缓存击穿防护(分布式锁)
*/
@Cacheable(value = "hot-data", key = "#key")
public String getHotData(String key) {
// 使用分布式锁防止缓存击穿
String lockKey = "lock:hot-data:" + key;
try {
// 尝试获取锁
Boolean lockAcquired = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "locked", Duration.ofSeconds(10));
if (Boolean.TRUE.equals(lockAcquired)) {
try {
// 双重检查
Cache cache = cacheManager.getCache("hot-data");
if (cache != null) {
Cache.ValueWrapper wrapper = cache.get(key);
if (wrapper != null) {
return (String) wrapper.get();
}
}
// 从数据库加载数据
return loadDataFromDatabase(key);
} finally {
// 释放锁
redisTemplate.delete(lockKey);
}
} else {
// 等待其他线程加载完成
Thread.sleep(100);
return getHotData(key); // 递归调用
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("获取热点数据被中断", e);
}
}
/**
* 预热缓存
*/
@EventListener
@Async
public void warmUpCache(ContextRefreshedEvent event) {
log.info("开始预热缓存...");
// 预热用户缓存
List<Long> hotUserIds = getHotUserIds();
for (Long userId : hotUserIds) {
findUserById(userId);
}
// 预热配置缓存
loadSystemConfigurations();
log.info("缓存预热完成");
}
/**
* 缓存更新策略
*/
@CacheEvict(value = "users", key = "#user.id")
public User updateUser(User user) {
User updatedUser = userRepository.save(user);
// 异步更新相关缓存
asyncUpdateRelatedCache(user.getId());
return updatedUser;
}
@Async
private void asyncUpdateRelatedCache(Long userId) {
// 更新用户相关的其他缓存
cacheManager.getCache("user-roles").evict(userId);
cacheManager.getCache("user-permissions").evict(userId);
}
private List<Long> getHotUserIds() {
// 获取热点用户ID列表
return Arrays.asList(1L, 2L, 3L, 4L, 5L);
}
private void loadSystemConfigurations() {
// 加载系统配置到缓存
}
private String loadDataFromDatabase(String key) {
// 从数据库加载数据
return "data-" + key;
}
@Autowired
private RedisTemplate<String, Object> redisTemplate;
}
8.4 异步处理优化
线程池配置
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Bean(name = "taskExecutor")
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
// 最大线程数
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);
// 队列容量
executor.setQueueCapacity(1000);
// 线程名前缀
executor.setThreadNamePrefix("async-task-");
// 拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 线程空闲时间
executor.setKeepAliveSeconds(60);
// 等待任务完成后关闭
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(30);
executor.initialize();
return executor;
}
@Bean(name = "ioTaskExecutor")
public ThreadPoolTaskExecutor ioTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// IO密集型任务配置更多线程
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors() * 2);
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 4);
executor.setQueueCapacity(2000);
executor.setThreadNamePrefix("io-task-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setKeepAliveSeconds(120);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
@Override
public Executor getAsyncExecutor() {
return taskExecutor();
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
}
@Component
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
log.error("异步任务执行异常 - 方法: {}, 参数: {}", method.getName(), Arrays.toString(params), ex);
// 发送告警通知
sendAlertNotification(ex, method, params);
}
private void sendAlertNotification(Throwable ex, Method method, Object... params) {
// 实现告警通知逻辑
}
}
@Service
public class AsyncProcessingService {
@Async("taskExecutor")
public CompletableFuture<String> processDataAsync(String data) {
try {
// 模拟数据处理
Thread.sleep(1000);
String result = "Processed: " + data;
log.info("异步处理完成: {}", result);
return CompletableFuture.completedFuture(result);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return CompletableFuture.failedFuture(e);
}
}
@Async("ioTaskExecutor")
public CompletableFuture<Void> sendEmailAsync(String to, String subject, String content) {
try {
// 模拟邮件发送
Thread.sleep(2000);
log.info("邮件发送完成: {} -> {}", subject, to);
return CompletableFuture.completedFuture(null);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return CompletableFuture.failedFuture(e);
}
}
/**
* 批量异步处理
*/
public CompletableFuture<List<String>> batchProcessAsync(List<String> dataList) {
List<CompletableFuture<String>> futures = dataList.stream()
.map(this::processDataAsync)
.collect(Collectors.toList());
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenApply(v -> futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList()));
}
/**
* 异步任务编排
*/
public CompletableFuture<String> complexAsyncWorkflow(String input) {
return processDataAsync(input)
.thenCompose(result -> {
// 第二步处理
return CompletableFuture.supplyAsync(() -> {
return "Enhanced: " + result;
});
})
.thenCompose(enhanced -> {
// 第三步处理
return CompletableFuture.supplyAsync(() -> {
return "Final: " + enhanced;
});
})
.exceptionally(ex -> {
log.error("异步工作流执行失败", ex);
return "Error: " + ex.getMessage();
});
}
}
8.5 HTTP性能优化
连接池配置
@Configuration
public class HttpClientConfig {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
// 配置HTTP连接池
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
factory.setHttpClient(httpClient());
factory.setConnectTimeout(5000);
factory.setReadTimeout(10000);
restTemplate.setRequestFactory(factory);
// 添加拦截器
restTemplate.getInterceptors().add(new LoggingInterceptor());
restTemplate.getInterceptors().add(new RetryInterceptor());
return restTemplate;
}
@Bean
public CloseableHttpClient httpClient() {
return HttpClients.custom()
.setConnectionManager(poolingConnectionManager())
.setDefaultRequestConfig(requestConfig())
.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true))
.build();
}
@Bean
public PoolingHttpClientConnectionManager poolingConnectionManager() {
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
// 最大连接数
manager.setMaxTotal(200);
// 每个路由的最大连接数
manager.setDefaultMaxPerRoute(50);
// 连接存活时间
manager.setDefaultSocketConfig(SocketConfig.custom()
.setSoTimeout(10000)
.build());
return manager;
}
@Bean
public RequestConfig requestConfig() {
return RequestConfig.custom()
.setConnectTimeout(5000)
.setSocketTimeout(10000)
.setConnectionRequestTimeout(3000)
.build();
}
}
@Component
public class LoggingInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution) throws IOException {
long startTime = System.currentTimeMillis();
log.debug("HTTP请求: {} {}", request.getMethod(), request.getURI());
ClientHttpResponse response = execution.execute(request, body);
long duration = System.currentTimeMillis() - startTime;
log.debug("HTTP响应: {} - {}ms", response.getStatusCode(), duration);
return response;
}
}
@Component
public class RetryInterceptor implements ClientHttpRequestInterceptor {
private static final int MAX_RETRIES = 3;
private static final long RETRY_DELAY = 1000;
@Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution) throws IOException {
IOException lastException = null;
for (int i = 0; i < MAX_RETRIES; i++) {
try {
return execution.execute(request, body);
} catch (IOException e) {
lastException = e;
if (i < MAX_RETRIES - 1) {
log.warn("HTTP请求失败,准备重试 ({}/{}): {}",
i + 1, MAX_RETRIES, e.getMessage());
try {
Thread.sleep(RETRY_DELAY * (i + 1));
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new IOException("重试被中断", ie);
}
}
}
}
throw lastException;
}
}
响应压缩配置
# application.yml
server:
compression:
enabled: true
mime-types:
- text/html
- text/xml
- text/plain
- text/css
- text/javascript
- application/javascript
- application/json
- application/xml
min-response-size: 1024
http2:
enabled: true
tomcat:
max-connections: 8192
max-threads: 200
min-spare-threads: 10
accept-count: 100
connection-timeout: 20000
# 访问日志
accesslog:
enabled: true
directory: /app/logs
file-date-format: .yyyy-MM-dd
pattern: '%h %l %u %t "%r" %s %b %D'
prefix: access_log
suffix: .log
8.6 最佳实践总结
性能监控指标
@Component
public class PerformanceMetrics {
private final MeterRegistry meterRegistry;
private final Timer.Sample sample;
public PerformanceMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.sample = Timer.start(meterRegistry);
}
/**
* 记录方法执行时间
*/
@Around("@annotation(Timed)")
public Object timeMethod(ProceedingJoinPoint joinPoint) throws Throwable {
Timer.Sample sample = Timer.start(meterRegistry);
try {
return joinPoint.proceed();
} finally {
sample.stop(Timer.builder("method.execution.time")
.tag("class", joinPoint.getTarget().getClass().getSimpleName())
.tag("method", joinPoint.getSignature().getName())
.register(meterRegistry));
}
}
/**
* 记录数据库查询性能
*/
public void recordDatabaseQuery(String operation, long duration) {
Timer.builder("database.query.time")
.tag("operation", operation)
.register(meterRegistry)
.record(duration, TimeUnit.MILLISECONDS);
}
/**
* 记录缓存命中率
*/
public void recordCacheHit(String cacheName, boolean hit) {
Counter.builder("cache.requests")
.tag("cache", cacheName)
.tag("result", hit ? "hit" : "miss")
.register(meterRegistry)
.increment();
}
/**
* 记录HTTP请求性能
*/
public void recordHttpRequest(String method, String uri, int status, long duration) {
Timer.builder("http.requests")
.tag("method", method)
.tag("uri", uri)
.tag("status", String.valueOf(status))
.register(meterRegistry)
.record(duration, TimeUnit.MILLISECONDS);
}
}
@RestController
public class PerformanceController {
@Autowired
private PerformanceMetrics performanceMetrics;
@GetMapping("/api/performance/metrics")
public ResponseEntity<Map<String, Object>> getPerformanceMetrics() {
Map<String, Object> metrics = new HashMap<>();
// JVM指标
Runtime runtime = Runtime.getRuntime();
metrics.put("jvm.memory.used", runtime.totalMemory() - runtime.freeMemory());
metrics.put("jvm.memory.free", runtime.freeMemory());
metrics.put("jvm.memory.total", runtime.totalMemory());
metrics.put("jvm.memory.max", runtime.maxMemory());
// 线程指标
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
metrics.put("threads.count", threadBean.getThreadCount());
metrics.put("threads.peak", threadBean.getPeakThreadCount());
// GC指标
List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
for (GarbageCollectorMXBean gcBean : gcBeans) {
metrics.put("gc." + gcBean.getName().toLowerCase() + ".collections", gcBean.getCollectionCount());
metrics.put("gc." + gcBean.getName().toLowerCase() + ".time", gcBean.getCollectionTime());
}
return ResponseEntity.ok(metrics);
}
}
性能优化检查清单
## Spring Boot性能优化检查清单
### JVM优化
- [ ] 配置合适的堆内存大小(-Xms, -Xmx)
- [ ] 选择合适的垃圾收集器(G1GC推荐)
- [ ] 配置GC日志和监控
- [ ] 启用JVM性能参数
- [ ] 配置OOM时自动dump堆内存
### 数据库优化
- [ ] 配置连接池参数
- [ ] 优化SQL查询和索引
- [ ] 启用查询缓存
- [ ] 配置批量操作
- [ ] 避免N+1查询问题
### 缓存优化
- [ ] 实现多级缓存策略
- [ ] 防止缓存穿透、击穿、雪崩
- [ ] 配置合理的TTL
- [ ] 实现缓存预热
- [ ] 监控缓存命中率
### 异步处理
- [ ] 配置线程池参数
- [ ] 使用异步处理非关键业务
- [ ] 实现异步任务监控
- [ ] 配置异常处理策略
### HTTP优化
- [ ] 启用响应压缩
- [ ] 配置HTTP/2
- [ ] 优化连接池配置
- [ ] 实现请求重试机制
- [ ] 配置超时参数
### 监控和诊断
- [ ] 集成APM工具
- [ ] 配置性能指标收集
- [ ] 实现健康检查
- [ ] 配置告警规则
- [ ] 定期性能测试
总结
本章详细介绍了Spring Boot应用的性能优化:
- JVM性能调优:内存配置、GC优化、监控指标
- 数据库性能优化:连接池配置、查询优化、批量操作
- 缓存优化:多级缓存、防护策略、预热机制
- 异步处理优化:线程池配置、任务编排、异常处理
- HTTP性能优化:连接池、压缩、重试机制
- 最佳实践:性能监控、优化检查清单
通过这些优化措施,可以显著提升Spring Boot应用的性能和稳定性,为用户提供更好的体验。