如何保证查询节目时避免缓存穿透?
阅读过上面章节的小伙伴应该知道了 缓存穿透是指查询的数据在缓存和数据库中都不存在,导致每次查询这条数据都会穿透过缓存,直接去查询数据库,相当于没有缓存一样。
而这种问题在查询节目详情时同样会存在,比如说某个黑客调用节目详情接口时,就会传入一个不存在的节目id,先查一遍缓存,缓存不存在则再去查询数据库,结果数据库也不存在,当并发高时,就会对数据库造成很大的压力
在注册用户功能中,我们结合了验证码和布隆过滤器的方案来解决缓存穿透,那么在查询节目详情功能中,应该用什么方案呢?我们从业务特点来入手:
正常用户查询节目详情时,都是事先查询了节目主页或者节目列表后,再来查询节目详情的,也就是说节目id时肯定存在缓存或者数据库中的,如果是缓存和数据库都不存在的节目id说明此id就是不正常的,服务收到了此id就应该直接拒绝,不再执行后续的流程
注意这里的关键点,如果判断节目id不存在,则说明此节目id肯定是不正常的,这是不是和布隆过滤器的判断特点非常的贴合!布隆过滤器的特点就是如果判断某个元素不存在,那么说明此元素一定就不存在!关于布隆过滤器的详细讲解,小伙伴可跳转下面章节进行学习、
配置
bloom-filter:
name: program-detail-bloom-filter
expectedInsertions: 1000
falseProbability: 0.01
控制层
@ApiOperation(value = "查询详情(根据id)")
@PostMapping(value = "/detail")
public ApiResponse<ProgramVo> getDetail(@Valid @RequestBody ProgramGetDto programGetDto) {
return ApiResponse.ok(programService.detail(programGetDto));
}
public ProgramVo detail(ProgramGetDto programGetDto) {
//查询节目id是否存在布隆过滤器中
compositeContainer.execute(CompositeCheckType.PROGRAM_DETAIL_CHECK.getValue(),programGetDto);
//验证通过执行节目查询
return getDetail(programGetDto);
}
验证的具体逻辑
@Component
public class ProgramBloomFilterCheckHandler extends AbstractComposite<ProgramGetDto> {
@Autowired
private BloomFilterHandler bloomFilterHandler;
@Override
protected void execute(final ProgramGetDto param) {
boolean contains = bloomFilterHandler.contains(String.valueOf(param.getId()));
if (!contains) {
throw new DaMaiFrameException(BaseCode.PROGRAM_NOT_EXIST);
}
}
@Override
public String type() {
return CompositeCheckType.PROGRAM_DETAIL_CHECK.getValue();
}
@Override
public Integer executeParentOrder() {
return 0;
}
@Override
public Integer executeTier() {
return 1;
}
@Override
public Integer executeOrder() {
return 1;
}
}
可以看到这里是直接通过布隆过滤器来判断节目id是否存在的,但什么时候放进去的呢?
其实这里是在节目启动初始化的时候放入的,从数据库中查询出所有节目id然后放入布隆过滤器中,这么做也是为了方便小伙伴学习,节目启动后可以直接的来学习了。
而实际的生产环境肯定不会这么做,节目的数据上千万上亿,直接全部查询不现实,肯定是通过运营人员,添加好节目后,再添加到布隆过滤器中的,而这里的初始化流程同样值得小伙伴好好的学习,这里针对Spring的初始化不同策略进行封装成了组件,使用了抽象思想和设计模式,
- 点赞
- 收藏
- 关注作者
评论(0)