1.缓存架构优化
// 多级缓存实现
@Service
public class MultiLevelCacheService {
@Autowired
private CaffeineCacheManager localCache; // 本地缓存
@Autowired
private RedisTemplate redisTemplate; // 分布式缓存
public Object get(String key) {
// 1. 查本地缓存
Object value = localCache.get(key);
if(value != null) {
return value;
}
// 2. 查分布式缓存
value = redisTemplate.opsForValue().get(key);
if(value != null) {
// 回填本地缓存
localCache.put(key, value);
return value;
}
// 3. 查数据库
value = getFromDB(key);
if(value != null) {
// 更新缓存
redisTemplate.opsForValue().set(key, value);
localCache.put(key, value);
}
return value;
}
// 缓存预热
@PostConstruct
public void warmUp() {
// 加载热点数据到Redis
List<HotKey> hotKeys = getHotKeys();
for(HotKey key : hotKeys) {
String value = getFromDB(key);
redisTemplate.opsForValue().set(key, value);
}
}
}
2. 数据库优化
-- 索引优化
ALTER TABLE red_packet ADD INDEX idx_user_id(user_id);
ALTER TABLE red_packet ADD INDEX idx_status_created(status, created_time);
-- SQL改写示例
-- 优化前
SELECT * FROM red_packet WHERE user_id = 1 ORDER BY created_time DESC;
-- 优化后
SELECT id,amount,status
FROM red_packet FORCE INDEX(idx_user_id)
WHERE user_id = 1
ORDER BY created_time DESC
LIMIT 10;
-- 分库分表
-- 按用户ID分库
database_${user_id % 4}
-- 按时间分表
red_packet_${yyyyMM}
3.JVM调优
# JVM参数优化
-Xms4g -Xmx4g # 堆内存初始和最大值设置一致,避免扩容
-XX:+UseG1GC # 使用G1垃圾收集器
-XX:MaxGCPauseMillis=200 # GC停顿时间目标
-XX:+HeapDumpOnOutOfMemoryError # OOM时dump堆
-XX:+PrintGCDetails # 打印GC详细日志
-XX:+PrintGCDateStamps
4.线程池优化
@Configuration
public class ThreadPoolConfig {
@Bean
public ThreadPoolExecutor businessThreadPool() {
return new ThreadPoolExecutor(
20, // 核心线程数
50, // 最大线程数
60L, // 空闲线程存活时间
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(500), // 工作队列
new ThreadFactoryBuilder()
.setNameFormat("business-thread-%d")
.build(),
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
}
// 线程池监控
@Scheduled(fixedRate = 5000)
public void monitorThreadPool() {
ThreadPoolExecutor executor = businessThreadPool();
log.info("线程池状态: " +
"活跃线程数:{}, " +
"完成任务数:{}, " +
"队列任务数:{}",
executor.getActiveCount(),
executor.getCompletedTaskCount(),
executor.getQueue().size());
}
}
5.网络传输优化
// 1. 使用protobuf压缩传输数据
@Data
@Message
public class RedPacketProto {
@Tag(1)
private Long id;
@Tag(2)
private BigDecimal amount;
@Tag(3)
private Integer status;
}
// 2. HTTP响应GZIP压缩
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public GZipFilter gzipFilter() {
return new GZipFilter();
}
}
// 3. 长连接复用
@Bean
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
factory.setConnectionRequestTimeout(1000);
factory.setConnectTimeout(1000);
factory.setReadTimeout(3000);
// 开启连接池
PoolingHttpClientConnectionManager cm =
new PoolingHttpClientConnectionManager();
cm.setMaxTotal(200);
cm.setDefaultMaxPerRoute(20);
factory.setHttpClient(
HttpClients.custom().setConnectionManager(cm).build()
);
return new RestTemplate(factory);
}
6.接口优化
@RestController
@RequestMapping("/api/red-packet")
public class RedPacketController {
// 1. 接口合并
@GetMapping("/detail")
public Result getDetail(Long packetId) {
// 并行调用多个接口
CompletableFuture<RedPacketInfo> packetFuture =
CompletableFuture.supplyAsync(() ->
getRedPacketInfo(packetId)
);
CompletableFuture<List<GrabRecord>> recordsFuture =
CompletableFuture.supplyAsync(() ->
getGrabRecords(packetId)
);
CompletableFuture<UserInfo> userFuture =
CompletableFuture.supplyAsync(() ->
getUserInfo(packetId)
);
// 等待所有结果返回
CompletableFuture.allOf(
packetFuture,
recordsFuture,
userFuture
).join();
return Result.success(new DetailVO(
packetFuture.get(),
recordsFuture.get(),
userFuture.get()
));
}
// 2. 返回结果优化
@GetMapping("/list")
public Result getList(RedPacketQuery query) {
// 只返回必要字段
return redPacketService.getList(query)
.stream()
.map(packet -> {
RedPacketVO vo = new RedPacketVO();
vo.setId(packet.getId());
vo.setAmount(packet.getAmount());
vo.setStatus(packet.getStatus());
return vo;
})
.collect(Collectors.toList());
}
}
7.系统监控
@Aspect
@Component
public class PerformanceMonitor {
@Around("execution(* com.xx.controller.*.*(..))")
public Object monitor(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
String methodName = pjp.getSignature().getName();
try {
return pjp.proceed();
} finally {
long end = System.currentTimeMillis();
// 记录方法执行时间
Metrics.timer("method.latency")
.tag("method", methodName)
.record(end - start, TimeUnit.MILLISECONDS);
// 记录QPS
Metrics.counter("method.qps")
.tag("method", methodName)
.increment();
}
}
}
8.预防措施
@Configuration
public class RedisConfig {
// 1. 布隆过滤器防缓存穿透
@Bean
public BloomFilter<String> bloomFilter() {
return BloomFilter.create(
Funnels.stringFunnel(Charset.defaultCharset()),
1000000, // 预计元素数量
0.01 // 误判率
);
}
// 2. 缓存雪崩解决
@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
return RedisCacheConfiguration
.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30)) // 统一过期时间
.serializeValuesWith(
RedisSerializationContext
.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer())
);
}
// 3. 热点缓存永不过期
@PostConstruct
public void initHotCache() {
String key = "hot_red_packet";
redisTemplate.opsForValue().set(key, value, -1); // 永不过期
}
}
9.自适应限流
// 基于滑动时间窗口的自适应限流
public class AdaptiveRateLimiter {
// 时间窗口(毫秒)
private long windowTime = 1000;
// 窗口内最大请求数
private long maxRequests = 1000;
// 每个窗口的计数器
private Map<Long, AtomicLong> counters = new ConcurrentHashMap<>();
public boolean tryAcquire() {
long now = System.currentTimeMillis();
long windowStart = now - windowTime;
// 清理过期窗口
counters.entrySet().removeIf(
entry -> entry.getKey() < windowStart
);
// 当前窗口计数器
AtomicLong counter = counters.computeIfAbsent(
now, k -> new AtomicLong()
);
// 获取当前窗口内的请求总数
long totalRequests = counters.values().stream()
.mapToLong(AtomicLong::get)
.sum();
// 根据系统负载动态调整限流阈值
double cpuLoad = getSystemCpuLoad();
long adjustedLimit = (long)(maxRequests * (1 - cpuLoad));
return totalRequests < adjustedLimit &&
counter.incrementAndGet() <= adjustedLimit;
}
}
10.热点数据实时统计
// 使用RingBuffer实现滑动窗口热点统计
public class HotKeyDetector {
// 环形缓冲区
private RingBuffer<HotKeyCounter> ringBuffer;
// 初始化RingBuffer
public HotKeyDetector(int bufferSize) {
this.ringBuffer = RingBuffer.createSingleProducer(
HotKeyCounter::new,
bufferSize,
new YieldingWaitStrategy()
);
// 启动消费者线程
DisruptorConsumer consumer = new DisruptorConsumer();
ringBuffer.addGatingSequences(consumer.getSequence());
EXECUTOR.submit(consumer);
}
// 记录热点key访问
public void record(String key) {
long sequence = ringBuffer.next();
try {
HotKeyCounter counter = ringBuffer.get(sequence);
counter.setKey(key);
counter.incrementCount();
} finally {
ringBuffer.publish(sequence);
}
}
// 消费者处理逻辑
private class DisruptorConsumer implements Runnable {
private Sequence sequence = new Sequence();
@Override
public void run() {
while (true) {
try {
long available = ringBuffer.getCursor();
long current = sequence.get();
for (long i = current + 1; i <= available; i++) {
HotKeyCounter counter = ringBuffer.get(i);
// 更新热点统计
updateHotKey(counter);
sequence.set(i);
}
} catch (Exception e) {
log.error("处理热点统计异常", e);
}
}
}
}
}