使用缓存一些常见的套路问题。html
缓存穿透前端
在缓存设计中,查询缓存 -> key不存在 -> 回源DB -> 更新缓存,这是一个典型的方案。web
缓存穿透是指查询一个必定不存在的Key,因为缓存层不存在,将致使这个不存在的数据每次请求都要到存储层去查询,直接对DB形成影响。在恶意攻击和失败回调中可能会出现这种状况。shell
1.对空对象进行缓存。对查询结果为空的状况也进行缓存,如当此查询结果为空,设置Key对应对象为NULL,缓存时间设置短一点,存储层中有数据后及时更新。数据库
2.对全部可能查询的参数Key以hash形式存储,在控制层先进行校验,不符合则丢弃。最多见的是采用布隆过滤器,将全部可能存在的数据哈希到一个足够大的bitmap中,一个必定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。比较适合命中不高,可是更新不频繁的数据。后端
缓存失效缓存
1.能够分析用户行为,尽可能让失效时间点均匀分布。针对失效时间相同的key,在设置失效时间时不设置固定的时间,而在原有基础上加上一个随机的值,好比1分钟-5分钟,这样就能够有效分散开缓存失效的时间。安全
2.考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。并发
缓存并发分布式
有时候若是网站并发访问高,一个缓存若是失效,可能出现多个进程同时查询DB,同时设置缓存的状况,若是并发确实很大,这也可能形成DB压力过大。
1.添加分布式锁,在缓存更新或者过时的状况下,先尝试获取到锁,当更新或者从数据库获取完成后再释放锁,其余的请求只须要牺牲必定的等待时间,便可直接从缓存中继续获取数据。
2.按期从DB里查询数据,再刷到缓存里面,确保缓存里面的数据一直能够读到。
缓存雪崩
因为缓存扛了大量的请求,有效保护了数据库的安全。可是当缓存雪崩,所用请求就会瞬间所有打到DB上,可能会致使数据库崩溃。
1.保证缓存服务的高可用性,当一个实例挂掉的时候,请求也能够转移到集群的其余实例上。缓存失效时的雪崩效应对底层系统的冲击很是大,这时候可使用双缓存机制,在工做缓存以外另外维护一层灾备缓存。
2.使用降级策略,当缓存服务出现问题时,能够暂时对用户展现一份固定的数据,避免系统的崩溃,等待缓存服务的恢复。前端也应该有此机制,好比当后端接口返回非正常数据时,将以前保存的旧数据固定展现给用户,避免页面崩溃的问题。
缓存数据的淘汰
缓存淘汰的策略有两种:
1.定时去清理过时的缓存
2.当有用户请求过来时,再判断这个请求所用到的缓存是否过时,过时的话就去底层系统获得新数据并更新缓存
二者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂,具体用哪一种方案,根据本身的应用场景来权衡。
更新缓存仍是淘汰缓存
什么是更新缓存:数据不但写入数据库,还会写入缓存
什么是淘汰缓存:数据只会写入数据库,不会写入缓存,只会把数据淘汰掉
更新缓存的优势:缓存不会增长一次miss,命中率高
淘汰缓存的优势:简单
先操做数据库仍是先操做缓存
假设先写数据库,再淘汰缓存:第一步写数据库操做成功,第二步淘汰缓存失败,则会出现DB中是新数据,Cache中是旧数据,数据不一致。
假设先淘汰缓存,再写数据库:第一步淘汰缓存成功,第二步写数据库失败,则只会引起一次Cache miss。
因此结论是:先淘汰缓存,再写数据库
参考: