38b375dc77f57101b2835f8a8741a855.png

作者|小芸君

你好,我是小芸君。

Redis相信大家都不陌生,它的诞生开始是为了解决一个实际性问题:在一台小型虚拟机上面处理大量写入负载。

大致的业务场景就是有多个独立运行的网站会连续不断地向虚拟机服务器发送页面访问记录,服务器将每个网站一定数量的最新的页面访问记录保存下来,并实时地展示给用户。

当最大负载达到每秒数千条时,虚拟机服务器就撑不住了,无论使用哪种关系型数据库进行优化都达不到理想效果。

于是Redis就诞生了。

背景

从上面的例子我们知道在redis出现之前,数据库是我们所有的希望。以MySQL为例,它是国内诸多互联网公司的选择。近几年互联网发展迅速,数据库容纳的数据越来越多,用户请求也随之暴涨,而每次请求都是一次对数据库的读和写操作。

尤其是到了双十一、双十二这样的线上购物狂欢节,都是数据库的苦难日。


实际上,绝大多数的用户请求都是读操作,并且经常查询的都是重复的东西,这其中浪费了很多时间花费在数据I/O上。所以我们能不能给数据库加一个缓存呢?

当应用程序从数据库查询到数据后,在redis中缓存一下。下次再需要的时候,先从redis这取,就不需要再查数据库了。

由于redis把数据记录在内存中,不用去执行慢如蜗牛的I/O操作,节省了很多时间。

就是这小小的一点改变,数据库的负担就减轻了不少,随着程序的不断运行,缓存的数据越来越多,挡住的请求也越来越多,网络性能也得到很大提升。

但是又有一个问题,无止境地缓存下去,服务器的内存资源迟早要完,怎么办?

54e9436d036230cf77dc644663389ccb.png

缓存过期和缓存淘汰

缓存的数据都在内存中,就算是在服务器上,内存的空间资源也是很有限的,不可能无节制的存下去,不然服务器迟早崩掉。

给缓存内容加上一个超时时间。不得不说这是一个好点子,超期的缓存就删除掉,这样就可以及时腾出空间了。

知道要删除哪些缓存内容了,那到底要什么时候去删除呢?最简单的做法就是定期删除。默认100ms删除一次,1秒就可以执行10次。

redis并不是一下子删除所有的,大量缓存数据扫描一次需要花费很长一段时间,这在实际生产环境中是不允许的。redis采用了随机算法,选择一部分数据去删除掉,这样就能立马缓解内存压力了。

但是,随机算法存在一定缺陷。在这样的缓存淘汰机制下,有些运气好的键值对一直未被扫描到,每次都幸运逃脱。针对这种情况,redis又该怎么解决呢?

惰性删除。对于已经超期的缓存键值,如果遇到了查询这些键值的请求,redis会立即删除。但是这是被动式触发的,不查询就不会发生。可见,这并不是最终的解决方案。

redis对于内存不足的问题提供了8种策略:

  • noeviction:返回错误,不会删除任何键值
  • allkeys-lru:使用LRU算法删除最近最少使用的键值
  • volatile-lru:使用LRU算法从设置了过期时间的键集合中删除最近最少使用的键值
  • allkeys-random:从所有key随机删除
  • volatile-random:从设置了过期时间的键的集合中随机删除
  • volatile-ttl:从设置了过期时间的键中删除剩余时间最短的键
  • volatile-lfu:从配置了过期时间的键中删除使用频率最少的键
  • allkeys-lfu:从所有键中删除使用频率最少的键

我们可以结合业务场景选择合适的策略使用。

f980fe853a996695a6b8fcd70c8b7dd7.png

缓存穿透和布隆过滤器

想一想在开发中你有没有遇到这样的情况,当查询某条数据的时候,数据库不存在查询的记录,于是数据库做了一次无用功。由于数据不存在,所以导致redis也没法缓存。不仅如此,下次同样的请求来了,还是一样要去查数据库,这样的话redis作用就没有发挥作用了。

我们把上述这种现象叫做缓存穿透。

那能不能想个办法把明明没有结果的请求拦截下来呢?

答案是肯定的,布隆过滤器。布隆过滤器擅长从超大数据集中,快速确定所要查找的数据存不存在,如果它告诉你查找的数据不存在,那一定是不存在。

这样缓存穿透的问题就可以得到解决了。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐