Redis(五)—— 配置文件、持久化、Redis集群、穿透/击穿/雪崩

📅 2026/7/15 16:07:24
Redis(五)—— 配置文件、持久化、Redis集群、穿透/击穿/雪崩
一、Redis配置文件详解注意这是Redis服务本身的配置文件相当于maven的settings.xml而不是我们在springboot去配置Redis的那个application.yml。核心部分 include 引入其他redis配置文件相当于spring的import bind 设置IP默认是127.0.0.1 protected-mode yes 是否开启保护模式默认开启 daemonize yes 是否以守护进程方式运行redis默认是no我们将其改为yes pidfile /../../..pid 既然是守护进程就指定这个守护进程的pid文件 loglevel 日志级别有好多种日志级别 logfile 指定日志文件的位置 databases 16 默认数据库16个 always-show-logo yes 这个很有意思就是开启redis服务的时候会不会打印图标和springboot的那个图标一回事 SNAPSHOP快照部分用于RDB持久化的配置 save 900 1 900s内修改一次这是最低标准 save 300 10 save 60 10000 设置多长时间、多少次修改持久化一次60s内修改1万次进行一次持久化 stop-writes-on-bgsave-error yes 持久化出错后是否继续工作 rdbcompression yes 是否要压缩rdb文件默认是压缩 rdbchecksum yes 保存rdb文件的时候是否检查文件错误 dir ./ rdb文件和aof文件的保存目录RDB和AOF保存在相同目录下都通过dir指定 REPLICATION主从复制用到的配置 下次再讲 SECURITY安全配置 requirepass 123456 设置密码 CLIENT 对客户端的限制不用动了解即可 maxclients 10000 最多可以连接redis-server的客户端数量 maxmemory redis的最大运行内存 maxmemory-policy redis要超过最大运行内存了怎么办同JUC的6个策略1-6从谨慎到发疯 # 1. noeviction 一个都不能删直接返回redis运行内存不够了这个错误 # 2. volatile-lru 只对设置了过期时间的key进行LRU # 3. allkeys-lru 对所有 key进行LRU # 4. valatile-ttl 删除即将过期的key # 5. volatile-random 随机删除即将过期的key # 6. allkeys-random 随机删除key APPEND ONLY AOF持久化配置 appendoNly no 默认不开启AOF持久化默认使用RDB方式持久化因为RDB在大部分情况下就够用了 appendfilename AOF持久化文件名 appendfsync always/everysec/no # 每次修改都sync消耗性能/每秒一次sync,可能会丢失这1s的数据/不执行sync,这个时候操作系统自己同步数据速度最快在redis中查看密码的命令cj:0config get requirepass 1) requirepass 2) CsiFlow!#680二、持久化PS:RDB类比undologMVCC里的快照记得不AOF可以类比mysql的binlog去看持久化的原因redis必须持久化吗对啊redis是运行在内存里的不持久化的话redis宕机后再启动啥都没有了此时全部的流量都会打到MySQL上又会给MySQL打崩但“内存断电”这只是redis需要持久化的其中一个原因。一共有两个原因redis宕机后重启恢复数据主从复制RDB 文件3 种持久化方式:Redis 不同于 Memcached 的很重要一点就是Redis 支持持久化而且支持快照snapshottingRDB只追加文件append-only file, AOFRDB 和 AOF 的混合持久化(Redis 4.0 新增)2.1 RDB 持久化Redis 可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。Redis 创建快照之后可以将快照复制到主从结构其他服务器从而创建具有相同数据的服务器副本将快照留在原地以便重启服务器的时候使用。RDB持久化的过程跟浏览器下载文件的过程一样 先在dir指定的路径下创建一个dump.rdb文件往里写入数据写完后替换上次的dump.rdb文件区别于AOF的“追加”。持久化了以后怎么用全自动的只要dump.rdb文件放在redis开启目录下redis每次开启时都会开机自检核对数据持久化是 Redis 默认采用的持久化方式在redis.conf配置文件中默认有此下配置不用改默认的就很好用save 900 1 #在900秒(15分钟)之后如果至少有1个key发生变化Redis就会自动触发bgsave命令创建快照。 save 300 10 #在300秒(5分钟)之后如果至少有10个key发生变化Redis就会自动触发bgsave命令创建快照。 save 60 10000 #在60秒(1分钟)之后如果至少有10000个key发生变化Redis就会自动触发bgsave命令创建快照。1、触发RDB的时机上面save设置了触发RDB的时机但这并不是全部的时机。flushdb、flushall命令会自动触发RDB满足上面save规定关掉redis时2、RDB 创建快照时会阻塞主线程吗redis是单线程的但是在进行持久化的时候会fork一个子线程这个子线程专门进行RDB持久化操作主线程照样运行其他命令。Redis 提供了两个命令来生成 RDB 快照文件save: 同步保存操作会阻塞 Redis 主线程bgsave: fork 出一个子进程/线程子进程执行不会阻塞 Redis 主线程默认选项。2.2 AOF 持久化只记录写命令不记录读命令和binlog一样恢复数据的时候把所有命令都执行一遍先写AOF再更新缓存这样写完AOF还没更新缓存redis就崩了的情况下也能恢复数据。过appendonlyyes参数开启其他配置都不用动文件名appendonly.aof2.3 二者的选择与比较能说出这仨点即可RDB运行效率更高所以RDB是redis默认开启的AOF默认不开启AOF的安全性更高。但是效率是牺牲数据的实时性带来的AOF可以用sync命令去设置每次修改都同步或者每秒同步但是RDB只能用save命令设置多少秒同步不能精确到每一条命令。试想我们设置一个save 60 10000,60s内发生一万次修改的时候持久化到硬盘但是如果还没到60s发生第9999次修改后宕机了那这9999次修改就丢失了。但AOF也不是完全安全的哦因为AOF默认开始的是每秒同步但是如果这1秒没来及同步就宕机了就会丢失这1秒的数据。当然如果你开启每条命令同步那就是绝对安全的了。RDB恢复速度更快。RDB存储的是数据库快照而AOF就和mysql的binlog一样存储的是一条条执行过的命令。如果要恢复大规模数据RDB直接拷贝快照但是AOF要一条条执行命令你想想哪个快解决AOF越写越多占用磁盘的问题定期压缩如何压缩呢如果有一条命令set a 1再有一条命令set a 2那么只存储set a 2就好啦2.4 rdb或aof文件被破坏怎么办aof文件是可以打开的比如说我们打开文件以后往里面随便敲点东西。那么下次redis开机会直接开不了解决调用redis提供的redis-check-aof工具修复aof文件。综上如果Redis 保存的数据丢失一些也没什么影响的话可以选择使用 只用RDB。不建议单独使用 AOF因为RDB确实牛哇时不时地创建一个 RDB 快照可以进行数据库备份、更快的重启以及解决 AOF 引擎错误。如果企业对保存的数据要求安全性比较高的话建议同时开启 RDB 和 AOF 持久化或者开启 RDB 和 AOF 混合持久化所以要么单独使用RDB要么使用RDBAOF要么使用混合策略就是不能单独使用AOF三、Redis发布订阅底层如何实现发布订阅逻辑redis是用C语言写的发布与订阅的功能在pubsub.c这个文件里想看源码的可以去看。三个命令subscribe 频道名publish 频道名unsubscribe 频道名应用场景redis的消息中间件功能只用于简单场景复杂场景的话我们用rocketMQ卡夫卡这种专业的消息中间件去做。除了推送公众号这种显而易见的发布订阅聊天室可以用redis实现吗可以管理者我自己瞎起的名字作为发布者所有聊天室的人作为订阅者。要想做到每一个发送的聊天信息都能被所有人收到那就要先发给管理者然后由管理者推送给所有订阅者。就是多了先“发给管理者”这一步而已四、Redis集群redis主从复制跟MYSQL的主从复制是一模一样的都是主机能读能写从机只能读。任何项目中都不可能只用一台redis主要原因是因为redis会宕机次要原因是性能瓶颈没法实现负载均衡最低配置是一主二从其实技术上来讲一主一从是可以的但是由于redis的哨兵模式当主机挂掉了并且只有一个从机的时候是没办法进行选举的所以在redis里集群的最低配就是一主二从。默认情况下每个redis服务都认为自己是主节点。就要让他低头认老大变成从节点4.1 主从复制分为部分复制和全部复制这里只讲全部复制。数据分成两部分可视化一下从节点清空自己数据然后拷贝过来主节点的RDB文件这是主节点的上一个版本的快照但是不是此时此刻的版本呀。主节点会记录RDB快照后发生的所有写命令在复制客户端缓冲区每个从节点独立一个缓冲区主节点发送给从节点从节点执行这些命令追上主节点状态。为什么redis用RDB实现主从同步而不是像MySQL一样用AOF把命令都跑一遍用AOF把命令都跑一遍也可以实现主从复制但是慢。4.2 集群搭建在一台机器上开三个redis服务/进程/程序占用3个不同的端口号当然也可以开在不同的机器上哈4.3 配置一主二从和docker“数据卷容器”实现多个容器之间的数据同步“通过docker run--volumes-fromdocker01挂载了docker01那么docker01就是docker02的父容器”的思想是一样的。https://blog.csdn.net/qq_44886213/article/details/127844443https://blog.csdn.net/qq_44886213/article/details/127844443永久方法一在配置文件中进行配置只需要配置从机就行这是永久的也是实践中真实采用的。临时方法二用SLAVE命令 只需要配置从机就行这是临时的测试的时候用一下用set命令向主机中写一个key从机中就能查出来了底层是用RDB实现的同步的吗临时配置主从和永久配置主从带来的区别主机断了无区别一主二从模式下主机宕机了怎么办因为我们没有配置哨兵模式所以不会选举新的主机就干等着主机回来或者用SLAVEOF no one命令手动配置一个新主机这就是“谋朝篡位”。主机回来以后自动连接上他的两个从机经测试主机断开后再连接然后set一个新的值从机是能拿到这个新值的说明主机回来以后自动建立起和从机的链接。“谋朝篡位”特别形象。因为一旦主机走了之后上任了新主机那么原来的主机回来以后也失去了地位所以“谋朝篡位”很形象从机断了有区别当从机断开连接后再次回来的时候。如果使用命令行方式临时配置的那么回来的从机又变成主机了相当于和主机断开连接。但是如果是用配置文件配置的回来的时候依然是从机。原因在于redis启动的时候会读配置文件如果是用临时方式配置的从机回来以后成为主机我们再将其用SLAVE命令变成从机能拿到之前的命令吗能啊别被绕进去。因为主从复制拷贝的是主机的全部数据主机和从机的数据完全一致的一个奇思妙想如果是下图这种关系当然生产实际不会用这种的哈只是一个奇思妙想把6380配成6379的从机把6381配成6380的从机。那么6380的身份到底是主机还是从机呢我们用info replication命令去查发现6380的role是从机。那么当6379宕掉时6380会成为主机执行写操作吗不可以五、哨兵模式——投票选举5.1 原理一句话描述哨兵模式在前面的描述里主从模式下当主机宕掉后我们用SLAVEOF no one命令手动配置新主机叫做手动的“谋朝篡位”。一句话理解哨兵模式——自动版“谋朝篡位”。6个进程哨兵是单独开的一个进程这个进程和redis服务并列关系类似于QQ和QQ管家之间的关系不是多进程关系哦。还是以一主二从为例这个哨兵定期向三台redis服务发送ping(心跳命令) 命令看看有没有人回复PONG没有回复就认为它挂了。这里有一个问题万一哨兵自己挂了怎么办所以哨兵模式采用多哨兵一共安排了3个哨兵也就是说我们在一主二从的模式下一旦采用了哨兵模式就至少开了6个进程。主观下线客观下线简单来说主观下线就是1个哨兵认为redis服务宕机了只有1个哨兵这样想这是主观的客观下线就是3个哨兵哨兵经过一系列确认操作确认redis服务确实挂掉了。假如现在master偷摸自己挂掉了当哨兵1定时给master发送PING命令时发现master没有回复PONG命令哨兵1就主观认为master挂掉了但是哨兵1不会马上发起选举操作因为还要拉其他两个哨兵进行客观下线的确认。当哨兵2和哨兵3给master发PING命令也得不到回复时注意不是发一次而是累积多次PING累积达到一定次数就认为客观下线。那么此时就发起选举这个选举可能是由哨兵1哨兵2哨兵3任何一个发起的比如说我们设置累积10次PING得不到回复就认为master客观下线那么第10次PING是哪个哨兵发起的就由哪个哨兵发起选举。投票算法如何选举新主机投票下面讲一下投票算法。5.2 实操——如何使用哨兵模式redis已经给我们准备好了之前说过哨兵是单独开的一个进程这个进程和redis服务并列关系在这里如果要开启哨兵模式就要按照以下步骤1vim命令新建并编写哨兵配置文件conf文件2运行哨兵进程3测试选举master崩了到选举出新master是一个动态的过程建议看视频10:00左右34、哨兵模式详解_哔哩哔哩_bilibili34、哨兵模式详解是【狂神说Java】Redis最新超详细版教程通俗易懂的第34集视频该合集共计36集视频收藏或关注UP主及时了解更多相关视频内容。https://www.bilibili.com/video/BV1S54y1R7SB?p34vd_source4e5addbe07f6c2c1f970580da6513dd65.3 哨兵模式的优缺点优点高性能——负载均衡主从模式的优点它都有高可用master挂掉进行failover故障转移重新选举master保证了系统的高可用健壮性哨兵模式实现自动的‘谋权篡位’一改之前的手动模式“自动”便是增加了系统的健壮性缺点别看我们上面就配置了一行但是实际上哨兵模式的配置很麻烦的六、缓存穿透和雪崩面试高频工作常用再也不怕缓存雪崩、击穿、穿透8 张图搞懂https://mp.weixin.qq.com/s/_StOUX9Nu-Bo8UpX7ThZmg先回顾一下缓存在哪个地方当redis仅作为缓存使用不作为key-value数据库使用时它就在MySQL前面充当CPU-cache-内存中的“cache”的作用。缓存异常会面临的三个问题缓存雪崩、击穿和穿透。其中缓存雪崩和缓存击穿主要原因是数据不在缓存中而导致大量请求访问了数据库数据库压力骤增容易引发一系列连锁反应导致系统奔溃。不过一旦数据被重新加载回缓存应用又可以从缓存快速读取数据不再继续访问数据库数据库的压力也会瞬间降下来。因此缓存雪崩和缓存击穿应对的方案比较类似。而缓存穿透主要原因是数据既不在缓存也不在数据库中。因此缓存穿透与缓存雪崩、击穿应对的方案不太一样。“穿透”和“击穿”两个容易混你这样理解就行了一个个的请求发射到缓存这个墙上“穿透”是不走墙的“击穿”是走墙的。穿透你要忽略“穿”这个字只看“透”这个字相当于绕过了缓存直接访问数据库你修了一道墙缓存想保护后面的房子数据库但攻击者找了一条你根本没封死的暗道源源不断地绕过去。“击穿”呢是把墙上的某给点给打穿了。雪崩更好理解了墙直接塌了。1. 缓存穿透读请求先访问缓存如果缓存没有命中再去访问数据库MySQL数据库中也没有。那么当有大量这样的请求到来时数据库的压力骤增这就是缓存穿透的问题。PS首先为什么出现这个问题因为redis数据和mysql无法保持一致如果是完全一致的那redis不存在的mysql肯定也不存在直接打回去就行了。而redis的设计哲学就是利用了数据的不一致性这一点打了个“容错差”缓存穿透的发生一般有这两种情况业务误操作缓存中的数据和数据库中的数据都被误删除了所以导致缓存和数据库中都没有数据黑客恶意攻击故意大量访问某些读取不存在数据的业务无论是一个这样的凑巧请求还是上万个这样的恶意请求都叫缓存穿透因为你业务上根本不知道会来一个还是上万个所以直接一起防了算了。解决方法① 校验。最基本的就是首先做好参数校验一些不合法的参数请求直接抛出异常信息返回给客户端。比如查询的数据库 id 不能小于 0、传入的邮箱格式不对的时候直接返回错误消息给客户端等等。② 缓存空值请求来了 → 查缓存没有 → 查数据库也没有 →把空值写入缓存→ 返回空。这样下次请求同一个不存在的数据的时候缓存就会直接返回空值。但是这种方法无法避免恶意请求每次都造不一样的假数据。③ 使用布隆过滤器快速判断缓存是否存在布隆过滤器实际是上一种hash数据结构在写入数据库数据时使用布隆过滤器做个标记也就是说在数据库存在的数据一定是有标记的。我们先不查数据库而是查询布隆过滤器快速判断数据是否存在过滤掉那些请求不存在数据的请求。这样就不会去数据库读不存在的数据了也就不会发生缓存穿透了。2. 缓存击穿击穿”很形象打击的对象是某一个点这个点叫做“热点数据”。想象大量请求访问同一个热点数据比如某男艺人塌房的热搜好比一连串的子弹都打在同一个地方而redis是一堵墙替MySQL挡住了这些子弹但是当缓存过期的一瞬间这堵墙消失 就会有一连串的子弹打到MySQL上MySQL崩溃。解决方法①互斥锁。当业务线程在处理用户请求时如果发现访问的数据不在 Redis 里就加个互斥锁保证缓存构建成功之间只有一个请求去读取数据库而不是全跑去读数据库这个请求负责从数据库读取数据再将数据更新到 Redis 里当这个请求把缓存构建好后再释放锁。未能获取互斥锁的请求要么等待锁释放后重新读取缓存要么就返回空值或者默认值。//实现互斥锁的时候最好设置超时时间不然第一个请求拿到了锁然后这个请求发生了某种意外而一直阻塞一直不释放锁这时其他请求也一直拿不到锁整个系统就会出现无响应的现象。②设置不让缓存过期。但是缓存还是要更新的啊不然就跟MySQL的数据不一致了别忘了数据的一致性是ACID的终极目标数据都不一致了再高的可用性也白搭。而是由redis服务自己更新缓存数据 。redis后台开启一个线程来负责更新。3. 缓存雪崩“雪崩”很形象缓存雪崩其实不只是缓存崩了而是由缓存崩了引起来的一系列数据库继而崩了微服务继而崩了整个系统继而崩了这才是雪崩。当大量缓存数据在同一时间过期失效或者 Redis 故障宕机时如果此时有大量的用户请求都无法在 Redis 中处理于是全部请求都直接访问数据库从而导致数据库的压力骤增严重的会造成数据库宕机从而形成一系列连锁反应造成整个系统崩溃这就是缓存雪崩的问题。总结雪崩的两个原因redis宕机更严重解决方法①服务熔断---请求限流。暂停业务应用对缓存服务的访问直接返回错误这样做是为了保证数据库不崩溃等到 Redis 恢复正常后再允许业务应用访问缓存服务。但是直接服务熔断有点太粗暴了为了减少对业务的影响我们可以启用请求限流机制只将少部分请求发送到数据库进行处理再多的请求就在入口直接拒绝服务等到 Redis 恢复正常并把缓存预热完后再解除请求限流的机制。②构建redis集群异地多活。注意不是主从复制主从复制是一个写节点两个读节点说白了还是一个服务节点。异地多活可以看成多个主从复制组成的集群缓存key集中过期危害小一点或许MySQL能扛过去解决方法①均匀设置过期时间。避免将大量的数据设置成同一个过期时间。我们可以在对缓存数据设置过期时间时给这些数据的过期时间加上一个随机数②互斥锁。③设置不让缓存过期。