Redis相关概念以及缓存预热、缓存雪崩、缓存击穿、缓存穿透解决方案

单线程的Redis为什么这么块
  1. 纯内存操作
  2. 单线程操作,避免了频繁的上下文切换
  3. 采用了非阻塞I/O多路复用机制
Redis的数据类型,以及每种数据类型的使用场景
  1. String
  2. hash
  3. list
  4. set
  5. sorted set:比set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。
Redis删除策略
  1. 定时删除

    • 创建一个定时器,当key设置过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作
    • 优点:节约内存,到时就删除,快速释放掉不必要的内存占用
    • 缺点:CPU压力很大,无论CPU此时负载多高,均占用CPU,会影响redis服务器响应时间和指令吞吐量
    • 总结:用处理器性能换取存储空间
  2. 惰性删除

    • 数据到达过期时间,不做处理,等下次访问该数据
      • 如果未过期,返回数据
      • 发现已过期,删除,返回不存在
    • 优点:节约CPU性能,发现必须删除的时候才删除
    • 缺点:内存压力大,出现长期占用内存的数据
    • 总结:用存储空间换取处理器性能
  3. 定期删除

    • Redis相关概念以及缓存预热、缓存雪崩、缓存击穿、缓存穿透解决方案
    • 周期性轮询redis库中时效性数据,采用随机抽取的策略,通过过期数据占比的方式删除
  4. 删除策略对比
    Redis相关概念以及缓存预热、缓存雪崩、缓存击穿、缓存穿透解决方案

逐出算法
1. 新数据进入检测

当新数据进入redis时,如果内存不足怎么办?

  • Redis使用内存存储数据,在执行每一个命令前,会调用freeMemoryIfNeeded()检测内存是否充足。如果内存不满足新加入数据的最低存储要求,redis要临时删除一些数据为当前指令清理存储空间。清理数据的策略称为逐出算法。
  • 注意:逐出数据的过程不是100%能够清理出足够的可使用的内存空间,如果不成功则反复执行。当对所有数据尝试完毕后,如果不能达到内存清理的要求,将出现错误信息。
2. 影响数据逐出的相关配置
  • 最大可使用内存

maxmenory
占用物理内存的比例,默认为0,表示不限制。生产环境中根据需求设定,通常设置在50%以上。

  • 每次选取待删除数据的个数

maxmemory-samples
选取数据时并不会全库扫描,导致严重的性能消耗,降低读写性能。因此采用随机获取数据的方式作为待检测删除数据。

  • 删除策略

maxmemory-policy
达到最大内存后,对被挑选出来的数据进行删除的策略。

3. 删除策略
  1. volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  2. volatile-lfu:从已设置过期时间的数据集挑选使用频率最低的数据淘汰。
  3. volatile-ttl :从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  4. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
  5. allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
  6. allkeys-lfu:从数据集中挑选使用频率最低的数据淘汰。
  7. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
  8. no-enviction(驱逐):禁止驱逐数据,新写入操作会报错
Redis为什么是单线程的

因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。Redis利用队列技术将并发访问变成串行访问。

缓存预热

缓存预热就是系统启动前,提前将相关的缓存数据直接加载到缓存系统,这样可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题。用户直接查询事先被预热的缓存数据。

缓存雪崩

在一个较短的时间内,缓存中较多的key集中过期,所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。
解决办法

  1. 构建多级缓存架构
  2. 数据有限策略调正,也就是把缓存失效时间分散开
缓存击穿

Redis中某个key过期,该key访问量巨大。多个数据请求读取Redis缓存均为命中,发起了大量对数据库同一个数据的访问,导致对数据库服务器造成压力。
解决办法

  1. 监测热点数据,设置热点数据永不过期。
  2. 加互斥锁
缓存穿透

缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空。
解决办法

  1. 缓存null:对查询结果为null的数据进行缓存
  2. 布隆过滤器:将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。