Redis-缓存

Redis有哪些数据结构?底层分别是如何实现的?适合哪些场景?

  • 字符串(String):Redis中最基本的数据结构,底层是简单的动态字符串,适合储存简单的键值对数据

  • 列表(List):底层实现的双向链表压缩链表,可以进行快速的插入和删除操作,适合用于实现消息队列、最新消息排行等场景

  • 集合(Set):底层实现是哈希表和数组,可以实现高效的插入删除和查找操作,并且支持对多个集合进行交集、并集和差集等操作,适合用于去重、共同好友查找等场景

  • 有序集合(Z Set):底层实现是跳跃表和压缩链表的结合,可以对每个元素关联一个分数,并按照分数进行排序,适合用于排行榜、安全中获取数据等场景

  • 哈希(Hash):底层实现是哈希表和压缩链表,可以储存多个键值对,适合用于储存对象或者记录的多个字段

数据类型底层数据结构适用场景
字符串动态字符串简单的键值对
列表双向链表和压缩链表消息队列、最新消息排行榜
集合哈希表和数组去重、共同好友查找
有序集合跳表和压缩链表排行榜、安全中获取数据
哈希哈希表和压缩链表储存对象、记录多个字段

还有其他数据类型吗?

  • 位图:以位的形式储存数据,适合处理大量的布尔值数据

  • 超日志:用于估计唯一元素的数量,节省内存空间

  • 地理空间:用于存储地理位置数据,并支持地理位置查询

  • 流:用于处理消息队列和日志数据

什么是跳表?

跳表是一种通过多层级索引来实现快速查找的数据结构,它结合了链表和层级索引的特点,具有简单实现、高效查找和扩展性好的优点

Z-set为什么要使用两种数据结构?

面对不同数量的数据情况,需要用不同的数据结构

数据量小的情况,需要压缩内存:选择压缩链表(以时间换空间)

数据量大的情况,需要提高查询效率:选跳表(以空间换时间)

为什么要使用跳表而不是二叉树或红黑树

  • 实现简单:相比与红黑树等平衡树,跳表的实现方式更加简单。它使用了层级结构和随机化的方式来时先平衡性,减少了实现的复杂性。跳表的插入、删除和查找操作的时间复杂度都是O(log n),在实践中表现良好

  • 占用空间小:跳表相对于二叉树和红黑树具有更好的空间效率。跳表不需要存储额外的指针和颜色信息,只需要存储节点的值和层级索引。这使得跳表在空间占用方面更加节省

  • 范围查询效率高:跳表对于范围查询有较好的支持。通过跳表的层级结构,可以快速定位到需要的位置,从而实现高效的范围查询

Redis是如何做数据持久化的?

Redis在做数据持久化时,提供了两种不同的方式:快照(RDB)追加文件(AOF)

  • 快照(RDB)持久化:Redis可以将内存中的数据保存到磁盘中,形成一个快照文件。快照文件是一个二进制文件,包含了某个时刻Redis中所有数据。在Redis进行快照持久化时,会fork一个子进程,将快照数据写入磁盘。当快照文件的大小达到一定阈值时,Redis会自动触发快照操作。快照持久化的优点是备份恢复速度快,缺点是可能会丢失一些数据,因为快照是定期保存的,如果Redis在快照保存前崩溃,就会丢失数据

  • 追加文件(AOF)持久化:Redis可以将所有的写操作记录到AOF文件,以此来达到数据持久化的目的。AOF文件是一个文本文件,记录了Redis服务器执行的所有操作。当Redis重启时,会根据AOF文件重新构建数据集。不同快照持久化,AOF持久化是实时记录的,因此可以尽可能地保证数据的完整性。但是AOF文件会不断增大,需要定期进行压缩。

Redis默认情况下同时启用了快照持久化和AOF持久化,可以根据实际需求选择其中一种或者两种方式进行数据持久化

Redis的Pipeline是什么?有什么好处?

Redis Pipeline是一种用于批量执行Redis命令的技术,它可以将多个命令一次性发送给Redis服务器,然后一次性接受服务器的响应结果,从而减少网络通信次数和客户端与服务器之间的延迟时间。Redis Pipeline可以提高Redis的性能和吞吐量,特别是在需要执行大量命令的场景下,效果尤其明显。

Redis集群的一些问题。分布式,主从同步等

  • Redis集群是一种分布式Redis部署模式,它将一个Redis数据库分成多个节点,每个节点可以运行在不同的物理机器上,从而提高可用性和性能

  • Redis集群中的每个节点都可以是主节点或从节点,其中主节点负责接收客户端的读写请求,并将数据同步到从节点上。从节点则负责复制主节点的数据,并在主节点宕机时接管主节点的角色。Redis集群中的主从复制机制可以提高数据的可用性和可靠性

  • Redis集群采用哈希槽(Hash slot)的方式来实现数据分片。Redis集群将整个键空间划分为16384个哈希槽,每个槽可以储存一个或多个键值对。当客户端连接到Redis集群时,Redis集群会根据键的哈希值,将键值对分配到合适的哈希槽上

哨兵机制

用来实现主从节点故障转移,检测主节点是否存活,如果发现主节点挂了,会选举一个从节点切换为主节点,并且把新主节点的相关信息通知给从节点和客户端

  • 第一轮投票:判断主节点下线

  • 第二轮投票:选出哨兵leader

  • 由哨兵leader进行主从故障转移

    • 选出新节点

    • 将从节点指向新主节点

    • 通知客户的主节点已更换

    • 将旧节点变为从节点

缓存时如何实现高性能和高并发的?

  • 缓存可以将经常访问的数据或计算结果保存在内存或其他快速访问的介质中,从而减少对数据库或其他慢速资源的访问,提高系统的性能和并发能力。缓存有很多种类型,基本原理大都是利用空间换时间

  • 一些提高性能和并发能力的优化策略

    • 根据数据的访问特点选择合适的缓存淘汰策略

    • 进行缓存预热,在系统启动前或在定时任务中提前将一些常用或重要的数据加载到缓存中

    • 尽量的避免发生缓存穿透,击穿或雪崩,可以采用布隆过滤器,设置缓存过期时间,加锁队列控制,使用二级缓存等来预存

缓存数据的一致性是什么?常用的方式有哪些?

缓存数据一致性指的是在使用缓存系统时,保证缓存数据与后端数据的一致性。当后端数据发生变化时,缓存数据也应该相应地进行更新,以确保用户获取到的数据是最新的。

主要有以下几种方式:

  • 缓存-穿透:当缓存中不存在需要的数据时,请求直接访问后端数据库,获取数据并写入缓存,从而保证缓存与数据库的一致性

  • 缓存-更新:当后端数据发生变化时,及时更新缓存中对应的数据。可以通过订阅后端数据变更的消息队列或者在数据库更新操作完成后,同步更新缓存

  • 缓存-过期:设置缓存数据的过期时间,当数据过期时,再次访问时会触发后端数据的查询和缓存更新操作,从而保证数据的一致性

  • 缓存-失效:当后端数据发生变化时,主动使缓存失效,可以通过发布消息或者调用缓存系统提供的接口,清除对应的缓存数据

  • 读写锁:使用读写锁来保证在更新缓存时,其他并发请求不能读取旧的缓存数据,以避免脏读问题

Redis过期删除策略有哪些?

主动删除一些过期的键

  • 定时删除:在设置key的过期时间时,同时创建一个定时事件,当时间到达时,有时间处理器自动执行key的删除操作

    • 优点:可以保证过期key会尽快被删除,内存会被尽快地释放,对内存友好

    • 缺点:key较多的情况下,会占用一定的CPU时间,对服务器造成一定的影响,对CPU不友好

  • 惰性删除:不主动删除过期键,每次缓存中访问key时,都会检测key是否过期,如果过期,则删除该key

    • 优点:只会占用少量的系统资源,对CPU时间友好

    • 缺点:如果一个key已经过期,没有被删除,并且以后不会再访问,那么该key就不会被释放,造成资源的浪费

  • 定期删除:每隔一段时间,从缓存中取出一定的key进行检查,删除过期的key

    • 优点:通过限制删除操作执行的时长和频率,来减少删除操作对CPU的影响,同时也能删除一部分过期的数据,在前两种方法中进行了取中操作

    • 缺点:1.性能效果上不比前两种方法好,2.难以确定删除操作执行的时长和频率

Redis使用的是过期删除+惰性删除

缓存数据的淘汰策略有哪些?

当内存使用量达到限制时,会启用淘汰策略,删除一些键来腾出空间

  • LRU(Least Recently Used):根据键的最近使用时间来淘汰数据。当空间不足时,优先淘汰最近最久未使用的数据

  • LFU(Least Frequently Used):根据键的使用频率来淘汰数据,当空间不足时,优先淘汰使用频率最低的数据

  • FIFO(First In First Out):先进先出,根据键的插入时间来淘汰数据。当空间不足时,优先淘汰最早插入的数据

  • Random(随机):随机选择需要淘汰的数据,没有具体的规则

  • TTL(Time To Live):设置键的过期时间,在过期时间到达后自动淘汰数据

缓存的“穿透”,“击穿”,和”雪崩“是什么,怎么解决?

  1. 缓存穿透,指大量的请求访问一个不存在的数据,这个数据既不在redis中也不再数据库中,数据库无法正常返回数据,从而导致数据库压力骤增。

    缓存穿透的发生主要有两种情况

    • 业务操作失误,数据被误删了

    • 黑客攻击,大量请求访问不存在的数据

    解决方案

    • 方案一:缓存空对象

      当从DB查询数据为空,我们仍然将对这个空结果进行缓存,具体的值需要使用特殊的标识,能和真正缓存的数据分开。另外,需要设置较短的过期时间,一般建议不要超过5分钟

    • 方案二:布隆过滤器(BloomFilter)

      在缓存服务的基础上,构建BloomFilter 数据结构,在BloomFilter中储存对应的Key是否存在,如果存在,说明该Key对应的值不为空

    • 方案三:非法请求的限制

      在API入口处对请求参数进行判断是否合法,拒绝恶意的请求

  2. 缓存雪崩,是指大量缓存数据同一时间过期或者redis故障宕机时,大量请求在redis中无法处理,全都访问到数据库,导致数据库、系统崩溃。

    对于不同的诱因,有不同的策略

    • 大量数据同时过期

      • 均匀设置过期时间:给缓存的数据设置一个不同的过期时间

      • 互斥锁:当发现受访问的数据不在redis中,就加个互斥锁(要加上过期时间),保证同一时间内只有一个请求来构建缓存,构建完成后再释放锁

      • 后台更新缓存:可以通过消息队列给后台发送消息,进行更新缓存,让缓存“永久有效”

    • redis宕机

      • 服务熔断或者请求限流:暂停业务,请求直接返回错误或者对请求进行限流

      • 构建redis缓存高可靠集群:采用主从节点切换的方式,主节点发生故障,换成从节点

  3. 缓存击穿,是指某个季度“热点”数据在某个时间点过期时,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从DB加载数据并回设到缓存,但是这个时候大并发的请求可能会瞬间DB压垮。对于一些设置了过期时间的Key,如果这些Key可能会在某些时间点背超高并发第访问,是一种非常“热点”的数据。这个时候,需要考虑这个问题。

    区别:

    和缓存“雪崩”的区别在于,前者针对某一Key缓存,后者则是很多Key

    和缓存“穿透”的区别在于,这个Key是真实存在对应的值的

    有两种方案可以解决:

    • 使用互斥锁。请求发现缓存不存在后,去查询DB前,使用分布式锁,保证有且只有一个线程去查询DB,并更新到缓存

    • 手动过期,缓存上不设置过期时间

什么是缓存预热?如何实现?

缓存预热指的是在系统启动的时候,先把查询结果预存到缓存中,一遍用户后面查询时可以直接从缓存中读取,以减少系统启动后或负载增加时对数据库或其他数据源的频繁访问,从而提高系统的性能和响应速度

实现缓存预热可以通过以下步骤

  1. 确定预热的数据:确定需要预热的数据集,可以是最长被访问的热点数据、重要的业务数据或其他需要提前加载到缓存的数据

  2. 编写预热脚本:编写一个预热脚本,通过读取数据源(如数据库、文件等)获取需要预热的数据,并将其存储到缓存中。可以使用缓存客户端提供的API来进行数据的读取和写入

  3. 在系统启动时执行预热脚本:将预热脚本配置在系统启动脚本中,确保在系统启动时执行预热操作。这可以通过应用程序启动时调用预热脚本的方式来实现

  4. 定时预热:除了在系统启动时进行预热之外,还可以定期执行预热操作,以确保缓存中的数据适中保持最新和热门。可以使用定时任务或调度工具来定期触发预热脚本

  5. 监控和日志记录:在预热过程中,监控缓存的状态和性能指标,以确保预热操作的顺利进行,同时,记录预热的日志,方便后续分析和排查问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值