[Redis][典型运用][缓存]详细讲解

目录


0.什么是缓存?

  • 缓存核心思路:把⼀些常⽤的数据放到触⼿可及(访问速度更快)的地⽅,⽅便随时读取
  • 缓存是更快,但是空间上往往是不足的,因此大部分时候,缓存只放一些(热点数据)
  • 二八定律:20%的热点数据,能够应对80%的访问场景

1.使用Redis作为缓存

1.为什么用?

  • 关系型数据库虽然功能强⼤,但是有⼀个很⼤的缺陷:性能不⾼
    • 换⽽⾔之,进⾏⼀次查询操作消耗的系统资源较多
  • 为什么说关系型数据库性能不高?
    • 硬件层面
      • 数据库把数据存储在硬盘上,硬盘的IO速度并不快,尤其是随机访问
      • 如果查询不能命中索引,就需要进⾏表的遍历,这就会⼤⼤增加硬盘IO次数
    • 软件层面
      • 关系型数据库对于SQL的执⾏会做⼀系列的解析,校验,优化⼯作
      • 如果是⼀些复杂查询,⽐如联合查询,需要进⾏笛卡尔积操作,效率更是降低很多
  • 因此,如果访问数据库的并发量比较高,对于数据库的压力是很大的,很容易就会使数据库服务器宕机
  • 如何让数据库能够承担更大的并发量呢?
    • 开源:引入更多的机器,部署更多的数据库实例,构成数据库集群(主从复制,分库分表等)
    • 节流:引入缓存,使用其他的方式保存经常访问的热点数据,从而降低直接访问数据库的请求数量
    • 实际开发中,两种方案往往会搭配使用
  • Redis就是一个用来作为数据库缓存的常见方案
  • Redis访问速度比MySQL快很多,或者说处理同一个访问请求,Redis消耗的系统资源比MySQL少很多 ,因此Redis能支持的并发量更大
    • Redis数据在内存中,访问内存比硬盘快很多
    • Redis只是支持简单的key-value存储,不涉及复杂查询的那么多限制规则

2.如何用?

  • Redis像一个"护盾"一样,把MySQL给罩住了

    • 客户端访问业务服务器,发起查询请求
    • 业务服务器先查询Redis,看想要的数据是否在Redis中存在
      • 如果已经在Redis中存在了,就直接返回,此时不必访问MySQL了
      • 如果在Redis中存在,再查询MySQL
  • 根据"二八定律",只需要在Redis中放20%的热点数据,就可以使80%的请求不再真正查询数据库了,虽然业务场景可能不同,但是至少绝大多数情况下,使用缓存都能够大大提升整体的访问效率,降低数据库的压力

  • 注意

    • 缓存是用来加快"读操作"的速度的
    • 如果是写操作,还是要老老实实写数据库,缓存并不能提高性能

2.缓存的更新策略

0.前言

  • 如何知道Redis中应该存储哪些数据呢?
  • 如何知道哪些数据是热点数据呢?

1.定期生成

  • 每隔⼀定的周期(⽐如⼀天/⼀周/⼀个⽉),对于访问的数据频次进⾏统计,挑选出访问频次最⾼的前N%的数据
    • 把访问的数据,以日志的形式记录下来
    • 数据量非常大,通常写个程序来统计
  • 这种做法实时性较低,对于一些突然情况应对的并不好
    • 例如:春节期间,春晚这样的词会成为高频词,但是平常则很少会有人搜索
  • 一般性的操作流程?
    • 写一套离线的流程,通过定时任务触发
      • 完成统计热词的过程
      • 根据热词,找到数据
      • 把得到的缓存数据同步到缓存服务器上
      • 控制这些缓存服务器自动重启
  • 优点:上述过程,实际上实现比较简单,过程更可控,方便排查问题
  • 缺点:实时性不够,如果出现一些突发性事件,有一些本不是热词的内容,成了热词,新的热词就可能给后面的数据库啥的带来较大压力

2.实时生成

  • 先给缓存设定容量上限(通过Redis配置⽂件的maxmemory参数设定)
  • 流程
    • 用户的每次查询
      • 如果在Redis中查到了,就直接返回
      • 如果在Redis中不存在,就从数据库查,把查到的结果同时也写入Redis
    • 如果缓存已经满了(达到上限),就触发缓存淘汰策略,把⼀些"相对不那么热⻔"的数据淘汰掉
    • 按照上述流程,持续一段事件之后,Redis内部的数据自然就是"热门数据"了
  • 通用的淘汰策略
    • FIFO(First In First Out)先进先出:把缓存中存在时间最久的(也就是先来的数据)淘汰掉
    • LRU(Least Recently Used)淘汰最久未使⽤的 :记录每个key的最近访问时间,把最近访问时间最⽼的key淘汰掉
    • LFU(Least Frequently Used)淘汰访问次数最少的 :记录每个key最近⼀段时间的访问次数,把访问次数最少的淘汰掉
    • Random随机淘汰 :从所有的key中抽取幸运⼉被随机淘汰掉
  • 上述淘汰策略,可以自己实现,当然Redis也提供了内置的淘汰策略,可供直接使用
    • volatile-lru:当内存不⾜以容纳新写⼊数据时,从设置了过期时间的key使⽤LRU算法进⾏淘汰
    • allkeys-lru:当内存不⾜以容纳新写⼊数据时,从所有key使⽤LRU算法进⾏淘汰
    • volatile-lfu:4.0版本新增,当内存不⾜以容纳新写⼊数据时,在过期的key中,使⽤LFU算法进⾏删除key
    • allkeys-lfu:4.0版本新增,当内存不⾜以容纳新写⼊数据时,从所有key中使⽤LFU算法进⾏淘汰
    • volatile-random:当内存不⾜以容纳新写⼊数据时,从设置了过期时间的key中,随机淘汰数据
    • allkeys-random:当内存不⾜以容纳新写⼊数据时,从所有key中随机淘汰数据
    • volatile-ttl 在设置了过期时间的key中,根据过期时间进⾏淘汰,越早过期的优先被淘汰(相当于FIFO,只不过是局限于过期的key)
    • noeviction默认策略 ,当内存不⾜以容纳新写⼊数据时,新写⼊操作会报错
      • 不适用于实时更新缓存
  • 整体来说Redis提供的策略和上述介绍的通⽤策略是基本⼀致的,只不过Redis这⾥会针对"过期key"和"全部key"做分别处理
    • 除⾮是Redis中的数据完全不关键,否则不应该使⽤allkeys系列的策略

3.缓存相关问题

1.缓存预热(Cache Preheating)

  • 什么是缓存预热?
    • 使⽤Redis作为MySQL的缓存的时候,当Redis刚刚启动,或者Redis⼤批key失效之后
    • 此时由于Redis⾃⾝相当于是空着的,没啥缓存数据,那么MySQL就可能直接被访问到,从⽽造成较⼤的压⼒
    • 因此就需要提前把热点数据准备好,直接写⼊到Redis中,使Redis可以尽快为MySQL撑起保护伞
  • 热点数据可以基于之前介绍的统计的⽅式⽣成即可,这份热点数据不⼀定⾮得那么"准确",只要能帮助MySQL抵挡⼤部分请求即可
  • 随着程序运⾏的推移,缓存的热点数据会逐渐⾃动调整,来更适应当前情况

2.缓存穿透(Cache Penetration)

  • 什么是缓存穿透?
    • 访问的key在Redis和数据库中都不存在 ,此时这样的key不会被放到缓存上,后续如果仍然在访问该key,依然会访问到数据库
    • 这就会导致数据库承担的请求太多,压⼒很⼤
  • 如何产生?
    • 业务设计不合理,⽐如缺少必要的参数校验环节,导致⾮法的key也被进⾏查询了
      • 典型问题
    • 开发/运维误操作,不⼩⼼把部分数据从数据库上误删了
      • 没那么典型,表现也是缓存穿透,误删操作不一定能及时发现
    • ⿊客恶意攻击
  • 如何解决?
    • 针对要查询的参数进⾏严格的合法性校验
      • 例如 :要查询的key是⽤⼾的⼿机号,那么就需要校验当前key是否满⾜⼀个合法的⼿机号的格式
    • 针对数据库上也不存在的key,也存储到Redis中,可以设成一个非法值
      • 例如value就随便设成⼀个"",避免后续频繁访问数据库
    • 使⽤布隆过滤器先判定key是否存在,再真正查询

3.缓存雪崩(Cache Avalanche)

  • 什么是缓存雪崩?
    • 短时间内⼤量的key在缓存上失效,导致数据库压⼒骤增,甚⾄直接宕机
    • 本来Redis是MySQL的⼀个护盾,帮MySQL抵挡了很多外部的压⼒,⼀旦护盾突然失效了,MySQL⾃⾝承担的压⼒骤增,就可能直接崩溃
  • 如何产生?
    • Redis挂了 -> Redis宕机 / Redis集群模式下大量节点宕机
    • Redis大量的key同时过期
      • Redis正常,但是之前短时间内设置了大量的key,并且设置的过期时间是相同的
  • 如何解决?
    • 部署⾼可⽤的Redis集群,并且完善监控报警体系
    • 不给key设置过期时间或者设置过期时间的时候添加随机时间因⼦(避免同一时间过期)

4.缓存击穿(Cache Breakdown)

  • 此处把breakdown翻译成"击穿",个⼈认为并⾮是⼀个好的选择,容易和缓存穿透混淆
    • 翻译成"瘫痪"或者"崩溃"也许更合适⼀些
  • 什么是缓存击穿?
    • 相当于缓存雪崩的特殊情况,针对热点key突然过期了,导致⼤量的请求直接访问到数据库上,甚⾄引起数据库宕机
  • 如何解决?
    • 基于统计的⽅式发现热点key,并设置永不过期
    • 进⾏必要的服务降级
      • 感性理解:本身服务器功能有10个,在特定情况下,适当的关闭一些不重要的功能,只保留核心功能,可以理解成电子设备的"省电模式"
      • 例如:访问数据库的时候使⽤分布式锁,限制同时请求数据库的并发数
相关推荐
初听于你2 分钟前
缓存技术揭秘
java·运维·服务器·开发语言·spring·缓存
恒悦sunsite2 小时前
Ubuntu之apt安装ClickHouse数据库
数据库·clickhouse·ubuntu·列式存储·8123
奥尔特星云大使3 小时前
MySQL 慢查询日志slow query log
android·数据库·mysql·adb·慢日志·slow query log
来自宇宙的曹先生3 小时前
MySQL 存储引擎 API
数据库·mysql
间彧3 小时前
MySQL Performance Schema详解与实战应用
数据库
间彧3 小时前
MySQL Exporter采集的关键指标有哪些,如何解读这些指标?
数据库
weixin_446260853 小时前
Django - 让开发变得简单高效的Web框架
前端·数据库·django
mpHH3 小时前
babelfish for postgresql 分析--todo
数据库·postgresql
zizisuo4 小时前
解决在使用Lombok时maven install 找不到符号的问题
java·数据库·maven
邂逅星河浪漫4 小时前
【RabbitMQ】docker-compose编排部署RabbitMQ容器——CentOS
分布式·docker·centos·rabbitmq·docker-compose