中间件Redis

Redis为什么快?

  • 基于内存的操作
  • 单线程,避免了上下文切换
  • 高效的数据结构,Hash表、有序集合、列表等。
  • I/O多路复用模型,实现了单线程处理多个客户端链接的处理
  • 多线程的引入:在Redis 6.0中,引入了多线程的机制可以减少由于网络I/O等待造成的影响,还可以充分利用 CPU 的多核优势。

Redis的数据类型

  • 1.字符串(String)
    • 底层实现:SDS。Redis 中的字符串类型底层使用 SDS 结构来实现。SDS 是一个动态字符串结构,由长度、空闲空间和字节数组三部分组成。SDS 提供了常数时间复杂度的长度获取、减少内存重分配次数、二进制安全等特性。
    • 使用场景:主要用于存储token这类的简单字符串数据、分布式锁、还有Int类型的自增数字、分布式Id。
  • 2.Hash
    • 底层实现
      • ziplist(压缩列表):当哈希对象保存的键值对数量较少且每个键值对的键和值的字符串长度也较短时,Redis 会使用 ziplist 作为底层实现。
      • hashtable(哈希表):当哈希对象中的数据量超过一定阈值时(如键值对数量过多或键值对中的字符串长度过长),Redis 会将底层实现转换为 hashtable。Hashtable 是一种散列表结构,通过哈希函数计算字段在数组中的索引,实现快速的查找、插入和删除操作。
      • listpack(Redis 7.0 之后):在 Redis 7.0 版本之后,listpack 取代了 ziplist 作为哈希类型在存储少量数据时的底层实现。listpack 解决了 ziplist 的连锁更新问题,提高了性能。
    • 使用场景:主要用来存储像用户信息、商品信息、购物车信息等。
  • 3.List
    • 底层实现
      • linkedlist(链表):Redis 的列表类型底层使用双向链表实现。链表中的每个节点都包含前一个节点和后一个节点的指针,以及节点存储的数据。这种结构使得 Redis 可以在列表的两端快速地进行插入和删除操作。
      • quicklist(Redis 3.2 之后):在 Redis 3.2 版本之后,列表的底层实现由链表改为了 quicklist。Quicklist 是一种基于 ziplist 和 linkedlist 的混合结构,它将多个 ziplist 串联起来,每个 ziplist 内部仍然保持顺序存储,但整体上可以通过指针快速访问各个 ziplist。这种结构既保留了 ziplist 的紧凑性,又通过指针提高了访问速度。
    • 使用场景:主要用于消息队列或者广播之类的,
  • 4.set
    • 底层实现
      • intset(整数集合):当集合只包含整数元素时,Redis 会使用 intset 作为底层实现。Intset 是一个有序集合,内部使用数组存储整数,并且会根据整数的范围动态选择合适的存储类型(如 16 位、32 位或 64 位整数)。
      • hashtable:当集合中包含非整数元素时,Redis 会使用 hashtable 作为底层实现。每个元素都作为 hashtable 的一个键值对存储,其中键是元素本身,值是一个空对象(通常是一个特殊的占位符)。
    • 使用场景:主要用于计算、交集、并集、差集,共同好友等。
  • 5.Zset
    • 底层实现
      • 跳跃表(Skip List):Redis 的有序集合类型底层使用跳跃表实现。跳跃表是一种随机化的数据结构,能够在有序集合中实现快速的查找、插入和删除操作。它通过多层索引来提高查找效率,每一层索引都是对下一层索引的稀疏表示。
      • ziplist(Redis 3.2 之前或元素较少时):在 Redis 3.2 版本之前,或者当有序集合中的元素数量较少且每个元素的字符串长度也较短时,Redis 可能会使用 ziplist 作为底层实现来节省内存空间。但请注意,在 Redis 3.2 及之后的版本中,有序集合的默认底层实现是跳跃表。
    • 使用场景
      • 排行榜:存储用户的积分或排名信息,用于生成排行榜。
      • 热度排名:根据元素的分数进行排序,用于生成热度或权重排名。
      • 延迟消息(不建议)
  • 6.stream
    • 消息队列
  • 7.bitmap
    • 是否在线
    • 签到 -按照每天时间做一个key,对应的人Id在某天有没有签到。统计一个月,30天30个Key
  • 8.geo
    • 地图数据

缓存穿透、缓存击穿、缓存雪崩

  • 缓存穿透

    • 定义:缓存穿透是指查询一个缓存和数据库中都不存在的数据,导致每次请求都直接查询数据库,从而给数据库带来压力。
    • 原因
      • 恶意攻击,攻击者有意查询不存在的数据。
      • 缓存数据失效不及时或系统设计不当。
    • 解决方案
      • 缓存空对象:将不存在的数据也缓存起来,但设置一个较短的过期时间,如2分钟。这样,后续的查询就可以直接从缓存中获取空值,避免访问数据库。
      • 布隆过滤器:在缓存层前使用布隆过滤器,对所有可能的数据建立一个布隆过滤器。查询时,先通过布隆过滤器判断数据是否存在,如果不存在,则直接返回,不查询数据库。
  • 缓存击穿

    • 定义:缓存击穿是指在高并发环境下,大量请求同时访问缓存中不存在的数据(通常是一个热点数据),导致这些请求穿透到数据库,给数据库带来巨大压力。
    • 原因
      • 热点数据在缓存中突然失效。
      • 缓存中没有存储这个数据,而数据库中有这个数据。
    • 解决方案
      • 互斥锁:当查询缓存未命中时,使用互斥锁(如Redis的SETNX命令)来确保只有一个线程能够查询数据库并重建缓存。其他线程则等待锁释放后重新查询缓存。
      • 逻辑过期:在缓存的value中设置逻辑过期时间,当数据逻辑过期时,通过异步线程重建缓存,而不是在查询时同步重建。这样可以减少对数据库的压力。
  • 缓存雪崩

    • 定义:缓存雪崩是指在某一时刻发生大量的缓存失效,导致瞬间大量的请求直接打到数据库,可能会导致数据库瞬间压力过大甚至宕机。
    • 原因
      • 大量缓存同时设置相同的过期时间。
      • Redis服务器宕机或缓存数据被误删除。
    • 解决方案
      • 设置随机过期时间:避免大量缓存同时失效,可以为每个缓存设置一个随机的过期时间。
      • 高可用架构:使用Redis的哨兵模式或集群模式,确保Redis服务的高可用性。即使部分节点失效,整个缓存层依然可以使用。
      • 熔断机制:在系统中加入熔断机制,当数据库请求达到一定的阈值时,直接拒绝部分请求,以保护数据库不被过度访问。
      • 数据预热:在系统启动后,预先加载部分常用的数据到缓存中,减少在高峰期的数据库访问。
      • 备份和恢复策略:定期备份Redis数据,并确保在Redis宕机后,可以快速恢复数据。

Redis的内存淘汰策略

  • noeviction

    • 描述:当内存不足以容纳新写入数据时,新写入操作会报错,不会淘汰任何数据。
    • 适用场景:对数据的完整性有极高要求,且能够接受在内存不足时拒绝所有写操作的场景。但通常不推荐在生产环境中使用,因为可能会导致Redis进程被强制杀死,数据全部丢失。
  • volatile-lru

    • 描述:从设置了过期时间的key中,使用LRU(最近最少使用)算法进行淘汰。即优先淘汰那些最近最少使用且已经设置了过期时间的key。
    • 适用场景:需要设置过期时间,同时希望缓存尽可能保留热门数据的场景。
  • volatile-ttl

    • 描述:从设置了过期时间的key中,淘汰过期时间剩余最短的key。这种策略优先淘汰那些即将过期的key,确保Redis存储的数据尽可能新鲜。
    • 适用场景:需要快速淘汰即将过期数据的场景,比如缓存即将失效的会话信息等。
  • volatile-random

    • 描述:从设置了过期时间的key中随机选择一个key进行淘汰。
    • 适用场景:在需要淘汰过期key,但又不希望完全依赖LRU算法的情况下,可以使用这种随机淘汰策略。
  • allkeys-lru

    • 描述:从所有key中使用LRU算法进行淘汰,不区分是否设置了过期时间。
    • 适用场景:适用于缓存场景,可以确保经常被访问的数据保留在内存中,提高缓存命中率。
  • allkeys-lfu

    • 描述:从所有key中使用LFU(最不经常使用)算法进行淘汰,也不区分是否设置了过期时间。LFU算法根据数据被访问的频率来决定哪些数据应该被移除。
    • 适用场景:适用于读操作频繁,且希望保留被频繁访问的数据的场景。
  • allkeys-random

    • 描述:从所有key中随机选择一个key进行淘汰,不考虑key的访问频率或过期时间。
    • 适用场景:在不确定哪些key是热门数据,或者对淘汰策略没有特殊要求的情况下,可以使用这种简单的随机淘汰策略。
  • volatile-lfu

    • 描述:与volatile-lru类似,但使用LFU算法进行淘汰,仅针对设置了过期时间的key。
    • 适用场景:适用于读操作频繁,且希望保留被频繁访问的、同时也有过期时间的数据的场景。
  • 如何设置和查看淘汰策略:

    • 通过配置文件设置:在Redis的配置文件redis.conf中,通过maxmemory-policy属性来设置淘汰策略,如maxmemory-policy volatile-lru。同时,还需要通过maxmemory属性来设置Redis能使用的最大内存大小。
    • 通过命令行动态设置:使用Redis的命令行工具redis-cli,通过CONFIG SET命令来动态设置淘汰策略,如CONFIG SET maxmemory-policy volatile-lru。

Redis的过期策略

  • 惰性删除(Lazy Deletion)
    • 在key被访问时,Redis会检查该key是否已过期。如果已过期,则删除该key。这种策略的优点是节省CPU资源,因为它只在key被访问时才检查其是否过期,但是缺点是如果过期的key长时间未被访问,那么这些key就会一直占用内存空间。
  • 定期删除(Periodic Deletion)
    • Redis会周期性地随机检查一部分设置了过期时间的key,并删除其中的过期key。这个周期是通过Redis的定时任务来完成的,默认每秒进行10次过期扫描(这个频率可以通过配置hz参数来调整,但并非直接对应每秒的扫描次数,而是Redis内部事件循环的频率)。
      在定期删除过程中,Redis并不是每次扫描都遍历所有的key,而是采用了一种随机的方式,每次只检查一部分key,从而避免了对CPU资源的过度占用。但是,这也可能导致一些过期的key在较长的时间内仍然占用内存

Redis缓存与数据库不一致

  1. 先更新数据库再删缓存
  2. 延迟双删:先删除缓存,再更新数据库,再删除一次缓存
  3. 使用Cannel监听数据库表的binlog来更新缓存
  • 业务不大,先更新库再删缓存
  • 业务并发度高,可以先删缓存,在读库的时候加分布锁,再更新库、再异步去删一次缓存

如何解决热Key

  • 多级缓存
  • 分片存储
  • 热Key拆分
  • 识别突发热Key,使用京东的hotkey。
  • redis 4.0.3中提供了redis-cli的热点key发现功能,执行redis-cli时加–hotkeys

如何解决热BigKey

  • 影响:
    • 占用内存大影响读取
    • 删除也耗时
    • 分片间内存分布不均匀
  • 识别:
    • 使用redis-cli工具:使用redis-cli --bigkeys命令扫描Redis中的键,并返回所有大小超过指定阈值的BigKey。这个命令会给出每个数据类型的最大key及其估算的内存占用。
    • 也可以结合–scan命令和–pattern参数来扫描特定模式的键。
  • 处理:
    • 拆分BigKey:
      • 对于Hash、List、Set等集合类型的大key,可以将其拆分成多个小key进行存储。例如,一个包含大量字段的Hash可以拆分成多个小Hash,每个小Hash存储一部分字段。
      • 使用哈希分片或前缀树等技术将大key拆分成更小的键,并存储在不同的实例或层级中。
    • 使用过期时间

Redis集群的选举投票机制是怎样的?

在Redis集群中,当主节点出现故障时,从节点会发起选举投票机制来选举出新的主节点。所有主节点都会参与投票,当超过半数的主节点同意某个从节点成为新的主节点时,该从节点就会被提升为主节点。这个过程是自动的,不需要人工干预。

Redis集群如何支持高可用性和故障转移?

Redis集群通过主从复制和哨兵模式(或集群模式自带的故障转移机制)来支持高可用性和故障转移。在主从复制模式下,数据从主节点复制到从节点,当主节点出现故障时,从节点可以接管主节点的角色继续提供服务。在哨兵模式下,哨兵会监控主节点和从节点的状态,并在主节点出现故障时自动进行故障转移。而在集群模式下,集群会自动处理节点的故障和恢复过程。

Redis的哨兵机制

  • 监控:哨兵(Sentinel)进程会持续监控主服务器和从服务器的运行状态,包括但不限于检查服务是否正常响应、判断主从复制是否正常进行等。
  • 自动故障检测与转移:当主服务器发生故障(如宕机或网络断开),哨兵能及时发现并确定主服务器是否真的不可达。如果达到预设条件,哨兵将自动执行故障转移操作,选择一个从服务器升级为主服务器,并通知其他从服务器开始复制新的主节点。
  • 配置更新:哨兵不仅负责切换主从角色,还会自动更新相关的配置信息,确保整个集群中的所有节点都知道新的主服务器是谁,从而维持集群的正确配置和数据同步。
  • 系统通知:哨兵可以向管理员或者其他应用程序发送报警信息,报告关于Redis服务器的各种状态变化,通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。

Redis的持久化

  1. RDB持久化机制
  • 定义与原理

    • RDB是Redis的数据备份文件,也被称为Redis数据快照。它是将内存中的全部数据以二进制文件的形式保存到磁盘上,实现数据的持久化。当Redis实例重启时,可以从RDB文件中读取数据以恢复数据库状态。
  • 触发机制

    • RDB的触发机制包括手动触发和自动触发。手动触发可以通过执行save或bgsave命令来实现,其中bgsave是异步执行,不会阻塞Redis主进程。自动触发则是在redis.conf配置文件中设置条件,当满足特定条件(如一定时间内修改了指定数量的key)时,Redis会自动执行bgsave命令进行持久化。
  • 优点

    • 文件紧凑:RDB文件是二进制文件,相对于AOF文件,它的体积更小,更节省磁盘空间。
    • 恢复速度快:由于RDB文件直接存储了内存数据,因此在恢复时速度较快。
    • 对性能影响小:生成RDB文件时,Redis主进程会fork一个子进程来处理,因此不会对Redis的性能造成太大影响。
  • 缺点

    • 数据丢失风险:RDB是间隔一段时间进行全量备份,如果在两次备份之间Redis宕机,那么会丢失这部分时间内的数据。
    • fork操作开销:在生成RDB文件时,Redis需要fork一个子进程,这个操作会消耗一定的CPU资源,并且在fork期间会阻塞Redis的写操作。
  1. AOF持久化机制
  • 定义与原理
    • AOF是Redis的另一种持久化机制,它通过记录Redis执行的所有写操作命令来实现数据的持久化。这些写操作命令以文本形式追加到AOF文件中,当Redis重启时,可以重新执行这些命令来恢复数据。
  • 触发机制
    • AOF的触发机制主要是基于写操作的同步策略。Redis提供了三种写操作同步策略:always(每次写操作都同步到磁盘)、everysec(每秒同步一次)、no(不自动同步,由操作系统决定何时同步)。
  • 优点
    • 数据可靠性高:AOF记录了所有的写操作命令,因此可以最大限度地保证数据的完整性。
    • 文件可读性强:AOF文件是文本文件,可以很方便地查看和编辑。
    • 灵活性高:AOF提供了重写机制,可以优化文件大小和提高恢复速度。
  • 缺点
    • 文件体积大:由于AOF记录了所有的写操作命令,因此随着时间的推移,AOF文件可能会变得非常大。
    • 恢复时间长:在恢复数据时,需要重放AOF文件中的所有命令,这可能会消耗较长时间。
    • 性能影响:频繁的写操作同步到磁盘会对Redis的性能产生一定影响。
      综上所述,Redis的RDB和AOF两种持久化机制各有其优缺点。在实际应用中,可以根据具体需求选择适合的持久化机制,或者同时使用两种机制以提供更好的数据保障。
  1. 混合模式
  • 混合模式的工作原理
    • 在混合模式下,Redis首先会像RDB模式那样生成一个快照文件,然后将从快照点开始的所有写操作记录到AOF日志中。这样,在Redis重启时,可以先加载RDB快照文件以快速恢复大部分数据,然后再重放AOF日志中的写操作,以恢复从快照点到Redis停机时的数据变更。
  • 混合模式的配置
    • 在Redis 4.0及以后版本中,混合模式是自动启用的,只要同时开启了RDB和AOF (无需额外配置,只要同时设置了RDB和AOF的相关参数,Redis就会自动采用混合模式)
  • 混合模式的优点
    • 快速恢复:通过加载RDB快照文件,可以快速恢复大部分数据,减少启动时间。
    • 数据完整性:通过AOF日志,可以确保从快照点到Redis停机时的数据变更不会丢失,提高数据完整性。
    • 性能优化:在数据恢复时,可以并行处理RDB快照文件和AOF日志,进一步提高恢复速度。
  • 混合模式的缺点
    • 磁盘空间占用:由于同时生成了RDB快照文件和AOF日志,可能会占用更多的磁盘空间。
    • 性能影响:在写操作频繁的场景下,AOF日志的写入可能会对Redis的性能产生一定影响。

Redis的集群

  1. 主从复制
  • 从节点配置saleof哪个主节点就可以。不具备故障自动转移和主节点挂掉如果如数没有同步到从节点导致数据丢失。
  1. 哨兵模式
  • 引入哨兵监控主节点状态,发现逐渐点故障,则会选一个合适的从节点重新作为主节点
  1. Cluster
  • Redis Cluster将全部的键空间划分为16384块,每一块空间称之为槽(slot)。
  • 使用CRC16算法对key进行hash,然后再对16383取模,结果便是对应的slot。
  • 集群中的每个主节点都会负责一部分slot的读写操作。

Redis的集群选举(Raft算法)

  • 选择优先级(slave-priority)最高的从节点作为新的主节点。
  • 如果存在多个优先级相同的从节点,则选择复制偏移量(即数据同步进度)最大的从节点。
  • 如果复制偏移量也相同,则选择运行ID最小的从节点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值