缓存中常见的一些问题

整理了一些缓存相关的问题

术语

  • 命中

根据百度百科的解释,终端用户访问加速节点时,如果该节点有缓存住了要被访问的数据时就叫做命中,如果没有的话需要回原服务器取,就是没有命中。取数据的过程与用户访问是同步进行的,所以即使是重新取的新数据,用户也不会感觉到有延时。 命中率=命中数/(命中数+没有命中数), 缓存命中率是判断加速效果好坏的重要因素之一。简单来说,就是先去读取缓存,读取到了就是命中了。

  • 过期

过期有两种,一种是时间过期,一种是淘汰过期。

时间过期好说,就是时间到了,被消除了。

所谓淘汰过期,只是在某些缓存服务器中对缓存内容大小进行了限制,当缓存接近于设置大笑时,会根据缓存服务的缓存策略进行操作,例如redis含有的一些淘汰策略:

  • voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  • volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
  • allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
  • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
  • no-enviction(驱逐):禁止驱逐数据

缓存失效

也叫做缓存雪崩。某些项目可能会在配置项中写一个固定的缓存过期时间,在并发比较高的情况下,可能会同时产生一些一些缓存键,这些缓存的的过期时候由于都是直接调取配置项,所以过期时间基本一致,这样就会导致在某一时间这些缓存同时失效,请求全部到DB,DB可能会压力过重。

解决方法:在缓存的时候给过期时间加上一个随机值,这样就会大幅度的减少缓存在同一时间过期。

缓存一致性

当数据时效性要求很高时,并且存在读与写场景都存在的并发场景,如何保证缓存的正确性?在写操作中,是先删除缓存还是操作完再重新覆盖缓存?如果在集群中,又如何保证副本缓存的同步?关于缓存一致性,内容稍微有点多,将在后期中详细叙述。

缓存并发

当某一个缓存失效,通常的操作顺序都是先查找数据,再进行操作,然后更新DB与cache。但在高并发的情况下,一个缓存过期会导致多个进程同时查找DB,如果缓存更新,对某个key有大量的并发请求,此时请求获得的结果可能是更新之前也可能是更新之后,从而会导致“一致性”的问题。

解决办法:由于缓存并发问题一般发生在查询期间,所以当缓存失效的时候,对key加锁。其他请求判断到请求锁存在,就等待,直到重新缓存完毕并解锁。

缓存击穿

指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。当在流量较大时,出现这样的情况,一直请求DB,很容易导致服务挂掉。

解决办法:无论是否查询到结果,都写入缓存,但是查询结果不存在的时候,设置过期时间稍短一点。


笔者认为,在缓存失效前重新写入缓存能有效的避免一些缓存问题,具体怎么在缓存失效前重新写入,方法有很多种,这里就不讨论了。

以上内容同步更新到了订阅号【后端与web安全】(backend_websecurity)中,欢迎关注,不定期更新内容。转载请以链接方式注明出处。

猜你喜欢

转载自my.oschina.net/OSrainn/blog/1819281