图8 缓存空对象
提示:为了减少Redis对大量空对象的缓存,可以适当减少空对象的过期时间。
(3)建立数据标识仓库。将MySQL中的所有数据的name值都映射成hash值,例如可以将“商品表”中的商品名“iphone8”映射成MD5计算出来的hash值b2dd48ff3e52d0796675693d08fb192e,然后再将全部name的hash值放入Redis中,从而构建出一个“数据库中所有可查数据的hash仓库”。之后,每次在查询MySQL之前都会先查询这个hash仓库,如果要查询数据的hash值存在于仓库中,再进入MySQL做真实的查询,如果不存在则直接返回。
需要注意的是,由于不同数据的hash值在概率上时可能相同的,因此可能会漏掉对个别数据的拦截,如图9中的“B”。
图9 不同数据的Hash值相同而造成的问题
2.缓存雪崩
除了缓存穿透以外,在使用缓存时还需要考虑缓存雪崩的情况。缓存雪崩是指由于某种原因造成Redis突然失效,从而造成MySQL瞬间压力骤增,进而严重影响MySQL性能甚至造成MySQL服务宕机。以下是造成缓存雪崩的两个常见原因:
(1)Redis重启;
(2)Redis中的大量缓存对象都设置了相同的过期时间。
为了避免缓存雪崩的发生,可参考使用以下解决方案:
(1)搭建Redis集群,保证高可用;
(2)避免大量缓存对象的key集中失效,尽力让过期时间分配均匀一些,例如,可以给各个缓存的过期时间乘一个随机数;
(3)通过队列、锁机制等控制并发访问MySQL的线程数。