• 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. 进行必要的服务降级,例如访问数据库的时候使用分布式锁,限制同时请求的数据库的并发数

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

  • 相关阅读:
    卡尔曼滤波(Kalman Filter)原理浅析-数学理论推导-1
    ssm(Spring+SpringMVC+MyBatis)台球室内乒乓球室体育器械租赁收费系统
    Linux常用基本指令
    C语言文件操作
    iOS系统下轻松构建自动化数据收集流程
    常用设计模式
    英语语音篇 - 元音自然拼读
    利用HTML5 MediaDevices API调用手机摄像头并结合JavaScript库实现人脸识别
    多目标权重融合方式
    【k8s】4、资源管理命令-陈述式
  • 原文地址:https://blog.csdn.net/weixin_61427900/article/details/133183132