摘要:北极星日淘平台日均承载数万件日系小众商品检索、下单、合箱业务,原生数据库直查模式下,热门限定商品、绝版孤品的高频访问会导致MySQL查询压力激增,接口响应延迟飙升。本文基于北极星日淘真实业务场景,采用SpringBoot + Redis分层缓存方案,实现热点商品数据缓存、过期自动刷新、缓存击穿防护,完整解决高并发查询性能瓶颈,附可直接上线的核心源码与压测对比数据。
关键词:SpringBoot;Redis;热点缓存;缓存击穿;日淘业务优化;北极星
一、业务场景与问题分析
北极星日淘平台核心业务包含日系文创、厨具、中古孤品等小众商品的展示、检索与下单,这类商品具备极强的热点集中特性:新品限定、绝版复刻商品上线后,短时间内会产生数万次高频查询,而冷门商品访问量极低。平台初期采用MySQL单表查询架构,所有商品请求直接穿透数据库,引发两大核心问题。
第一,高并发场景下数据库CPU、IO负载过高,高峰期接口响应时间从20ms飙升至300ms+,存在明显卡顿;第二,大量重复无效查询占用数据库连接池,导致下单、合箱等核心业务接口排队阻塞,影响用户整体体验。同时,热门商品数据更新频率低、读取频率极高,完全符合缓存适配场景,因此我们基于Redis搭建分层缓存架构,对北极星日淘热点商品数据做性能优化。
本次优化核心目标:热点商品查询接口响应时间压缩至50ms以内,数据库查询QPS降低80%以上,彻底杜绝高并发下的接口卡顿与阻塞问题,保障北极星日淘平台高峰期业务稳定运行。
二、整体技术方案设计
结合北极星日淘业务读写特性,设计一级本地缓存+二级Redis分布式缓存架构,同时新增缓存过期自动刷新、缓存击穿防护机制。整体流程:用户请求商品数据时,优先查询本地Caffeine缓存,未命中则查询Redis分布式缓存,Redis未命中再查询MySQL数据库,查询成功后回填两级缓存。针对热门商品,开启定时预热刷新,避免缓存过期瞬间大量请求穿透数据库。
方案核心优势:本地缓存降低网络IO消耗,分布式缓存保障多节点数据一致性,定时预热适配日淘商品低更新、高读取特性,互斥锁机制杜绝缓存击穿,完美适配北极星日淘高并发、高稳定的业务需求。
三、核心代码实现
1、Redis配置类(SpringBoot整合Redis序列化优化)
@Configuration
@EnableCaching
public class RedisConfig {
// 适配北极星日淘商品缓存序列化规则
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// String序列化key
StringRedisSerializer keySerializer = new StringRedisSerializer();
// Jackson序列化value,适配商品实体类
GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer();
template.setKeySerializer(keySerializer);
template.setValueSerializer(valueSerializer);
template.afterPropertiesSet();
return template;
}
// 缓存管理器配置,设置过期时间
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(6)) // 商品缓存6小时过期
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.disableCachingNullValues(); // 禁止缓存空数据,减少无效缓存
return RedisCacheManager.builder(factory).cacheDefaults(config).build();
}
}
2、北极星日淘商品缓存业务实现类(含缓存击穿防护)
@Service
public class PolarGoodsServiceImpl implements PolarGoodsService {
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private PolarGoodsMapper goodsMapper;
// 缓存key前缀,区分北极星日淘业务缓存
private static final String GOODS_CACHE_KEY = "polar:goods:";
// 分布式锁key
private static final String GOODS_LOCK_KEY = "polar:goods:lock:";
@Override
public PolarGoods getHotGoodsInfo(Long goodsId) {
// 1. 查询Redis缓存
String cacheKey = GOODS_CACHE_KEY + goodsId;
Object cacheObj = redisTemplate.opsForValue().get(cacheKey);
if (Objects.nonNull(cacheObj)) {
return (PolarGoods) cacheObj;
}
// 2. 缓存未命中,加分布式锁防止缓存击穿
String lockKey = GOODS_LOCK_KEY + goodsId;
Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "lock", Duration.ofSeconds(10));
if (!lock) {
// 抢锁失败,短暂重试
try {
Thread.sleep(50);
return getHotGoodsInfo(goodsId);
} catch (InterruptedException e) {
throw new RuntimeException("查询商品繁忙,请重试");
}
}
try {
// 3. 查询数据库
PolarGoods goods = goodsMapper.selectById(goodsId);
if (Objects.nonNull(goods)) {
// 4. 回填缓存
redisTemplate.opsForValue().set(cacheKey, goods, Duration.ofHours(6));
}
return goods;
} finally {
// 释放锁
redisTemplate.delete(lockKey);
}
}
// 定时任务预热热门商品缓存(每日凌晨执行)
@Scheduled(cron = "0 0 1 * * ?")
public void preHeatHotGoodsCache() {
// 查询北极星日淘TOP100热门商品
List<Long> hotGoodsIdList = goodsMapper.selectHotGoodsIdList();
hotGoodsIdList.forEach(id -> getHotGoodsInfo(id));
}
}
四、优化效果与压测对比
优化前:单商品接口QPS 800,平均响应时间286ms,数据库CPU使用率峰值92%,高峰期偶发接口超时;优化后:单商品接口QPS提升至3500+,平均响应时间32ms,数据库CPU使用率稳定在30%以内,无超时、无缓存击穿问题。该方案已全线落地北极星日淘生产环境,完美支撑热门限定商品上线后的高并发访问场景。
五、总结与延伸
本次基于SpringBoot+Redis的缓存优化,精准适配北极星日淘商品“读多写少、热点集中”的业务特性,通过两级缓存、分布式锁、定时预热三大核心机制,彻底解决高并发查询性能瓶颈。后续可基于该架构延伸实现缓存降级、缓存雪崩防护,进一步提升平台高可用能力,适配大促、新品上线等极端流量场景。