性能优化与监控实践
概述
性能优化是高级Java工程师必备的核心技能,涉及JVM调优、代码优化、数据库优化、系统架构优化等多个层面。本文深入讲解性能分析方法、优化技巧和监控实践。
核心面试问题
1. 性能分析方法论
面试问题:如何系统性地分析和定位性能问题?有哪些性能分析工具?
性能分析框架
@Component
public class PerformanceAnalyzer {
private static final Logger logger = LoggerFactory.getLogger(PerformanceAnalyzer.class);
@Autowired
private MeterRegistry meterRegistry;
// 1. 方法执行时间统计
@Around("@annotation(PerformanceMonitoring)")
public Object monitorPerformance(ProceedingJoinPoint joinPoint, PerformanceMonitoring annotation) throws Throwable {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
Timer.Sample sample = Timer.start(meterRegistry);
try {
Object result = joinPoint.proceed();
// 记录成功执行时间
sample.stop(Timer.builder("method.execution.time")
.tag("class", className)
.tag("method", methodName)
.tag("status", "success")
.register(meterRegistry));
return result;
} catch (Exception e) {
// 记录异常执行时间
sample.stop(Timer.builder("method.execution.time")
.tag("class", className)
.tag("method", methodName)
.tag("status", "error")
.register(meterRegistry));
// 记录错误指标
Counter.builder("method.error.count")
.tag("class", className)
.tag("method", methodName)
.tag("error", e.getClass().getSimpleName())
.register(meterRegistry)
.increment();
throw e;
}
}
// 2. CPU使用率监控
@Scheduled(fixedRate = 30000) // 每30秒采集一次
public void monitorCpuUsage() {
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
if (osBean instanceof com.sun.management.OperatingSystemMXBean) {
com.sun.management.OperatingSystemMXBean sunBean =
(com.sun.management.OperatingSystemMXBean) osBean;
double processCpuLoad = sunBean.getProcessCpuLoad() * 100;
double systemCpuLoad = sunBean.getSystemCpuLoad() * 100;
Gauge.builder("system.cpu.usage")
.register(meterRegistry, () -> systemCpuLoad);
Gauge.builder("process.cpu.usage")
.register(meterRegistry, () -> processCpuLoad);
// CPU使用率过高告警
if (processCpuLoad > 80) {
logger.warn("进程CPU使用率过高: {:.2f}%", processCpuLoad);
sendAlert("HIGH_CPU_USAGE", "进程CPU使用率: " + String.format("%.2f%%", processCpuLoad));
}
}
}
// 3. 内存使用监控
@Scheduled(fixedRate = 30000)
public void monitorMemoryUsage() {
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage();
long heapUsed = heapUsage.getUsed();
long heapMax = heapUsage.getMax();
long nonHeapUsed = nonHeapUsage.getUsed();
double heapUsagePercent = (double) heapUsed / heapMax * 100;
Gauge.builder("jvm.memory.heap.used")
.register(meterRegistry, () -> heapUsed);
Gauge.builder("jvm.memory.heap.usage.percent")
.register(meterRegistry, () -> heapUsagePercent);
Gauge.builder("jvm.memory.nonheap.used")
.register(meterRegistry, () -> nonHeapUsed);
// 内存使用率过高告警
if (heapUsagePercent > 85) {
logger.warn("堆内存使用率过高: {:.2f}%", heapUsagePercent);
sendAlert("HIGH_MEMORY_USAGE", "堆内存使用率: " + String.format("%.2f%%", heapUsagePercent));
// 自动触发GC
System.gc();
}
}
// 4. GC监控
@PostConstruct
public void initGcMonitoring() {
List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
for (GarbageCollectorMXBean gcBean : gcBeans) {
String gcName = gcBean.getName().replace(" ", "_").toLowerCase();
Gauge.builder("jvm.gc.collections")
.tag("gc", gcName)
.register(meterRegistry, () -> gcBean.getCollectionCount());
Gauge.builder("jvm.gc.time")
.tag("gc", gcName)
.register(meterRegistry, () -> gcBean.getCollectionTime());
}
}
// 5. 线程池监控
public void monitorThreadPool(ThreadPoolExecutor executor, String poolName) {
Gauge.builder("threadpool.active.threads")
.tag("pool", poolName)
.register(meterRegistry, () -> executor.getActiveCount());
Gauge.builder("threadpool.pool.size")
.tag("pool", poolName)
.register(meterRegistry, () -> executor.getPoolSize());
Gauge.builder("threadpool.queue.size")
.tag("pool", poolName)
.register(meterRegistry, () -> executor.getQueue().size());
Gauge.builder("threadpool.completed.tasks")
.tag("pool", poolName)
.register(meterRegistry, () -> executor.getCompletedTaskCount());
}
// 6. 数据库连接池监控
public void monitorDataSource(HikariDataSource dataSource, String dataSourceName) {
HikariPoolMXBean poolBean = dataSource.getHikariPoolMXBean();
Gauge.builder("datasource.active.connections")
.tag("datasource", dataSourceName)
.register(meterRegistry, () -> poolBean.getActiveConnections());
Gauge.builder("datasource.idle.connections")
.tag("datasource", dataSourceName)
.register(meterRegistry, () -> poolBean.getIdleConnections());
Gauge.builder("datasource.total.connections")
.tag("datasource", dataSourceName)
.register(meterRegistry, () -> poolBean.getTotalConnections());
Gauge.builder("datasource.pending.threads")
.tag("datasource", dataSourceName)
.register(meterRegistry, () -> poolBean.getThreadsAwaitingConnection());
}
private void sendAlert(String alertType, String message) {
// 发送告警通知
logger.error("性能告警 [{}]: {}", alertType, message);
}
}
// 性能监控注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PerformanceMonitoring {
String value() default "";
boolean recordArgs() default false;
boolean recordResult() default false;
}
// 业务性能指标收集
@Service
public class BusinessMetricsCollector {
@Autowired
private MeterRegistry meterRegistry;
private final Counter orderCreatedCounter;
private final Timer orderProcessingTimer;
private final DistributionSummary orderAmountSummary;
public BusinessMetricsCollector(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.orderCreatedCounter = Counter.builder("business.orders.created")
.description("Total number of orders created")
.register(meterRegistry);
this.orderProcessingTimer = Timer.builder("business.order.processing.time")
.description("Order processing time")
.register(meterRegistry);
this.orderAmountSummary = DistributionSummary.builder("business.order.amount")
.description("Order amount distribution")
.register(meterRegistry);
}
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
orderCreatedCounter.increment(
Tags.of(
"user_type", event.getUserType(),
"product_category", event.getProductCategory()
)
);
orderAmountSummary.record(event.getAmount().doubleValue());
}
@EventListener
public void handleOrderProcessed(OrderProcessedEvent event) {
orderProcessingTimer.record(event.getProcessingTime(), TimeUnit.MILLISECONDS,
Tags.of(
"status", event.getStatus(),
"payment_method", event.getPaymentMethod()
)
);
}
// 实时性能统计
public PerformanceStats getRealTimeStats() {
return PerformanceStats.builder()
.totalOrders(orderCreatedCounter.count())
.averageProcessingTime(orderProcessingTimer.mean(TimeUnit.MILLISECONDS))
.averageOrderAmount(orderAmountSummary.mean())
.maxOrderAmount(orderAmountSummary.max())
.timestamp(Instant.now())
.build();
}
}
2. JVM性能调优
面试问题:JVM参数如何配置?如何分析堆转储文件?
JVM调优实践
@Configuration
public class JVMOptimizationConfig {
// JVM启动参数配置示例
public static class JVMParameters {
public static void printOptimalParameters() {
System.out.println("=== JVM优化参数建议 ===");
// 堆内存配置
System.out.println("堆内存配置:");
System.out.println("-Xms4g -Xmx4g # 初始和最大堆大小相同");
System.out.println("-XX:NewRatio=2 # 老年代:年轻代 = 2:1");
System.out.println("-XX:SurvivorRatio=8 # Eden:Survivor = 8:1");
// GC配置
System.out.println("\nGC配置:");
System.out.println("-XX:+UseG1GC # 使用G1垃圾收集器");
System.out.println("-XX:MaxGCPauseMillis=200 # 最大GC暂停时间");
System.out.println("-XX:G1HeapRegionSize=16m # G1分区大小");
System.out.println("-XX:G1NewSizePercent=30 # 年轻代最小比例");
System.out.println("-XX:G1MaxNewSizePercent=60 # 年轻代最大比例");
// 方法区配置
System.out.println("\n方法区配置:");
System.out.println("-XX:MetaspaceSize=256m # 元空间初始大小");
System.out.println("-XX:MaxMetaspaceSize=512m # 元空间最大大小");
// 栈配置
System.out.println("\n栈配置:");
System.out.println("-Xss1m # 每个线程栈大小");
// 直接内存配置
System.out.println("\n直接内存配置:");
System.out.println("-XX:MaxDirectMemorySize=1g # 最大直接内存");
// 性能调优参数
System.out.println("\n性能调优参数:");
System.out.println("-XX:+UseFastAccessorMethods # 优化原始类型的getter方法调用");
System.out.println("-XX:+UseCompressedOops # 压缩普通对象指针");
System.out.println("-XX:+UseCompressedClassPointers # 压缩类指针");
System.out.println("-XX:+UseStringDeduplication # 字符串去重");
// 诊断参数
System.out.println("\n诊断参数:");
System.out.println("-XX:+HeapDumpOnOutOfMemoryError # OOM时生成堆转储");
System.out.println("-XX:HeapDumpPath=/path/to/heapdump.hprof # 堆转储文件路径");
System.out.println("-XX:+PrintGC # 打印GC信息");
System.out.println("-XX:+PrintGCDetails # 打印详细GC信息");
System.out.println("-XX:+PrintGCTimeStamps # 打印GC时间戳");
System.out.println("-Xloggc:/path/to/gc.log # GC日志文件");
}
}
}
@Component
public class HeapDumpAnalyzer {
// 生成堆转储
public void generateHeapDump(String filePath) {
try {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy(
server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class);
mxBean.dumpHeap(filePath, true);
System.out.println("堆转储已生成: " + filePath);
} catch (Exception e) {
System.err.println("生成堆转储失败: " + e.getMessage());
}
}
// 分析内存泄漏
public MemoryLeakAnalysis analyzeMemoryLeak() {
MemoryLeakAnalysis analysis = new MemoryLeakAnalysis();
// 1. 获取内存使用情况
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
analysis.setHeapUsed(heapUsage.getUsed());
analysis.setHeapMax(heapUsage.getMax());
analysis.setHeapUsagePercent((double) heapUsage.getUsed() / heapUsage.getMax() * 100);
// 2. 分析各个内存区域
List<MemoryPoolMXBean> memoryPools = ManagementFactory.getMemoryPoolMXBeans();
Map<String, MemoryUsage> poolUsages = new HashMap<>();
for (MemoryPoolMXBean pool : memoryPools) {
poolUsages.put(pool.getName(), pool.getUsage());
}
analysis.setMemoryPoolUsages(poolUsages);
// 3. 检查潜在的内存泄漏
List<String> suspiciousAreas = new ArrayList<>();
// 检查老年代使用率
MemoryUsage oldGenUsage = poolUsages.get("G1 Old Gen");
if (oldGenUsage != null) {
double oldGenPercent = (double) oldGenUsage.getUsed() / oldGenUsage.getMax() * 100;
if (oldGenPercent > 90) {
suspiciousAreas.add("老年代使用率过高: " + String.format("%.2f%%", oldGenPercent));
}
}
// 检查元空间使用率
MemoryUsage metaspaceUsage = poolUsages.get("Metaspace");
if (metaspaceUsage != null) {
double metaspacePercent = (double) metaspaceUsage.getUsed() / metaspaceUsage.getMax() * 100;
if (metaspacePercent > 80) {
suspiciousAreas.add("元空间使用率过高: " + String.format("%.2f%%", metaspacePercent));
}
}
analysis.setSuspiciousAreas(suspiciousAreas);
return analysis;
}
// 分析GC情况
public GCAnalysis analyzeGCPerformance() {
GCAnalysis analysis = new GCAnalysis();
List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
long totalGCTime = 0;
long totalGCCount = 0;
Map<String, GCStats> gcStats = new HashMap<>();
for (GarbageCollectorMXBean gcBean : gcBeans) {
String gcName = gcBean.getName();
long gcTime = gcBean.getCollectionTime();
long gcCount = gcBean.getCollectionCount();
totalGCTime += gcTime;
totalGCCount += gcCount;
GCStats stats = new GCStats();
stats.setGcName(gcName);
stats.setCollectionCount(gcCount);
stats.setCollectionTime(gcTime);
stats.setAverageTime(gcCount > 0 ? (double) gcTime / gcCount : 0);
gcStats.put(gcName, stats);
}
analysis.setTotalGCTime(totalGCTime);
analysis.setTotalGCCount(totalGCCount);
analysis.setGcStats(gcStats);
// 计算GC开销
long uptime = ManagementFactory.getRuntimeMXBean().getUptime();
double gcOverhead = (double) totalGCTime / uptime * 100;
analysis.setGcOverhead(gcOverhead);
// GC性能评估
List<String> recommendations = new ArrayList<>();
if (gcOverhead > 5) {
recommendations.add("GC开销过高(" + String.format("%.2f%%", gcOverhead) + "),建议调整GC参数");
}
analysis.setRecommendations(recommendations);
return analysis;
}
}
// 自动化性能调优
@Component
public class AutoTuning {
@Autowired
private PerformanceAnalyzer performanceAnalyzer;
@Scheduled(fixedRate = 300000) // 每5分钟执行一次
public void autoTunePerformance() {
PerformanceMetrics metrics = collectPerformanceMetrics();
// 根据性能指标自动调整
if (metrics.getCpuUsage() > 80) {
optimizeCpuUsage();
}
if (metrics.getMemoryUsage() > 85) {
optimizeMemoryUsage();
}
if (metrics.getGcOverhead() > 5) {
optimizeGCPerformance();
}
}
private PerformanceMetrics collectPerformanceMetrics() {
// 收集性能指标
return new PerformanceMetrics();
}
private void optimizeCpuUsage() {
// CPU优化策略
System.out.println("执行CPU优化策略:");
System.out.println("1. 降低后台任务频率");
System.out.println("2. 优化算法复杂度");
System.out.println("3. 启用CPU亲和性");
}
private void optimizeMemoryUsage() {
// 内存优化策略
System.out.println("执行内存优化策略:");
System.out.println("1. 清理缓存");
System.out.println("2. 触发手动GC");
System.out.println("3. 优化对象生命周期");
// 清理缓存
clearCaches();
// 建议手动GC
System.gc();
}
private void optimizeGCPerformance() {
// GC优化策略
System.out.println("执行GC优化策略:");
System.out.println("1. 调整堆大小比例");
System.out.println("2. 优化GC触发阈值");
System.out.println("3. 切换GC算法");
}
private void clearCaches() {
// 清理应用缓存
System.out.println("清理应用缓存");
}
}
3. 代码层面性能优化
面试问题:常见的代码性能优化技巧有哪些?如何避免性能陷阱?
代码优化实践
@Service
public class CodeOptimizationExamples {
@Autowired
private UserRepository userRepository;
@Autowired
private OrderRepository orderRepository;
// 1. 字符串拼接优化
public class StringOptimization {
// 错误示例:频繁字符串拼接
public String buildMessageBad(List<String> items) {
String message = "";
for (String item : items) {
message += item + ", "; // 每次都创建新的String对象
}
return message;
}
// 正确示例:使用StringBuilder
public String buildMessageGood(List<String> items) {
StringBuilder sb = new StringBuilder();
for (String item : items) {
sb.append(item).append(", ");
}
return sb.toString();
}
// 更好的示例:使用String.join
public String buildMessageBest(List<String> items) {
return String.join(", ", items);
}
}
// 2. 集合操作优化
public class CollectionOptimization {
// 预分配集合大小
public List<User> processUsersBad(int expectedSize) {
List<User> users = new ArrayList<>(); // 默认大小10,会多次扩容
// 添加用户
return users;
}
public List<User> processUsersGood(int expectedSize) {
List<User> users = new ArrayList<>(expectedSize); // 预分配大小,避免扩容
// 添加用户
return users;
}
// 使用合适的集合类型
public boolean containsUserBad(List<Long> userIds, Long targetId) {
return userIds.contains(targetId); // O(n)时间复杂度
}
public boolean containsUserGood(Set<Long> userIds, Long targetId) {
return userIds.contains(targetId); // O(1)时间复杂度
}
// 避免不必要的装箱拆箱
public int sumNumbersBad(List<Integer> numbers) {
int sum = 0;
for (Integer num : numbers) {
sum += num; // 自动拆箱
}
return sum;
}
public int sumNumbersGood(int[] numbers) {
int sum = 0;
for (int num : numbers) {
sum += num; // 避免装箱拆箱
}
return sum;
}
}
// 3. 数据库查询优化
public class DatabaseOptimization {
// N+1查询问题
public List<OrderWithUser> getOrdersWithUserBad() {
List<Order> orders = orderRepository.findAll();
List<OrderWithUser> result = new ArrayList<>();
for (Order order : orders) {
// 每个订单都会执行一次用户查询,产生N+1问题
User user = userRepository.findById(order.getUserId()).orElse(null);
result.add(new OrderWithUser(order, user));
}
return result;
}
public List<OrderWithUser> getOrdersWithUserGood() {
// 使用JOIN查询一次性获取所有数据
return orderRepository.findOrdersWithUsers();
}
// 批量操作优化
public void updateOrderStatusBad(List<Long> orderIds, String status) {
for (Long orderId : orderIds) {
orderRepository.updateStatus(orderId, status); // 逐条更新
}
}
public void updateOrderStatusGood(List<Long> orderIds, String status) {
orderRepository.batchUpdateStatus(orderIds, status); // 批量更新
}
// 分页查询优化
public List<Order> getOrdersPaginatedBad(int page, int size) {
int offset = page * size;
return orderRepository.findOrdersWithOffset(offset, size); // 大偏移量性能差
}
public List<Order> getOrdersPaginatedGood(Long lastOrderId, int size) {
return orderRepository.findOrdersAfterId(lastOrderId, size); // 游标分页
}
}
// 4. 缓存优化
@Component
public class CacheOptimization {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private final Cache<String, Object> localCache = Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(Duration.ofMinutes(10))
.build();
// 缓存雪崩预防
public Object getCachedDataWithRandomExpiration(String key) {
String cachedValue = (String) redisTemplate.opsForValue().get(key);
if (cachedValue != null) {
return JSON.parseObject(cachedValue, Object.class);
}
Object data = loadDataFromDatabase(key);
if (data != null) {
// 随机过期时间,防止缓存雪崩
int randomMinutes = ThreadLocalRandom.current().nextInt(10, 30);
redisTemplate.opsForValue().set(key, JSON.toJSONString(data),
Duration.ofMinutes(randomMinutes));
}
return data;
}
// 多级缓存
public Object getDataWithMultiLevelCache(String key) {
// 1. 先查本地缓存
Object data = localCache.getIfPresent(key);
if (data != null) {
return data;
}
// 2. 查Redis缓存
String cachedValue = (String) redisTemplate.opsForValue().get(key);
if (cachedValue != null) {
data = JSON.parseObject(cachedValue, Object.class);
localCache.put(key, data); // 回填本地缓存
return data;
}
// 3. 查数据库
data = loadDataFromDatabase(key);
if (data != null) {
redisTemplate.opsForValue().set(key, JSON.toJSONString(data), Duration.ofHours(1));
localCache.put(key, data);
}
return data;
}
private Object loadDataFromDatabase(String key) {
// 模拟数据库查询
return new Object();
}
}
// 5. 异步处理优化
@Component
public class AsyncOptimization {
@Async
public CompletableFuture<String> processDataAsync(String input) {
// 异步处理耗时操作
return CompletableFuture.supplyAsync(() -> {
// 模拟耗时处理
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "Processed: " + input;
});
}
// 并行处理
public List<String> processMultipleData(List<String> inputs) {
List<CompletableFuture<String>> futures = inputs.stream()
.map(this::processDataAsync)
.collect(Collectors.toList());
return futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
}
// 批量异步处理
public void processBatch(List<Order> orders) {
// 分批处理,避免一次性处理太多数据
int batchSize = 100;
for (int i = 0; i < orders.size(); i += batchSize) {
int end = Math.min(i + batchSize, orders.size());
List<Order> batch = orders.subList(i, end);
CompletableFuture.runAsync(() -> processBatchAsync(batch));
}
}
private void processBatchAsync(List<Order> batch) {
// 异步处理批次
for (Order order : batch) {
// 处理订单
}
}
}
// 6. 对象池化
@Component
public class ObjectPoolOptimization {
// 重用昂贵对象
private final ObjectPool<ExpensiveObject> objectPool =
new GenericObjectPool<>(new ExpensiveObjectFactory());
public String processWithPooledObject(String input) {
ExpensiveObject obj = null;
try {
obj = objectPool.borrowObject();
return obj.process(input);
} catch (Exception e) {
throw new RuntimeException("处理失败", e);
} finally {
if (obj != null) {
try {
objectPool.returnObject(obj);
} catch (Exception e) {
// 记录归还对象失败
}
}
}
}
// 线程本地对象复用
private final ThreadLocal<StringBuilder> threadLocalStringBuilder =
ThreadLocal.withInitial(() -> new StringBuilder(256));
public String buildString(List<String> parts) {
StringBuilder sb = threadLocalStringBuilder.get();
sb.setLength(0); // 清空但不释放内存
for (String part : parts) {
sb.append(part);
}
return sb.toString();
}
}
// 7. 算法优化
public class AlgorithmOptimization {
// 查找优化:使用哈希表替代线性查找
public boolean findUserInListBad(List<User> users, Long targetId) {
for (User user : users) {
if (user.getId().equals(targetId)) {
return true;
}
}
return false;
}
public boolean findUserInMapGood(Map<Long, User> userMap, Long targetId) {
return userMap.containsKey(targetId);
}
// 排序优化:选择合适的排序算法
public List<Integer> sortSmallList(List<Integer> numbers) {
// 小列表使用插入排序
if (numbers.size() < 50) {
return insertionSort(new ArrayList<>(numbers));
} else {
// 大列表使用快速排序或归并排序
return numbers.stream().sorted().collect(Collectors.toList());
}
}
private List<Integer> insertionSort(List<Integer> list) {
for (int i = 1; i < list.size(); i++) {
int key = list.get(i);
int j = i - 1;
while (j >= 0 && list.get(j) > key) {
list.set(j + 1, list.get(j));
j--;
}
list.set(j + 1, key);
}
return list;
}
// 缓存计算结果
private final Map<String, Integer> fibonacciCache = new ConcurrentHashMap<>();
public int fibonacciWithCache(int n) {
String key = String.valueOf(n);
return fibonacciCache.computeIfAbsent(key, k -> {
if (n <= 1) return n;
return fibonacciWithCache(n - 1) + fibonacciWithCache(n - 2);
});
}
}
}
// 性能测试工具
@Component
public class PerformanceBenchmark {
public void benchmarkStringConcatenation(int iterations) {
// 测试字符串拼接性能
long start, end;
// String += 方式
start = System.nanoTime();
String result1 = "";
for (int i = 0; i < iterations; i++) {
result1 += "test";
}
end = System.nanoTime();
System.out.println("String += 耗时: " + (end - start) / 1_000_000 + "ms");
// StringBuilder 方式
start = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < iterations; i++) {
sb.append("test");
}
String result2 = sb.toString();
end = System.nanoTime();
System.out.println("StringBuilder 耗时: " + (end - start) / 1_000_000 + "ms");
}
public void benchmarkCollectionOperations(int size) {
List<Integer> list = new ArrayList<>();
Set<Integer> set = new HashSet<>();
// 填充数据
for (int i = 0; i < size; i++) {
list.add(i);
set.add(i);
}
int target = size / 2;
// 测试查找性能
long start = System.nanoTime();
boolean found1 = list.contains(target);
long end = System.nanoTime();
System.out.println("List.contains 耗时: " + (end - start) + "ns");
start = System.nanoTime();
boolean found2 = set.contains(target);
end = System.nanoTime();
System.out.println("Set.contains 耗时: " + (end - start) + "ns");
}
}
4. 系统架构性能优化
面试问题:如何设计高性能的系统架构?负载均衡、缓存、数据库优化策略?
架构优化方案
// 1. 负载均衡策略
@Component
public class LoadBalancingOptimization {
private final List<ServerInstance> servers;
private final AtomicInteger roundRobinCounter = new AtomicInteger(0);
private final Map<String, Integer> serverWeights;
public LoadBalancingOptimization() {
this.servers = initServers();
this.serverWeights = initWeights();
}
// 轮询负载均衡
public ServerInstance roundRobinSelect() {
if (servers.isEmpty()) {
return null;
}
int index = roundRobinCounter.getAndIncrement() % servers.size();
return servers.get(index);
}
// 加权轮询
public ServerInstance weightedRoundRobinSelect() {
int totalWeight = serverWeights.values().stream().mapToInt(Integer::intValue).sum();
int randomWeight = ThreadLocalRandom.current().nextInt(totalWeight);
int currentWeight = 0;
for (ServerInstance server : servers) {
currentWeight += serverWeights.get(server.getId());
if (randomWeight < currentWeight) {
return server;
}
}
return servers.get(0); // 默认返回第一个
}
// 最少连接数负载均衡
public ServerInstance leastConnectionsSelect() {
return servers.stream()
.min(Comparator.comparing(ServerInstance::getActiveConnections))
.orElse(null);
}
// 响应时间加权
public ServerInstance responseTimeWeightedSelect() {
return servers.stream()
.filter(ServerInstance::isHealthy)
.min(Comparator.comparing(server ->
server.getAverageResponseTime() * server.getActiveConnections()))
.orElse(null);
}
// 一致性哈希负载均衡(适用于缓存场景)
public ServerInstance consistentHashSelect(String key) {
if (servers.isEmpty()) {
return null;
}
TreeMap<Integer, ServerInstance> hashRing = buildHashRing();
int hash = key.hashCode();
Map.Entry<Integer, ServerInstance> entry = hashRing.ceilingEntry(hash);
if (entry == null) {
entry = hashRing.firstEntry();
}
return entry.getValue();
}
private TreeMap<Integer, ServerInstance> buildHashRing() {
TreeMap<Integer, ServerInstance> hashRing = new TreeMap<>();
for (ServerInstance server : servers) {
for (int i = 0; i < 160; i++) { // 虚拟节点
String virtualNode = server.getId() + "#" + i;
hashRing.put(virtualNode.hashCode(), server);
}
}
return hashRing;
}
private List<ServerInstance> initServers() {
return Arrays.asList(
new ServerInstance("server1", "192.168.1.10", 8080),
new ServerInstance("server2", "192.168.1.11", 8080),
new ServerInstance("server3", "192.168.1.12", 8080)
);
}
private Map<String, Integer> initWeights() {
Map<String, Integer> weights = new HashMap<>();
weights.put("server1", 3); // 高性能服务器,权重大
weights.put("server2", 2);
weights.put("server3", 1);
return weights;
}
}
// 2. 连接池优化
@Configuration
public class ConnectionPoolOptimization {
// 数据库连接池优化
@Bean
@Primary
public DataSource optimizedDataSource() {
HikariConfig config = new HikariConfig();
// 基础连接配置
config.setJdbcUrl("jdbc:mysql://localhost:3306/testdb");
config.setUsername("root");
config.setPassword("password");
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
// 连接池大小优化
int cpuCores = Runtime.getRuntime().availableProcessors();
config.setMaximumPoolSize(cpuCores * 2); // 核心数的2倍
config.setMinimumIdle(cpuCores); // 最小空闲连接
// 连接超时优化
config.setConnectionTimeout(30000); // 30秒连接超时
config.setIdleTimeout(600000); // 10分钟空闲超时
config.setMaxLifetime(1800000); // 30分钟最大生命周期
config.setLeakDetectionThreshold(60000); // 1分钟泄露检测
// 性能优化配置
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
config.addDataSourceProperty("useServerPrepStmts", "true");
config.addDataSourceProperty("rewriteBatchedStatements", "true");
return new HikariDataSource(config);
}
// Redis连接池优化
@Bean
public LettuceConnectionFactory optimizedRedisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName("localhost");
config.setPort(6379);
// 连接池配置
GenericObjectPoolConfig<Object> poolConfig = new GenericObjectPoolConfig<>();
poolConfig.setMaxTotal(20); // 最大连接数
poolConfig.setMaxIdle(10); // 最大空闲连接
poolConfig.setMinIdle(5); // 最小空闲连接
poolConfig.setMaxWaitMillis(3000); // 最大等待时间
poolConfig.setTestOnBorrow(true); // 借用时测试
poolConfig.setTestOnReturn(true); // 归还时测试
poolConfig.setTestWhileIdle(true); // 空闲时测试
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
.poolConfig(poolConfig)
.commandTimeout(Duration.ofSeconds(30))
.shutdownTimeout(Duration.ofSeconds(20))
.build();
return new LettuceConnectionFactory(config, clientConfig);
}
// HTTP连接池优化
@Bean
public RestTemplate optimizedRestTemplate() {
// 配置HTTP连接池
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(200); // 最大连接数
connectionManager.setDefaultMaxPerRoute(50); // 每个路由的最大连接数
// 配置超时
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(3000) // 从连接池获取连接超时
.setConnectTimeout(3000) // 连接超时
.setSocketTimeout(30000) // 读取超时
.build();
// 创建HttpClient
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig)
.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true))
.build();
// 配置RestTemplate
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory(httpClient);
RestTemplate restTemplate = new RestTemplate(factory);
// 添加拦截器进行监控
restTemplate.getInterceptors().add(new HttpRequestInterceptor());
return restTemplate;
}
}
// 3. 缓存层级优化
@Service
public class MultiLevelCacheOptimization {
// L1: 本地缓存
private final Cache<String, Object> l1Cache = Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(Duration.ofMinutes(5))
.recordStats()
.build();
// L2: Redis缓存
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// L3: 数据库
@Autowired
private DataRepository dataRepository;
public <T> T getWithMultiLevelCache(String key, Class<T> clazz, Function<String, T> dataLoader) {
// L1缓存查询
Object cached = l1Cache.getIfPresent(key);
if (cached != null) {
recordCacheHit("L1", key);
return clazz.cast(cached);
}
// L2缓存查询
Object redisCached = redisTemplate.opsForValue().get(key);
if (redisCached != null) {
recordCacheHit("L2", key);
// 回填L1缓存
l1Cache.put(key, redisCached);
return clazz.cast(redisCached);
}
// L3数据源查询
T data = dataLoader.apply(key);
if (data != null) {
recordCacheMiss(key);
// 写入L2缓存
redisTemplate.opsForValue().set(key, data, Duration.ofHours(1));
// 写入L1缓存
l1Cache.put(key, data);
}
return data;
}
// 缓存预热
@PostConstruct
public void warmUpCache() {
CompletableFuture.runAsync(() -> {
System.out.println("开始缓存预热...");
// 预热热点数据
List<String> hotKeys = getHotKeys();
for (String key : hotKeys) {
try {
getWithMultiLevelCache(key, Object.class, dataRepository::findByKey);
Thread.sleep(10); // 避免过快的预热影响正常业务
} catch (Exception e) {
System.err.println("预热失败: " + key + ", " + e.getMessage());
}
}
System.out.println("缓存预热完成");
});
}
// 缓存统计
@Scheduled(fixedRate = 60000) // 每分钟统计一次
public void reportCacheStats() {
CacheStats stats = l1Cache.stats();
System.out.println("L1缓存统计:");
System.out.println("命中率: " + String.format("%.2f%%", stats.hitRate() * 100));
System.out.println("请求数: " + stats.requestCount());
System.out.println("命中数: " + stats.hitCount());
System.out.println("未命中数: " + stats.missCount());
System.out.println("加载时间: " + stats.averageLoadTime() + "ns");
System.out.println("逐出数: " + stats.evictionCount());
}
private List<String> getHotKeys() {
// 获取热点数据的键
return Arrays.asList("user:1", "product:1", "config:system");
}
private void recordCacheHit(String level, String key) {
// 记录缓存命中指标
Metrics.counter("cache.hit", "level", level).increment();
}
private void recordCacheMiss(String key) {
// 记录缓存未命中指标
Metrics.counter("cache.miss").increment();
}
}
// 4. 分布式锁优化
@Component
public class DistributedLockOptimization {
@Autowired
private RedisTemplate<String, String> redisTemplate;
// 高性能分布式锁实现
public boolean tryLockWithTimeout(String lockKey, String lockValue,
long timeout, TimeUnit unit) {
long timeoutMillis = unit.toMillis(timeout);
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < timeoutMillis) {
// 尝试获取锁
Boolean success = redisTemplate.opsForValue().setIfAbsent(
lockKey, lockValue, Duration.ofMillis(timeoutMillis));
if (Boolean.TRUE.equals(success)) {
return true;
}
// 自旋等待,但要避免CPU空转
try {
Thread.sleep(10); // 10ms自旋间隔
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
return false;
}
// 可重入锁实现
private final ThreadLocal<Map<String, Integer>> lockCounts =
ThreadLocal.withInitial(HashMap::new);
public boolean reentrantLock(String lockKey, String lockValue, long timeout) {
Map<String, Integer> currentThreadLocks = lockCounts.get();
// 检查是否已经持有锁
Integer count = currentThreadLocks.get(lockKey);
if (count != null && count > 0) {
// 重入锁
currentThreadLocks.put(lockKey, count + 1);
return true;
}
// 尝试获取新锁
if (tryLockWithTimeout(lockKey, lockValue, timeout, TimeUnit.MILLISECONDS)) {
currentThreadLocks.put(lockKey, 1);
return true;
}
return false;
}
public void reentrantUnlock(String lockKey, String lockValue) {
Map<String, Integer> currentThreadLocks = lockCounts.get();
Integer count = currentThreadLocks.get(lockKey);
if (count != null && count > 0) {
if (count == 1) {
// 释放锁
releaseLock(lockKey, lockValue);
currentThreadLocks.remove(lockKey);
} else {
// 减少重入次数
currentThreadLocks.put(lockKey, count - 1);
}
}
}
private void releaseLock(String lockKey, String lockValue) {
String script = """
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
""";
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
redisTemplate.execute(redisScript, Collections.singletonList(lockKey), lockValue);
}
}
高频面试题目
1. 理论深度题目
Q: 如何定位Java应用的性能瓶颈?
A: 性能瓶颈定位方法:
- 系统层面:CPU、内存、磁盘I/O、网络I/O监控
- JVM层面:堆内存、GC情况、线程状态分析
- 应用层面:方法执行时间、数据库查询、缓存命中率
- 工具使用:JProfiler、VisualVM、Arthas、APM工具
Q: JVM调优的一般步骤是什么?
A: JVM调优步骤:
- 现状分析:收集性能基线数据
- 瓶颈定位:确定性能瓶颈所在
- 参数调整:针对性调整JVM参数
- 效果验证:测试验证调优效果
- 持续监控:建立长期监控机制
2. 实战应用题目
Q: 如何优化一个高并发的电商系统?
答题要点:
- 架构优化:微服务拆分、负载均衡、CDN加速
- 缓存策略:多级缓存、缓存预热、缓存更新策略
- 数据库优化:读写分离、分库分表、索引优化
- 代码优化:异步处理、批量操作、对象池化
- 监控告警:全链路监控、性能指标告警
Q: 如何处理系统的性能突发问题?
答题要点:
- 快速定位:利用监控和日志快速定位问题
- 应急处理:降级、限流、扩容等应急措施
- 根因分析:深入分析问题根本原因
- 优化改进:制定长期优化方案
- 预防机制:建立预防和预警机制
总结
性能优化面试重点:
- 分析方法:系统化的性能分析方法论
- JVM调优:内存管理、GC优化、参数配置
- 代码优化:算法优化、资源管理、并发处理
- 架构设计:缓存策略、负载均衡、分布式优化
- 监控体系:指标收集、性能监控、告警机制
建议结合实际项目中的性能优化经验,能够描述具体的问题场景、分析过程和优化效果。