ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

redis--006

redis--006 1. 缓存穿透现象查询缓存、数据库都不存在的数据大量恶意请求直接打向数据库压垮 DB。例传入不存在的商铺 idRedis 查不到每次都去访问数据库。解决方案缓存空值缓存 null查询数据库不存在时把null存入 Redis 并设置短过期时间后续相同请求直接返回空不再访问数据库。优点简单直接缺点会占用少量 Redis 内存。布隆过滤器把所有合法数据 ID 预先存入布隆过滤器请求过来先过过滤器不合法直接拦截不去查 Redis 与 DB。适合海量数据场景。参数校验做 ID 格式、范围校验拦截非法参数避免 id 被猜测遍历。业务流程缓存空值方案根据 id 查询 Redis 缓存缓存命中判断是否为空值空值直接返回非空返回业务数据缓存未命中查询数据库数据库存在写入真实数据到 Redis返回数据数据库不存在写入 null 空值到 Redis结束2. 缓存击穿热点 Key 问题现象某一个热点高并发的 key 过期失效大量并发请求同时打到数据库瞬间冲击 DB。区别雪崩击穿是单个热点 key 失效雪崩是大量 key 集体失效。两种解决方案对比表格方案优点缺点互斥锁分布式锁无额外内存数据一致性好实现简单线程等待性能下降存在死锁风险逻辑过期线程不用等待并发性能高不保证强一致性消耗内存业务实现复杂①互斥锁流程请求查询 Redis 缓存命中直接返回缓存未命中尝试获取分布式互斥锁获取锁失败休眠重试再次查询缓存获取锁成功查询数据库重建缓存写入 Redis释放锁返回数据核心同一时刻只允许一个线程去数据库重建缓存其他线程等待重试。②逻辑过期不给 key 设置真实 TTL 过期在 value 内部存一个逻辑过期时间线程发现逻辑时间过期开启异步线程更新缓存旧数据直接返回给用户不阻塞请求。Override public Result queryById(Long id) { //缓存穿透 //解决击穿 Shop shop queryWithMutex(id); //返回 if (shop null) { return Result.fail(店铺不存在); } return Result.ok(shop); } public Shop queryWithMutex(Long id) { String LockKey null; Shop byId null; try { //查ID String shopJson stringRedisTemplate.opsForValue().get(cache:shop id); //存在返回不存在查数据库 if(StrUtil.isNotBlank(shopJson)) { Shop shop JSONUtil.toBean(shopJson, Shop.class); return shop; } if(shopJson ! null) { return null; } //实现缓存重建 LockKey lock:shop id; boolean isLock tryLock(LockKey); if (!isLock) { Thread.sleep(50); return queryWithMutex(id); } byId getById(id); //数据库结果 if (byId null) { //将空值写入redis stringRedisTemplate.opsForValue().set(cache:shop id,,10, TimeUnit.MINUTES); return null; } stringRedisTemplate.opsForValue().set(cache:shop id,JSONUtil.toJsonStr(byId),30, TimeUnit.MINUTES); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { unlock(LockKey); } return byId; } public Shop queryWithPassThrough(Long id) { //查ID String shopJson stringRedisTemplate.opsForValue().get(cache:shop id); //存在返回不存在查数据库 if(StrUtil.isNotBlank(shopJson)) { Shop shop JSONUtil.toBean(shopJson, Shop.class); return shop; } if(shopJson ! null) { return null; } Shop byId getById(id); //数据库结果 if (byId null) { //将空值写入redis stringRedisTemplate.opsForValue().set(cache:shop id,,10, TimeUnit.MINUTES); return null; } stringRedisTemplate.opsForValue().set(cache:shop id,JSONUtil.toJsonStr(byId),30, TimeUnit.MINUTES); return byId; } private boolean tryLock(String key) { Boolean flag stringRedisTemplate.opsForValue().setIfAbsent(key, 1,10,TimeUnit.MINUTES); return BooleanUtil.isTrue(flag); } private void unlock(String key) { stringRedisTemplate.delete(key); }3. 缓存雪崩现象大量 key 同一时间集体过期或者 Redis 整体宕机大量请求绕过缓存全部涌向数据库数据库压力雪崩。解决方案过期时间添加随机值TTL 加上随机偏移打散 key 失效时间避免集体过期。Redis 集群高可用主从、哨兵、集群避免 Redis 宕机。限流 降级网关层限流服务降级保护数据库。多级缓存本地 Caffeine 缓存 Redis 多级缓存Redis 故障可以兜底。三者对比总结面试速记表格问题诱因核心特点缓存穿透查询根本不存在的数据缓存、数据库都没有该数据缓存击穿单个热点 key 过期一个热点 key 失效并发打 DB缓存雪崩大量 key 同时过期 / Redis 宕机大批量 key 失效大规模压垮数据库面试常考区分点穿透查不存在的数据击穿一个热点 key 过期雪崩大批量 key 失效 /redis 挂掉。
返回列表