性能观与指标
先定义目标(P99 延迟、QPS、错误率),再测量定位瓶颈,最后优化。过早优化是万恶之源,先有数据再动手。
| 指标 | 含义 |
|---|---|
| RT / P99 | 响应时间,P99 表示 99% 请求低于该值 |
| QPS / TPS | 每秒请求/事务数 |
| 错误率 | 失败请求占比 |
| GC 停顿 | 垃圾回收导致的暂停时间 |
JVM 调优
设定合理堆大小与 GC;用 GC 日志、JFR(Java Flight Recorder)定位停顿来源。大堆低延迟考虑 ZGC。
java -Xms2g -Xmx2g -XX:+UseG1GC \
-XX:+FlightRecorder -XX:StartFlightRecording=duration=60s \
-jar app.jarJava Flight Recorder 开销极低,可长期开启采集方法、锁、GC 等剖面,是生产排查利器。
异步处理
耗时操作(发邮件、调用外部、重计算)用 @Async 或消息队列异步化,快速返回响应,提升吞吐与体验。
@Async
public CompletableFuture<Void> sendEmail(Order o) {
mailClient.send(o);
return CompletableFuture.completedFuture(null);
}默认 @Async 用 SimpleAsyncTaskExecutor(每次新建线程)。务必自定义线程池,否则高并发下资源失控。
缓存策略
本地缓存(Caffeine)适合单机热点;分布式缓存(Redis)保证多实例一致。注意失效、穿透、雪崩与一致性。
@Cacheable(value = "user", key = "#id")
public User findById(Long id) { return repo.findById(id); }
// 更新时 @CacheEvict 失效,避免脏读穿透(查不存在的 key)→ 空值缓存/布隆;雪崩(同时失效)→ 加随机 TTL;击穿(热点失效)→ 互斥重建。
数据库性能
加合适索引、避免 N+1、用批量写入、读写分离。慢查询是后端最常见的性能杀手。
-- 为高频查询条件建复合索引
CREATE INDEX idx_orders_status_created ON orders(status, created_at DESC);Docker 部署
用多阶段构建得到精简镜像,非 root 运行,合理设置 JVM 容器感知参数与内存上限。
FROM maven:17-eclipse-temurin AS build
WORKDIR /app
COPY . .
RUN mvn -B package -DskipTests
FROM eclipse-temurin:17-jre
COPY --from=build /app/target/*.jar app.jar
USER 1000
ENTRYPOINT ["java", "-jar", "app.jar"]可观测性与灰度
三大支柱:日志(结构化)、指标(Micrometer/Prometheus)、链路追踪(OpenTelemetry)。灰度发布降低上线风险。
@Timed(value = "order.create", description = "下单耗时")
public Order create(CreateOrderCmd cmd) { return repo.save(toEntity(cmd)); }Spring Boot 默认监听 SIGTERM 完成在途请求再退出。K8s 配合 readiness/liveness 探针实现平滑滚动。
常见陷阱与 FAQ
Java 10+ 默认感知容器限制。设 -XX:MaxRAMPercentage=75.0 让堆按比例占容器内存,避免超用被 kill。
写操作采用"先更新 DB,再删缓存"(Cache-Aside),并给缓存加 TTL 兜底;极端一致用 binlog 订阅(如 Canal)同步。
常见根因:数据库连接池太小、同步阻塞外部调用、锁竞争、GC 频繁。用 APM/火焰图逐层定位,别猜。