温故而知新- Redis篇【面试复习】

发布于:2024-05-21 ⋅ 阅读:(35) ⋅ 点赞:(0)

前言

2023-7-25 15:01:04

以下内容源自《【面试复习】》
仅供学习交流使用

版权

禁止其他平台发布时删除以下此话
本文首次发布于CSDN平台
作者是CSDN@日星月云
博客主页是https://blog.csdn.net/qq_51625007
禁止其他平台发布时删除以上此话

推荐

温故而知新- Redis篇

Redis的数据结构

string

list

hash

set

zset

hash的渐进式resize

zset的使用

redis中的zset

2023/7/28 16:37:28

Redis中的ZSet(有序集合)是一种特殊的数据结构,它是一种有序的字符串集合。每个成员都与一个分数(score)相关联,该分数用于对成员进行排序。在ZSet中,成员是唯一的,但是分数可以重复。

ZSet的主要特点是可以高效地插入、删除和查找成员,同时可以根据分数范围或成员来进行范围查找和排名操作。这使得ZSet在许多应用场景下非常有用,例如排行榜、计数器、优先级队列等。

常见的ZSet操作包括:

ZADD:向有序集合中添加一个成员及其对应的分数。
ZREM:从有序集合中删除一个成员。
ZSCORE:获取成员的分数。
ZRANK:获取成员在有序集合中的排名(按分数从低到高)。
ZREVRANK:获取成员在有序集合中的排名(按分数从高到低)。
ZRANGE:根据分数范围获取有序集合中的成员列表(按分数从低到高)。
ZREVRANGE:根据分数范围获取有序集合中的成员列表(按分数从高到低)。

下面是一个使用Redis的CLI(命令行界面)示例,演示如何创建和操作一个ZSet:

# 添加成员及其分数到有序集合"my_zset"
127.0.0.1:6379> ZADD my_zset 90 "Alice"
(integer) 1
127.0.0.1:6379> ZADD my_zset 85 "Bob"
(integer) 1
127.0.0.1:6379> ZADD my_zset 95 "Charlie"
(integer) 1

# 获取成员的分数
127.0.0.1:6379> ZSCORE my_zset "Alice"
"90.0"

# 获取成员在有序集合中的排名(按分数从低到高)
127.0.0.1:6379> ZRANK my_zset "Charlie"
(integer) 2

# 获取成员在有序集合中的排名(按分数从高到低)
127.0.0.1:6379> ZREVRANK my_zset "Bob"
(integer) 1

# 根据分数范围获取有序集合中的成员列表(按分数从低到高)
127.0.0.1:6379> ZRANGE my_zset 0 -1
1) "Bob"
2) "Alice"
3) "Charlie"
请注意,以上示例中使用的是默认情况下的升序排序。如果你想要降序排序,则可以使用ZREVRANGE等命令。

ZSet在Redis中是一个非常强大的数据结构,允许你进行高效的有序数据存储和检索。

zset为什么使用跳表

2023/7/28 16:38:44

ZSet在Redis中使用跳表(Skip List)的数据结构是因为跳表在有序集合这种场景下具有很好的性能特性。

跳表是一种随机化数据结构,它是有序链表的扩展,通过添加多级索引(跳跃)来提高查询效率。跳表允许在O(log n)的时间复杂度内进行插入、删除和查找操作,其中n是跳表中元素的数量。

对于有序集合(ZSet),要求元素按照分数进行排序,同时又需要高效地进行插入和删除操作。在这种情况下,传统的数据结构如红黑树虽然能够满足有序性的要求,但插入和删除操作的时间复杂度是O(log n),不如跳表高效。

跳表的优点包括:

查询高效:跳表允许通过多级索引快速定位元素,使得查询的时间复杂度较低。
插入和删除高效:跳表对插入和删除操作进行随机化优化,平均情况下时间复杂度为O(log n)。
简单易实现:相对于平衡二叉树等复杂数据结构,跳表的实现相对简单。
Redis中的ZSet使用跳表的结构来满足上述需求,使得ZSet在插入、删除和范围查询等操作上具有较高的性能。然而,值得注意的是,跳表也会带来一定的额外空间开销,因为它需要维护多级索引,但在Redis这种内存数据库中,通常更注重性能而不是空间的绝对节省。因此,跳表是Redis中实现有序集合的一个理想选择。

redis的事务

https://blog.csdn.net/Severn_Zhou/article/details/95235667

Redis的事务是一种将多个命令打包执行的机制,它允许一系列的命令按照顺序依次执行,同时保证这些命令在执行过程中不会被其他客户端的命令所中断。事务在Redis中通过MULTI、EXEC、WATCH、DISCARD等命令来实现。

以下是事务执行的基本过程:

  1. MULTI:在事务开始前,使用MULTI命令来标记事务的开始。
  2. 依次执行多个命令:在MULTI和EXEC之间,可以依次执行多个Redis命令,这些命令会被放入一个队列中,而不是立即执行。
  3. EXEC:执行EXEC命令来执行之前放入队列中的所有命令。Redis会依次执行队列中的命令,如果在执行过程中没有发生错误,那么所有命令都会被执行成功。否则,如果出现错误,比如其中一个命令失败,那么整个事务将会回滚,之前执行的命令都不会生效。
  4. WATCH:使用WATCH命令可以监视一个或多个键,如果在事务执行之前有其他客户端对这些键进行了修改,事务将会被中断。这可以用于乐观锁机制,保证事务的原子性。
  5. DISCARD:在事务执行之前,使用DISCARD命令可以取消当前事务,清空事务队列中的所有命令。

事务的特点:

  • 事务保证了一系列命令的原子性,要么全部执行成功,要么全部不执行。
  • 事务的执行是单线程的,不会被其他客户端的操作中断。
  • 事务不支持回滚点,一旦执行EXEC,整个事务会被执行,无法在执行过程中中途取消或回滚。

需要注意的是,虽然事务提供了原子性,但是在并发写入的情况下,使用WATCH命令时要小心竞态条件(race condition)。WATCH可以用于乐观锁控制,但是在实际使用中要根据具体场景谨慎使用,以避免潜在的问题。

另外,Redis的事务是一种逻辑上的事务,并非传统数据库中的ACID事务。在Redis中,没有像ROLLBACK这样的回滚操作,因为事务不会中途取消或回滚。事务更多地用于将多个命令打包执行,保证一系列操作的原子性。

使用redis如何设计分布式锁?

基于 Redis 实现的分布式锁,一个严谨的的流程如下:
1、加锁
SET lock_key $unique_id EX $expire_time NX
2、操作共享资源
3、释放锁:Lua 脚本,先 GET 判断锁是否归属自己,再DEL 释放锁

redis的持久化

Redis支持两种方式的持久化,分别是RDB(Redis Database File)和AOF(Append-Only File)。

RDB持久化: RDB持久化是将Redis在某个时间点上的数据快照(snapshot)保存到磁盘上的持久化方式。这个快照包含了Redis在生成快照时刻的所有数据,是一个二进制文件。RDB持久化适用于备份和数据恢复的场景。

RDB持久化的优点:

  • 对于数据恢复来说,RDB文件较小,加载速度较快。
  • RDB持久化是生成全量备份,适合用于灾难恢复。

RDB持久化的缺点:

  • 如果Redis意外宕机,会丢失最后一次快照之后的所有数据。
  • 生成快照时,Redis可能会阻塞客户端请求。

AOF持久化: AOF持久化是通过记录Redis服务器所执行的写命令来保证数据的持久性。AOF文件是一个追加写入的日志文件,它包含了Redis服务器执行的所有写操作指令。当Redis重启时,会重新执行AOF文件中的指令,从而将数据还原到原来的状态。
AOF持久化的优点:

AOF文件是一个追加写入的日志文件,不会导致像RDB那样的阻塞现象。
AOF持久化相对于RDB来说,数据丢失的风险更小,因为AOF记录的是每个写操作,所以在故障发生时,最多只会丢失最后一条写指令之后的数据。
AOF文件以纯文本方式记录,易于阅读和理解。
AOF持久化的缺点:

  • AOF文件通常比RDB文件大,因为它记录了每个写操作指令。
  • AOF文件的恢复速度可能比RDB慢,特别是当AOF文件很大时。

在Redis中,可以同时启用RDB和AOF持久化,以提供更高的数据安全性。也可以根据实际需求选择只启用其中一种持久化方式。同时,还可以根据配置选项来控制持久化的频率和策略,以平衡性能和数据持久化的要求。

如何保证缓存与数据库双写时的数据一致性

第一种方案:采用延时双删策略
具体的步骤就是:
先删除缓存;
再写数据库;
休眠500毫秒;
再次删除缓存。
第二种方案:异步更新缓存(基于订阅binlog的同步机制)
技术整体思路:
MySQL binlog增量订阅消费+消息队列+增量数据更新到redis

Redis常见性能问题和解决方案有哪些?

一、缓存穿透:就是查询一个压根就不存在的数据,即缓存中没有,数据库中也没有
解决方案:使用布隆过滤器,把数据先加载到布隆过滤器中,访问前先判断是否存在于布隆过滤器中,不存在代表这笔数据压根就不存在。
缺点:布隆过滤器是不可变的,可能一开始过滤器和数据库数据时一致的,后面数据库数据变了,或变多或变少,而对应的布隆过滤器的数据也要改变,这时会比较麻烦。
二、缓存击穿:数据库中有,缓存中没有。缓存击穿实际就是一个并发问题,一般来说查询数据,先查询缓存,有直接返回,没有再查询数据库并放到缓存中之后返回,但这种场景在并发情况下就会有问题,假设同时又100个请求执行上面
逻辑的代码,则可能会出现多个请求都查询数据库,因为大家同时执行,都查到了缓存中没有数据。
解决方案:加锁。如果是单机部署,则可以使用JVM级别的锁,如lock、synchronized。如果是集群部署,则需要使用分布式锁,如基于redis、zookeeper、mysql等实现的分布式锁。
三、缓存雪崩:大部分数据同时失效、过期,新的缓存又没来,导致大量的请求都去访问数据库而导致的服务器压力过大、宕机、系统崩溃。
解决方案:搭建高可用的redis集群,避免压力集中于一个节点;缓存失效时间错开,避免缓存同时失效而都去请求数据库。

redis的集群

最后

我们都有光明的未来

祝大家考研上岸
祝大家工作顺利
祝大家得偿所愿
祝大家如愿以偿
点赞收藏关注哦


网站公告

今日签到

点亮在社区的每一天
去签到