缓存技术经典问题总结



    目前大型系统都会使用分布式缓存技术提高性能,常用的如memcached和redis,实际上redis已渐成主流。缓存技术的实际使用过程中会遇到一些问题或现象,有一些坑。本文对一些经典问题进行了总结。

1.缓存穿透

    一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对后端系统造成很大的压力。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。

解决方案:
1)对查询结果为空的情况,我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟,或者该key对应的数据insert了之后清理缓存。
2)采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。

2.缓存雪崩

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。缓存中缺失的数据只能去数据库中查询,短时间造成数据库压力过大而崩溃。

解决方案:
不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

3.缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),在缓存失效时可能突然有特别多并发请求,同时读缓存没读到数据,又同时去数据库读取数据,引起数据库压力瞬间增大,造成过大压力。

缓存击穿与缓存穿透的区别是,它是存在的key,只是在缓存过期的一刻,同时有大量的请求,这些请求因为读不到缓存重复去读DB,造成瞬时DB请求压力骤增。

缓存击穿与缓存雪崩的区别在于,缓存击穿针对某一key缓存突然失效又遇到了大量请求的情况,而缓存雪崩则是描述很多key同时到期的情况。

解决方案:如果不能设置数据永不过期,可以在代码中通过互斥锁来解决。示例代码如下:

说明:如果缓存中有数据,直接就返回结果了。缓存中没有数据,就获取锁并从数据库去取数据,没释放锁之前,其它并发的请求会等待一定时间,再重新去缓存取数据。这样就防止都去数据库重复读取数据,重复往缓存中更新数据情况出现。

4.缓存无底洞现象

这个问题最早是由Facebook的工作人员在使用memcached是发现的。2010年Facebook已达到3000个memcached节点,储存数千G的缓存。当时他们发现一个问题,memcached的连接效率下降了,于是添加memcached节点,但添加完之后,并没有好转,称为“无底洞”现象。
造成这种现象的原因是,由于缓存系统通常采用hash函数将key映射到不同的实例,key的分布与业务无关,并且希望尽量分布均匀,但是由于数据量、访问量的需求,需要使用分布式后,批量操作比如批量获取多个key(例如redis的mget操作),通常需要从不同实例获取key值,相比于单机批量操作只涉及到一次网络操作,分布式批量操作会涉及到多次网络io。
以会员信息为例:
{
 ‘User-133-age’  22
 ‘user-133-height’ 170
 ‘user-89-age’ 60
 ‘user-89-height’ 182
}
如果开始只有两台服务器,该信息可能分布在两台机器上,当请求某会员信息时,需要连接两台服务器。如果增加两台,变成4台,由于key的分布与业务无关,且希望尽量分布均匀,该信息可能分布在4台机器上,当请求信息时,需要连接4台服务器。节点越多,要连接的节点也越多,对连接数,并没有随着节点的增多而降低,问题出现。

结论:
用一句通俗的话总结:更多的机器不代表更多的性能,所谓“无底洞”就是说投入越多不一定产出越多。分布式又是不可以避免的,因为我们的网站访问量和数据量越来越大,一个实例根本坑不住,所以如何高效的在分布式缓存和存储批量获取数据是一个难点。

解决方案:
1)对于memcached,redis,这种kv存储,key的设计,可以参考关系数据库中表与列的设计。比如:user表下有age列,name列,身高列,对应的key,可以用user:133:age=23,user:133:name=’lisi’,user:133:height=168;把某一组key,按其共同前缀来分布。在用分布式算法求其节点时,应该以’user-133’来计算,而不是以user-133-age/name/height来计算,这样3个关于个人信息的key,都落在同一个节点,访问时只需连接一个节点。
2)memcached没有数据结构,更没有复杂数据结构,只能用字符串存储,但目前的主流是redis,可以通过复杂数据结构,比如map类型来存储会员信息这样的对象,也就不存在这类问题了。

值得注意的是,缓存失效后,数据库压力骤增,数据库抗压能力本就不如缓存,极容易被击穿、压垮,重启后因为缓存是空的,所以可能再次被压垮,但被压垮之前会在缓存服务器积累了一部分缓存。数据库压垮后只能再次重启,可能会再次被压垮,压垮会再积累了一部分缓存。可能这样周而复始来回重启了还几次,直到缓存积累的足够多,足以抵抗访问的压力。

人生也许也是这样,一再,再再,不断迭代,不断重启,只是对于那些困境中的人来说,需要足够的毅力和能力,才能再次站起来,当然也还需要一些运气。但人与机器不同,如果实在站不起来怎么办,那就怎么舒服怎么呆着,一般来说,你没有义务,必须站起来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值