1.介绍
大量访问一个不存在的值,最终造成大量请求至mysql,导致mysql压力倍增。
2.解决方案
- 使用布隆表达式
- 如果查询不到,默认使用一个空的数据,比如说空的productInfo的json串,存于redis和ehcache中。
3. 实现
这里介绍第二种方案,即将空值存在缓存中。
3.1 思路
- 当redis和ehcache中,找不到商品时,此时会查询mysql
- mysql也查询不到此商品,立即返回一个空的商品
- 将空的商品数据推到重建缓存任务中,以便redis和ehcache增加此空的商品
- 下次访问时,就可以从redis或ehcache找到此空的商品,不在查询mysql了
3.2 代码
public class GetProductInfoCommand extends HystrixCommand<ProductInfo> {
private Long productId;
public GetProductInfoCommand(Long productId) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ProductService"))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(10)
.withMaximumSize(30)
.withAllowMaximumSizeToDivergeFromCoreSize(true)
.withKeepAliveTimeMinutes(1)
.withMaxQueueSize(50)
.withQueueSizeRejectionThreshold(100))
);
this.productId = productId;
}
@Override
protected ProductInfo run() throws Exception {
// 发送http或rpc接口调用,去调用商品服务的接口
...
if (resultCode == 201){ //假如201代表数据不存在,则返回空值
ProductInfo productInfo = new ProductInfo();
productInfo.setId(productId);
return productInfo;
}
else{
return JSONObject.parseObject(productInfoJSON, ProductInfo.class);
}
}
}
@Override
protected ProductInfo getFallback() {
...
}
}
@RequestMapping("/getProductInfo")
@ResponseBody
public ProductInfo getProductInfo(Long productId) {
ProductInfo productInfo = null;
productInfo = cacheService.getProductInfoFromReidsCache(productId);
if(productInfo != null) {
System.out.println("=================从redis中获取缓存,商品信息=" + productInfo);
}
if(productInfo == null) {
productInfo = cacheService.getProductInfoFromLocalCache(productId);
if(productInfo != null) {
System.out.println("=================从ehcache中获取缓存,商品信息=" + productInfo);
}
}
if(productInfo == null) {
GetProductInfoCommand command = new GetProductInfoCommand(productId);
productInfo = command.execute();
// 即使返回空值,也会将数据推送到一个内存队列中
RebuildCacheQueue rebuildCacheQueue = RebuildCacheQueue.getInstance();
rebuildCacheQueue.putProductInfo(productInfo);
}
return productInfo;
}