Redis

  1. 什么是Redis?

    Redis(Remote Dictionary Server)是一个开源的高性能键值存储内存数据库,以高性能、灵活的数据结构和丰富的功能著称。

  2. 数据结构

    字符串(string):可以存储图片或者序列化的对象,值最大存储为512M。应用场景:共享session、分布式锁,计数器、限流。

    字典(map):缓存用户信息

    集合(set):用户标签

    有序集合(Sorted Set):排行榜

    列表(list):消息队列,文章列表

    高级数据结构:位图,地理空间索引,流

  3. redis为什么快

    img

    • Mysql索引为了提高效率,选择了B+树的数据结构。其实合理的数据结构,就是可以让你的应用/程序更快。
    • Redis是单线程模型的,而单线程避免了CPU不必要的上下文切换和竞争锁的消耗。多路I/O复用技术可以让单个线程高效的处理多个连接请求。
    • 虚拟内存机制就是暂时把不经常访问的数据(冷数据)从内存交换到磁盘中,从而腾出宝贵的内存空间用于其它需要访问的数据(热数据)。通过VM功能可以实现冷热数据分离,使热数据仍在内存中、冷数据保存到磁盘。这样就可以避免因为内存不足而造成访问速度下降的问题。
  4. 缓存击穿、缓存穿透、缓存雪崩

    • 缓存穿透:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。

      产生情况:

      • 新的缓存模式没有考虑系统发布或重启后,缓存完全为空时,突发大量请求。
      • 业务/运维/开发失误的操作,比如缓存和数据库的数据都被误删除了。
      • 黑客非法请求攻击,比如黑客故意捏造大量非法请求,以读取不存在的业务数据。

      解决方案:

      • 1.如果是非法请求,我们在API入口,对参数进行校验,过滤非法值。
      • 2.如果查询数据库为空,我们可以给缓存设置个空值,或者默认值。但是如有有写请求进来的话,需要更新缓存哈,以保证缓存一致性,同时,最后给缓存设置适当的过期时间。(业务上比较常用,简单有效)
      • 3.使用布隆过滤器快速判断数据是否存在。即一个查询请求过来时,先通过布隆过滤器判断值是否存在,存在才继续往下查。
    • 缓存雪崩: 指缓存中数据大批量到过期时间,而查询数据量巨大,请求都直接访问数据库,引起数据库压力过大甚至down机。

      • 缓存雪奔一般是由于大量数据同时过期造成的,对于这个原因,可通过均匀设置过期时间解决,即让过期时间相对离散一点。如采用一个较大固定值+一个较小的随机值,5小时+0到1800秒酱紫。
      • Redis 故障宕机也可能引起缓存雪奔。这就需要构造Redis高可用集群啦。
    • 缓存击穿: 指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求打到db。

      • 1.使用互斥锁方案。缓存失效时,不是立即去加载db数据,而是先使用某些带成功返回的原子操作命令,如(Redis的setnx)去操作,成功的时候,再去加载db数据库数据和设置缓存。否则就去重试获取缓存。

        只允许一个请求线程去重建缓存,其他线程等待,缓存重建完成后,所有线程直接从新缓存中获取数据。

        deepseek_mermaid_20250825_c8c449
      • 2. “永不过期”,是指没有设置过期时间,但是热点数据快要过期时,异步线程去更新和设置过期时间。

    缓存雪崩是指数据库压力过大甚至down机,缓存击穿只是大量并发请求到了DB数据库层面。可以认为击穿是缓存雪崩的一个子集吧。

  5. 热点key

    如果某一热点key的请求到服务器主机时,由于请求量特别大,可能会导致主机资源不足,甚至宕机,从而影响正常的服务。

    如何解决热key问题?(写热点,读热点)

    方案 核心思想 优点 缺点 适用场景
    本地缓存(读热点) 将压力从 Redis 转移到应用内存 性能极致,彻底解决 数据一致性难保证 读多写少的热点数据(首选)
    Key 分片(写热点) 将一个热点分散成多个(减少CPU等待时间) 分散压力,提高吞吐 业务逻辑复杂 可拆分的计数器类数据(库存扣减、点赞计数)
    逻辑过期 避免缓存集中失效 平滑更新,用户体验好 短期数据不一致 极高并发的写更新
    限流降级 拒绝多余请求,保护系统 保证系统不崩溃 牺牲部分用户体验 突发流量,最后的防线

    分片对于必须原子更新的写操作,可能不适用。

  6. Redis的过期策略

    我们在set key的时候,指定这key60s后过期,60s后,redis是如何处理的?

    定时过期

    每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即对key进行清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。

    惰性过期

    只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。

    定期过期

    每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
    expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。

    Redis中同时使用了惰性过期和定期过期两种过期策略。

    • redis采取的是定期过期,每隔100ms就随机抽取一定数量的key来检查和删除的。
    • 但是呢,最后可能会有很多已经过期的key没被删除。这时候,redis采用惰性删除。在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间并且已经过期了,此时就会删除。

    但是,如果定期删除漏掉了很多过期的key,然后也没走惰性删除。就会有很多过期key积在内存,直接会导致内存爆的。或者有些时候,业务量大起来了,redis的key被大量使用,内存直接不够了。Redis有8种内存淘汰策略

    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中,根据过期时间进行淘汰,越早过期的优先被淘汰;
    • noeviction:默认策略,当内存不足以容纳新写入数据时,新写入操作会报错。
  7. 持久化机制

    img

    为了保证内存中的数据在断电或故障时不会丢失,Redis提供了两种主要的持久化机制:RDB(Redis Database)和AOF(Append Only File)。

    • RDB:是指在指定的时间间隔内,执行指定次数的写操作,将内存中的数据集快照写入磁盘中,它是Redis默认的持久化方式。它适合于数据备份和灾难恢复,但在发生故障后,自上次快照以来的所有数据都有可能丢失。
    • AOF:记录每一个写操作命令到一个日志文件中,命令以追加的方式保存。它主要解决数据持久化的实时性问题。默认是不开启的。它可以配置为每次写操作后同步到磁盘,或者每秒同步一次。在Redis重启时,AOF文件中的命令会被重新执行,以重建内存中的数据状态。通过AOF恢复数据通常比RDB更慢,但可以更频繁地记录数据状态,减少数据丢失的可能性。
  8. redis的高可用

    Redis 实现高可用有三种部署模式:主从模式,哨兵模式,集群模式

    • 主从模式:Redis部署了多台机器,有主节点,负责读写操作,有从节点,只负责读操作。从节点的数据来自主节点,实现原理就是主从复制机制。从服务器发送同步请求,主节点生成RDB并缓存生成RDB期间的写命令,主节点向全部从节点发送RDB,并缓存此期间的写命令。主节点向从节点同步全部写命令。

    • 哨兵模式:

      • 发送命令,等待Redis服务器(包括主服务器和从服务器)返回监控其运行状态;
      • 哨兵监测到主节点宕机,会自动将从节点切换成主节点,然后通过发布订阅模式通知其他的从节点,修改配置文件,让它们切换主机;
      • 哨兵之间还会相互监控,从而达到高可用。
    • Cluster集群模式:对数据进行分片,每台Redis节点上存储不同的内容,来解决在线扩容的问题。并且,它也提供复制和故障转移的功能。

      • 降低单节点内存需求:通过分片避免单节点存储全量数据。

      • 提高资源利用率:从节点仅保护对应分片,而非全量数据。

      • 支持弹性扩展:新增节点只需承担部分数据,避免内存爆炸。

        本质:Cluster 将“全量冗余”改为“分片级冗余”,用更细粒度的资源分配换取横向扩展能力。

  9. redis分布式锁

    分布式锁,是控制分布式系统不同进程共同访问共享资源的一种锁的实现。

    优势:高性能(Redis 操作纯内存,命令天生原子性),高可用(Redis 集群(哨兵或 Cluster)支持主节点宕机时自动切换,锁状态不会丢失), 灵活的过期机制(防死锁)

  10. MySQL与Redis 如何保证双写一致性

  • 缓存延时双删

    1. 写请求
    2. 先删除缓存
    3. 再更新数据库
    4. 休眠一会(比如1秒),再次删除缓存。
  • 删除缓存重试机制

    延时双删可能会存在第二步的删除缓存失败,导致的数据不一致问题

    img
    1. 写请求更新数据库
    2. 缓存因为某些原因,删除失败
    3. 把删除失败的key放到消息队列
    4. 消费消息队列的消息,获取要删除的key
    5. 重试删除缓存操作
  • 读取binlog异步删除缓存

    重试删除缓存机制会造成好多业务代码入侵

    "业务代码入侵"指为实现非业务功能需求(如缓存一致性),需要在业务逻辑中插入大量与核心业务无关的代码。

    img

  1. Redis6.0 多线程

    Redis的线程模型本质是"多线程+IO多路复用"的混合体

    1. IO多路复用:解决网络连接高并发问题
    2. 多线程:优化网络IO的局部性能瓶颈
    3. 单线程核心:保证数据操作的原子性和一致性
  2. 布隆过滤器:

    缓存穿透问题,使用布隆过滤器解决,其得出的判断结果是一定不存在或者可能存在

    布隆过滤器并没有存放完整的数据,它只是运用一系列哈希映射函数计算出位置,然后填充二进制向量。如果数量很大的话,布隆过滤器通过极少的错误率,换取了存储空间的极大节省,还是挺划算的。

posted @ 2025-09-28 16:04  疯啦吧你  阅读(14)  评论(0)    收藏  举报