redis做缓存(cache)

什么是缓存

缓存(Cache)的核心思路就是把一些常用的数据放到访问速度更快的地方,方便获取。
关于硬件的访问速度来说

CPU寄存器>内存>硬盘>网络

因此常见使用内存作为硬盘的缓存,例如redis。使用硬盘作为网络的缓存,例如浏览器通过http/https从服务器上获取到数据(html,css,js,图片,视频,音频,文字)像这种体积大,又不太会改变的数据,就可以保存到浏览器本地,后续在打开该网页,就不必重新从网络获取上述数据了。
根据“二八原则”,20%的热点数据,能够应对80%的访问场景。因此只需要把这些少量的热点数据缓存起来,就可以应对大多数的场景,从而在整体上有明显的性能提升。

使用redis作为缓存

在网站开发中,我们经常使用mysql来存储数据。mysql虽然功能强大,但是有一个致命的缺点,就是性能不高(进行一次查询操作要消耗很多系统硬件资源)。
:::info
为什么关系型数据库性能不高?

  1. 硬件原因
    1. 数据库把数据存储在硬盘上,硬盘的IO速度不快,尤其是随机访问
    2. 如果查询不能命中索引,就需要进行表的遍历,这就会增加磁盘IO次数
  2. 软件原因
    1. 关系型数据库对于sql的执行会做一系列解析,校验,优化工作
    2. 对于复杂查询,比如联合查询,需要进行笛卡尔积,效率很低
      :::
      因此,如果访问数据库的并发量很高,对于数据库的压力就很大,容易使数据库宕机。
      :::success
      为什么并发量高了就会宕机?
      服务器每次处理一个请求,就需要消耗一定的硬件资源,例如cpu,内存,硬盘,网络带宽。
      而一个服务器的资源是有限的,一个请求消耗一份资源,当把资源耗尽,后续请求就没有资源可用,就无法正确处理,更严重的还会导致服务器程序的代码崩溃。
      :::
      如何让数据库能够承担更大的并发量?
  • 开源:引入更多机器,部署更多数据库,构成数据库集群(主从复制,分库分表)
  • 节流:引入缓存,使用其他方式保存经常访问的热点数据,从而降低直接访问数据库的请求数量

实际开发中两种方案搭配使用

image.png

缓存更新策略

缓存更新策略

定期生成

访问的数据会以日志的形式记录下来,我们可以写个程序(如python,shell脚本代码),针对这些日志进行统计,统计这一天/周/月,每个词出现的频率,在根据频率降序排序,取出前20%的词,就是“热点词”。将这些“热点词”放大redis中

实时生成

如果在redis中查到,就直接返回;如果redis中不存在,就从数据库查,把查到的结果同时写到redis中。经过一段时间“动态平衡”,redis中的key就逐渐变成热点数据了。

内存淘汰机制

不停的写入redis,就会使redis的内存占用越来越多,当达到内存上限,就会触发redis的“内存淘汰机制”。

  1. FIFO(first in first out)先进先出:把缓存中存在时间最久的(先来的数据)淘汰掉
  2. LRU(least recently used)淘汰最久未使用:记录每个key的最近访问时间,把最近访问时间最老的key淘汰掉
  3. LFU(least frequently used)淘汰访问次数最少的:记录每个key最近一段时间的访问次数,把访问次数最少的淘汰掉
  4. Random随机淘汰:随机抽取key删除掉

redis配置文件中内置的淘汰策略

  • volatile-lru 当内存不⾜以容纳新写⼊数据时,从设置了过期时间的key中使⽤LRU算法(最近最少使⽤)进⾏淘汰
  • allkeys-lru 当内存不⾜以容纳新写⼊数据时,从所有key中使⽤LRU算法(最近最少使⽤)进 ⾏淘汰.
  • volatile-lfu4.0版本新增,当内存不⾜以容纳新写⼊数据时,在过设置了过期时间的key中,使⽤LFU算法 进⾏删除key.
  • allkeys-lfu 4.0版本新增,当内存不⾜以容纳新写⼊数据时,从所有key中使⽤LFU算法进⾏淘汰
  • volatile-random 当内存不⾜以容纳新写⼊数据时,从设置了过期时间的key中,随机淘汰数 据.
  • allkeys-random 当内存不⾜以容纳新写⼊数据时,从所有key中随机淘汰数据
  • volatile-ttl 在设置了过期时间的key中,根据过期时间进⾏淘汰,越早过期的优先被淘汰. (相当于 FIFO, 只不过是局限于过期的 key)
  • noeviction 默认策略,当内存不⾜以容纳新写⼊数据时,新写⼊操作会报错

缓存常见问题

缓存预热

缓存更新中,有定期更新,不需要预热;定期更新,需要预热。
在redis服务器首次接入的时候,服务器中没有数据。此时所有请求都会打给mysql,随着时间推移,redis上的数据越积累越多,mysql承担的压力逐渐变小。但就怕刚开始mysql就垮了,因此需要进行缓存预热(将定期生成和实时生成结合),先通过离线的方式,通过一些统计的途径,先把热点数据找到一批,导入到redis中,此时导入的这批热点数据,就能帮mysql承担很大的压力,随着时间推移,逐渐使用新的热点数据淘汰掉旧的数据。

缓存穿透(cache penetration)

查询某个key时,redis中没有,mysql中也没有。这次查询没有,下次查询还是没有,如果像这样的数据非常多,并且还反复查询,就会给mysql带来很大压力。
出现的可能原因

  1. 业务设计不合理,例如缺少必要的参数校验环节,导致非法的key也被进行查询
  2. 开发/运维误操作,不小心将部分数据从数据库上误删除
  3. 黑客攻击

解决方案

  1. 改进业务/加强监控报警(亡羊补牢)
  2. 如果发现这个key在redis和mysql中都不存在,仍然写入redis,value设成一个非法值如“”
  3. 引入布隆过滤器,每次查询redis/mysql之前都先判定key是否在布隆过滤器上存在。

布隆过滤器:结合了hash+bitmap,以比较小的空间,比较快的时间速度,实现对key是否存在的判定

缓存雪崩(cache avalanche)

短时间内,redis上大规模的key失效,导致缓存命中率陡降,并且mysql压力迅速上升,甚至导致宕机。
出现的可能原因

  1. redis挂了,redis宕机/redis集群模式下大量节点宕机
  2. redis正常,但是之前短时间内设置了很多key给redis,并且设置的过期时间正好相同

解决方案

  1. 加强监控报警,加强redis集群可用性的保证
  2. 不给key设置过期时间/设置过期时间的时候添加随机因子,避免同一时刻过期

缓存击穿(cache breakdown)

缓存雪崩的特殊情况,针对热点key突然过期,导致大量请求直接打到mysql上,甚至引起数据库宕机。
解决方案

  1. 基于统计方式发现热点key,并设置永不过期
  2. 进行必要的服务降级,例如访问数据库的时候使用分布式锁,限制同时请求的数据库的并发数

服务降级:本身服务器有十个功能,特定情况下,适当关闭一些不重要的功能,只保留核心功能(省点模式)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

指挥部在下面

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值