前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >根据面试经历,总结Redis面试题(实时更新)

根据面试经历,总结Redis面试题(实时更新)

作者头像
一写代码就开心
发布2022-05-09 10:36:26
5430
发布2022-05-09 10:36:26
举报
文章被收录于专栏:java和python

目录

欢迎关注B占---- 一天不写程序难受

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1Redis 使用场景:

数据高并发的读写 海量数据的读写 对扩展性要求高的数据

2 Redis缓存和map缓存区别

详细的区别:

1、Redis 可以用几十G内存来做缓存,Map不行,一般 JVM 也就分几个 G 数据就够大了

2、Redis 的缓存可以持久化,Map 是内存对象,程序一重启数据就没了

3、Redis 可以实现分布式的缓存,Map 只能存在创建它的程序里

4、Redis 可以处理每秒百万级的并发,是专业的缓存服务,Map 只是一个普通的对象

5、Redis 缓存有过期机制,Map 本身无此功能

6、Redis 有丰富的 API,Map 就简单太多了

3Redis支持的数据类型

Redis中数据是key-value形式,key为字符串类型,value可取类型:String字符串,Hash哈希表,List 列表,Set集合, Sorted Set 有序集合

4String 的业务场景

就是统计喜欢商品的个数,不喜欢商品的个数 喜欢就是incr 不喜欢就是dncr

5hash的业务场景

就是购物车的实现,一条命令就可以实现将商品加入购物车,还有新增商品的个数

在这里插入图片描述
在这里插入图片描述

6list的业务场景

里面最多存放2的32次减一个元素

就是我们看到的微博的推荐消息,我关注了很多的大V,他们发消息,我进入我的微博,就可以看到这些

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7set集合的使用场景

抽奖功能,我们需要点击参与抽奖,查看参与抽奖的总人数,随机抽取几个人

我们可以使用set集合实现以上的功能

以下是从set集合里面获取随机的2个元素

在这里插入图片描述
在这里插入图片描述

如果有一等奖,二等奖,等我们可以使用这个命令,抽取完从set集合里面删除

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8zset 集合的使用场景

设置的时候值里面加一个分数

热搜排序 视频热搜 书热卖

9Redis 底层是如何实现的

Redis是使用C语言进行编写的。我们在使用的时候就是将他作为缓存工具进行使用,Redis以solt(槽)作为数据存储单元,每个槽中可以存储N多个键值对。Redis中固定具有16384。理论上可以实现一个槽是一个Redis。每个向Redis存储数据的key都会进行crc16算法得出一个值后对16384取余就是这个key存放的solt位置。

一个String类型的value最大可以存储512M

10Redis的持久化策略

一共包含两种持久化策略:RDB 和 AOF rdb模式是默认模式,可以在指定的时间间隔内生成数据快照(snapshot),默认保存到dump.rdb文件中。当redis重启后会自动加载dump.rdb文件中内容到内存中。 rdb文件是一个紧凑文件,直接使用rdb文件就可以还原数据。 恢复数据的效率要高于aof

AOF默认是关闭的,需要在配置文件redis.conf中开启AOF。Redis支持AOF和RDB同时生效,如果同时存在,AOF优先级高于RDB(Redis重新启动时会使用AOF进行数据恢复) **AOF原理:**监听执行的命令,如果发现执行了修改数据的操作,同时直接同步到数据库文件中,同时会把命令记录到日志中。即使突然出现问题,由于日志文件中已经记录命令,下一次启动时也可以按照日志进行恢复数据, 相对RDB数据更加安全。

一个是快照,一个是追加文件的方式。

11什么时候会产生RDB文件

4 主从同步的时候,主服务器会生成rdb文件,将rdb文件给了从服务器

在这里插入图片描述
在这里插入图片描述

12如何恢复rdb文件

在这里插入图片描述
在这里插入图片描述

13如何开启aof(什么时候产生aof文件)

在redis.conf 文件中,将这个applandonly改为yes,开启aof 默认是不开启的

代码语言:javascript
复制
applandonly     yes

14两个持久化都开启,先执行哪个

先执行aof ,因为aof里面的数据是比rdb中的数据完整的

15rdb文件生成的底层步骤是什么

会产生一个子进程,这个子进程,将redis内存里面的数据先同步到一个区域,之后将这个区域的内容同步到dump.rdb 文件里面

在这里插入图片描述
在这里插入图片描述

16rdb底层为什么要使用一个临时区域,直接将内存中的数据同步到dump.rdb 文件不好嘛

如果直接同步过程中,redis挂了,那么到dump文件的数据就是不完整的,所以要先使用一个临时区域,即使在同步过程中挂了,dump文件里面的数据要么有,要么都没有

就是为了数据的完整性,一致性

17rdb持久化,为什么最后一次持久化会丢失数据

在这里插入图片描述
在这里插入图片描述

举个例子,如果20秒内,3个key进行变化就会执行rdb持久化,但是如果20秒内只有2个key变化,而且这个时候redis挂了,那么这两个key就丢失了

18AOF 文件过大,如何处理

如果aof文件过大,需要对这个文件进行重写,以达到压缩的目的; 重写是咋重写了,举个例子,我们往list里面存数据,每段时间都存一个数据,每存一个数据,都往aof文件追加一个写的命令,之后进行重写的时候,将3个命令合并为一个,那么这个就是达到了压缩的目的;

19主从复制的好处

1 读写分离 2 容灾快速恢复(我们读取数据的时候,有多个从机,一个挂了,另一个还可以使用)

20Redis中缓存穿透 缓存击穿 缓存雪崩

缓存穿透: redis中没数据,频繁的访问数据库,解决方法是将查询出来的空数据保存在redis中,或者加锁,高并发的时候,都抢锁,只有抢到的才可以查询数据库,这样就缓解了数据库的压力 缓存击穿 key是有过期时间 的,或者key重来没有被缓冲过,就是数据库中有,redis里面没有,当过期之后,出现大量的访问,之后访问数据库。解决的方法是 设置过期时间是永久,加锁(重入锁)都抢锁,只有抢到的才可以查询数据库,这样就缓解了数据库的压力 缓存雪崩: 在一段时间内容,出现大量缓存数据失效,这段时间内容数据库的访问频率骤增,这种情况称为缓存雪崩。解决方法,永久生效或者自定义时间,让让所有key尽量避开同一时间段,时间加一个随机数。

我们可以保证redis的高可用,使用redis的主从复制; 在服务系统使用本地缓冲,比如mybatis的二级缓冲; 使用限流降级,返回一些假数据,就是兜底数据

代码语言:javascript
复制
抢锁的事件,只有在redis里面拿不到数据的时候才有抢锁

21什么是缓存穿透?怎么解决?

缓存穿透:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。 解决方案:最简单粗暴的方法如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们就把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

22Redis事务

一个命令在运行时出错,还是会执行后面的命令,因为redis不支持事务的回滚, 如果命令本身出错,那么后面的是不会执行。

23加锁(重入锁)会造成线程阻塞,如何解决

为了解决死锁的问题,Redisson 内部提供了一个监控锁的看门狗,只要 Redisson 实例没被关闭就不断延长锁的有效时间,默认情况下,看门狗的检查锁的超时时间是 30 秒,检查时间是 10 秒(超时时间的三分之一),可以通过 setLockWatchdogTimeout 设置(只适用于未指定锁的时间的情况)

3、如果指定锁的时间,到达指定时间会自动解锁,因此设置的时间必须大于业务正常执行的时间,否则,业务没执行完,锁就会被释放

4、推荐使用指定时间的方式,省掉了续期操作,但需要合理设置过期时间,不能使锁过早释放

24Redis是单线程的,为什么性能高,读取快

1redis底层是c语言写的,C语言的执行速度是比较的快 2redis数据是存储在内存里面的,读取快,去除对于磁盘的io操作 3避免了上下文的切换 4 核心是基于io多路复用机制 5 redis底层有高效的数据存储结构

25io多路复用流程

在这里插入图片描述
在这里插入图片描述

26Redis中哨兵有什么作用?

Redis的哨兵就是帮助监控整个节点的,当节点主宕机等情况下,帮助重新选取主。

27redis 和 memecache 有什么区别?

memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型 redis的速度比memcached快很多 redis可以持久化其数据

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

28redis 如何做内存优化?

尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。 比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面。

29redis主从复制(一主二从)当从服务器挂掉,启动之后还是从的嘛

我们现在有一个一主二从的redis,当其中一个从的redis挂掉之后,在主的里面写入数据,重新启动这个挂掉的redis,这个redis其实是主的,需要你重新关联,并且只要关联之后,在主的里面重新写的数据会同步过来

30redis主从复制(一主二从)当主的挂掉,从服务器信息还是从

当主服务器挂掉之后,从服务器还是从的,当主服务重新启动,他还是主的,和之前一样

31主从复制的原理是什么

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

31.1全量复制

1 主节点fork出一个子进程,生成rdb文件 2 主节点通过网络将rdb文件传给从节点 3 从节点删除老数据,加载rdb文件,进行数据的同步

31.2部分复制

1 主节点和从节点都维护一个复制偏移量; 2 主节点里面维护一个缓冲区队列,当主节点的偏移量的大小大于了队列的长度,那么只能进行全量复制 3 服务器运行的id,每一个redis运行的时候,都会生成一个redisid,主从连接的时候,主节点会将自己的id发送给从节点,从节点将主节点的id进行保存。如果在同步的时候,会判断两个的id是不是一样,如果一样,会尝试的进行部分复制;

如果两个id不一样,只能进行全量复制;

在这里插入图片描述
在这里插入图片描述

32哨兵模式(就是自动将从机变为主机)

主从复制,万一主机挂掉,那么就需要从从机里面选择一个当做主机,但是我们不能手动输入命令 进行选择哪个从机变为主机,需要自动,所以就有了哨兵模式;

我们可以搭建哨兵集群,将sentinel.conf配置文件配置多份,进行启动,使用redis-sentinel 这个命令启动哨兵模式。

一主二从redis启动了,哨兵也启动了,当我们将主的redis手动挂了之后,我们查看2个从redis,发现有一个已经变成主了,这个就是哨兵的作用;

当我们把主的再启动,发现他变成从了,如今的主的就是刚选举的那个

33redis集群是如何分配6个节点的

在这里插入图片描述
在这里插入图片描述

34当一次性录入多个键值对,集群里面会报错,那咋办

在这里插入图片描述
在这里插入图片描述

35如何查看集群的状态

我们先进入一个redis,使用命令查询redis的状态

代码语言:javascript
复制
cluster  nodes
在这里插入图片描述
在这里插入图片描述

36一个集群里面,一个主从都挂了,那这个集群还可以使用嘛

在这里插入图片描述
在这里插入图片描述

37redis集群的好处

1 可以实现扩容 2 分摊压力 ,不能让请求过来,都在一个服务器上面 3 无中心化配置,就是随便连哪一个服务器,都可以进行集群的操作

38setnx 加锁之后,如果他睡着了,一直不放锁咋办

我们可以给这个锁设置一个时间,如果这个事件一过,那么就可以释放

在这里插入图片描述
在这里插入图片描述

39上锁之后,突然断电,无法设置过期时间,咋办

我们就要既要上锁,又要设置过期时间,同步进行

代码语言:javascript
复制
set   jj   jj   nx   ex   10

40redis存在线程安全的问题嘛

redis内部是单线程的,保障内部是串行操作 在外界使用的时候,要保证业务的执行顺序

41redis加锁了,但是任务执行时间大于设置的时间,咋办

我们给一个key加锁了,并且设置了过期时间,比如为10秒,但是这个任务执行的时间超过了10秒,那么达到10秒的时候,这个锁就释放了,其他线程就会操作这个key,这个是不允许的,这个就是问题,也就是一个任务还没有操作完这个key,其他线程就去操作这个key了,这个就是并发问题,如何解决?

使用redission 解决,也就是使用看门狗进行监听,当任务执行的时间大于过期的时间,自动给这个过期的时间进行续期;

41对一个key,加锁和释放锁不是同一个线程,这个咋处理?

为什么会出现这种情况:

就是一个线程任务加锁的时间比如是10秒,一过这个10秒就会过期,过期之后其他的线程就会抢这个锁,但是这个任务执行了15秒,当10秒的时候,时间一到锁过期,其他线程抢到了,让任务完成,就会删除这个锁,但是这个锁已经被其他的线程抢到,所以,你删除的就是其他线程的锁。

解决方法

在value里面加一个唯一的标识,就是UUID,删除锁的时候,判断这个UUID是不是一样,如果一样就可以进行删除。但是这个保障不了原子操作,因为判断的时候需要先查询出UUID,之后再删除,查询动作和删除动作,两步,保障不了原子性;

所以我们使用lua脚本,把两个弄为一个操作,就可以保障了原子性

42主从复制中,造成锁丢失

我们进行主从复制的时候,主节点里面数据加锁了,但是突然宕机了,这个时候数据还没有同步到从节点,所以这个锁就找不到了。这个情况咋办?

使用redlock(红锁)进行解决:这个专门处理异步复制出现的这种丢锁的问题

在这里插入图片描述
在这里插入图片描述

43redis 是内存数据库,如果宕机了,如何解决数据丢失的问题?

方案一:redis 拥有两种不同形式的持久化方法,它们都可以用小而紧凑的格式将存储 在内存中的数据写入硬盘:第一种持久化方法为时间点转储,转储操作既可以在“指定时间 段内有指定数量的写操作执行”这一条件被满足时执行,又可以通过条用两条转储到硬盘中 命令中的任何一条来执行;第二种持久化方法将所有修改了数据库的命令都写入一个只追加 文件里面,用户可以根据数据的重要程度,将只追加写入设置为从不同步、每秒同步一次或 者每写入一个命令就同步一次。 方案二:使用 redis 集群。Redis 实现了主从复制的特性:执行复制的从服务器会连接上主服 务器,接受主服务器发送的整个数据库的初始副本;之后主服务器执行的写命令,都会被发 送给所有连接着的从服务器去执行,从而实时地更新从服务器的数据集。因为从服务器包含 的数据会不断地进行更新,所以客户端可以向任意一个从服务器发送读请求,以此来避免对 主服务器进行集中式的访问

44redis的集群策略

在这里插入图片描述
在这里插入图片描述

45哈希表是咋存储数据的

一维数组 + 二维的链表(key—value)

46redis 里面的set一个数据的底层实现的流程是什么

比如我们set jing fu 键是jing 值是fu

我们一执行这个语句,首先对jing进行一个hash运算,运算得到的值和redis底层数组的长度进行取余运算,得到一个值,这个值就是数组的下标位置,之后将键值对存储在这个下标关联的链表上面,以键值对的形式存储

以上就是执行这个语句,redis底层执行的流程

47什么是跳表

在这里插入图片描述
在这里插入图片描述

48缓冲出现问题:缓冲数据库双写不一致

48.1什么叫缓冲数据库双写不一致

在这里插入图片描述
在这里插入图片描述

就是在高并发的情况下,比如秒杀活动,一个线程先更新了数据库,准备更新redis缓冲的时候,卡住了,这时候另一个线程也更新了数据库,并且人家立马更新了redis缓冲,这个时候你缓过来了,也更新了redis,这个时候数据库里面的数据和redis里面的数据就不一样的了,这个就是缓冲数据库双写不一致;

48.2解决

1 更新完缓冲,里面设置过期时间

一般缓存是这样的: 1:读的顺序是先读缓存,后读数据库 2:写的顺序是先写数据库,然后写缓存 3:每次更新了相关的数据,都要把该缓存清理掉 4:为了避免极端条件下造成的缓存与数据库之间的数据不一致,缓存需要设置一个失效时间。时间到了,缓存自动被清理,达到缓存和数据库数据的“最终一致性”

49如何查看redis的版本(命令)

两个方法

代码语言:javascript
复制
./redis-server -v
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
进入redis的客户端

info
在这里插入图片描述
在这里插入图片描述

50 你理解的分布式锁?

在这里插入图片描述
在这里插入图片描述

51redis除了做缓冲,还可以做什么

可以做文章的推荐,可以实现购物车,可以实现抽奖活动等

52对分布式锁的实战

52.1背景

我们写两个springboot项目,里面的代码都一样,都是操作同一个redis,比如redis里面,我们设置一个键值对,count = 100 ,这个就是商品的个数,每执行一个接口,就会操作这个键,让他减一;

两个项目的端口不一样,但是操作同一个键;

52.2没有加锁

在没有对这段逻辑加锁的情况下,相当于单级版,这个业务是可以执行下去的,也就是在浏览器输入这个接口,根据端口不一样,都可以实现对键的值减一操作;

但是在高并发下,会出现超卖情况,就相当于卖票一样,为什么会出现超卖的情况呢?

没有加锁情况,会出现的问题(超卖情况)

代码语言:javascript
复制
因为是操作同一个键,都要对这个键进行减一操作,多个线程都拿到了这个键,
比如,这个count的值变为1了,A线程拿到这个count了,准备对这个值进行减
一操作,但是他卡机了,这个时候B线程来了,他也拿到了count,发现值是1,
就进行了减一操作,这个时候count值为0了,这个时候A线程不卡了,
回来了,里面对count值进行减一操作,这个时候count值就变为-1了,
这个就是高并发情况下,出现的问题,我们就需要解决这个问题

为了解决这个问题,就需要加锁

52.3jvm层的单机版加锁

52.3.1synchronized

这个是jvm层的关键字,这个就是一个代码块,就可以实现对一段逻辑的加锁

52.3.2ReentrantLock

这个是一个类,

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

52.3.3使用哪个锁

这个要看业务 synchronized 是这个锁,必须得等里面的业务完成,才会释放锁,其他的线程在外面就得等,这个造成的情况就是外面的线程积压,万一里面一直不释放锁咋办。 ReentrantLock 这个锁是

在这里插入图片描述
在这里插入图片描述

52.3用Nginx部署这两个项目,变为分布式项目

在这里插入图片描述
在这里插入图片描述

以后我们在浏览器访问Nginx的ip就可以访问两个项目了,以上就相当于分布式的项目了。

项目里面的锁,只在自己的服务器里面有用,不会跑到其他的服务器里面

52.4出现的问题

我们项目里面只是有单级锁,但是现在是分布式项目,这样多线程的情况,会出现超卖的情况,也就说明了,单级锁是不能解决分布式项目的,所以,我们需要分布式锁

52.5redis加分布式锁

我们的业务逻辑,就把jvm层的锁去掉了,我们要使用分布式锁了,我们redis里面有一个命令setnx 这个命令就是加锁,我们先定义一个锁名称,作为键,值为当前的线程名称,拿到这个锁,返回ture,没有返回false,加锁之后,执行完逻辑,我们要释放锁,我们咋释放,就是删除锁;

52.6当前情况,分布式锁会出现的问题

1 在解锁之前,当前线程程序出现错误了,根本就没有执行解锁的命令; 解决: 就是对当前的逻辑进行try catch ,在finally里面进行强制删除锁;

2 在逻辑里面对键进行减一操作之后,突然服务器宕机了,根本没有走到finally里面,也就是锁根据没有释放,就宕机了,这个情况咋办?

解决:在加锁的时候,对这个锁加一个过期的时间,即使宕机了,只要过期时间一到,那么这个锁就被删除了

3 加锁,加过期的时间是两个步骤,万一还没有来得及加过期的时间,就宕机了,咋办 解决: 使用一个命令,保障原子性,就是加锁和加过期的时间是同一时间进行的。

4 如果A 线程设置的锁的时间是10秒,但是查询运行了15秒,到10秒的时候,锁已释放,其他线程就拿到了锁,到了15秒,就删除了其他的线程的锁,这个就是问题,删除其他线程的锁;

解决:只能删除自己的锁,就需要判断是不是自己的锁; 就需要将锁的值拿出来,进行判断是不是当前线程的值,一样才可以删除

5 判断是不是当前的锁,这个判断和解锁不是原子性的,就和那个加锁和加过期时间一样,必须保障原子性

解决: 1 可以使用lua脚本; 2 使用redis支持的事务;

52.7redis集群主从复制,主从复制出现异步复制造成锁丢失

以上解决了锁出现的一些问题,但是这个分布式锁还是有一些问题,比如

1 你咋找到逻辑时间会在过期时间之内,所以我们希望续期,确保业务在过期时间之内 2 主从复制出现异步复制造成锁丢失

以上的这两个问题,我们一般很难自己解决,所以使用redisson了

解决: 首先在项目里面写一个配置类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

以上的finally里面这样写,有可能出错,解锁和当前锁是不一样的

在这里插入图片描述
在这里插入图片描述

我们就要完善这个finally里面的写法

在这里插入图片描述
在这里插入图片描述

53redis默认的内存是多少?在哪里查看?如何设置修改

我们可以打开redis的配置文件redis.conf

在这里插入图片描述
在这里插入图片描述

一般这个是注释掉的,这个就是配置这个redis的最大的内存是多少,那他注释掉的话,代表的什么呢?

在这里插入图片描述
在这里插入图片描述

默认redis保障最大的性能,默认最大的内存

在这里插入图片描述
在这里插入图片描述

在配置文件里面配置那个地方,就可以修改

也可以使用命令

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

54 redis内存满了,出现oom了,咋办

我们手动设置这个最大内存为1b,当设置数据的时候,看看出现啥情况

在这里插入图片描述
在这里插入图片描述

以上就会报错,报出oom错误,所以,我们不能什么都往这个里面存,默认配置最大内存为物理机内存或者他的四分之三

为了不出现 oom ,那么就有了内存淘汰机制

55redis的过期删除策略

定期删除:redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。

惰性删除: 也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。

56redis的内存淘汰机制

采用定期删除+惰性删除就没其他问题了么?

不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制

代码语言:javascript
复制
在redis.conf中有一行配置

maxmemory-policy volatile-lru

该配置就是配内存淘汰策略的(什么,你没配过?好好反省一下自己)

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)
中挑选最近最少使用的数据淘汰

volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中
挑选将要过期的数据淘汰

volatile-random:从已设置过期时间的数据集(server.db[i].expires)
中任意选择数据淘汰

allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

no-enviction(驱逐):禁止驱逐数据,新写入操作会报错

ps:如果没有设置 expire 的key, 不满足先决条件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行为, 和 noeviction(不删除) 基本上一致。

57 1~2亿条数据需要缓存,请问如何设计这个存储案例

·单机单台100%不可能,肯定是分布式存储,用redis如何落地?

哈希取余分区

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
2亿条记录就是2亿个k,v,我们单机不行必须要分布式多机,
假设有3台机器构成一个集群,用户每次读写操作都是根据公式:

hash(key) % N个机器台数,计算出哈希值,用来决定数据映射到哪一个节点上。
**优点:**
  简单粗暴,直接有效,只需要预估好数据规划好节点,
  例如3台、8台、10台,就能保证一段时间的数据支撑。
  使用Hash算法让固定的一部分请求落到同一台服务器上
  ,这样每台服务器固定处理一部分请求(并维护这些请求的信息),
  起到负载均衡+分而治之的作用。
**缺点:**
   原来规划好的节点,进行扩容或者缩容就比较麻烦了额,不管扩缩,
   每次数据变动导致节点有变动,映射关系需要重新进行计算,
   在服务器个数固定不变时没有问题,如果需要弹性扩容或故障停机的情况下,
   原来的取模公式就会发生变化:Hash(key)/3会变成Hash(key) /?。
   此时地址经过取余运算的结果将发生很大变化,
   根据公式获取的服务器也会变得不可控。
   
某个redis机器宕机了,由于台数数量变化,
会导致hash取余全部数据重新洗牌。

一致性哈希算法分区

为什么会出现这个

设计目标是为了解决 分布式缓存数据变动和映射问题,某个机器宕机了,分母数量改变了,自然取余数不OK了。

·提出一致性Hash解决方案。 目的是当服务器个数发生变动时, 尽量减少影响客户端到服务器的映射关系

算法构建一致性哈希环

1 一致性哈希环

代码语言:javascript
复制
    一致性哈希算法必然有个hash函数并按照算法产生hash值,
    这个算法的所有可能哈希值会构成一个全量集,
    这个集合可以成为一个hash空间[0,2^32-1],
    这个是一个线性空间,但是在算法中,
    我们通过适当的逻辑控制将它首尾相连(0 = 2^32),
    这样让它逻辑上形成了一个环形空间。
 
   它也是按照使用取模的方法,前面笔记介绍的节点取模法是对节点(服务器)
   的数量进行取模。而一致性Hash算法是对2^32取模,简单来说,
   一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环,
   如假设某哈希函数H的值空间为0-2^32-1(即哈希值是一个32位无符号整形),
   整个哈希环如下图:整个空间按顺时针方向组织,圆环的正上方的点代表0,
   0点右侧的第一个点代表1,以此类推,2、3、4、……直到2^32-1,
   也就是说0点左侧的第一个点代表2^32-1, 0和2^32-1在零点中方向重合,
   我们把这个由2^32个点组成的圆环称为Hash环。
在这里插入图片描述
在这里插入图片描述

2 服务器IP节点映射 节点映射 将集群中各个IP节点映射到环上的某一个位置。 将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。假如4个节点NodeA、B、C、D,经过**IP地址的哈希函数计算(**hash(ip)),使用IP地址哈希后在环空间的位置如下:

在这里插入图片描述
在这里插入图片描述

3 key落到服务器的落键规则 当我们需要存储一个kv键值对时,首先计算key的hash值,hash(key),将这个key使用相同的函数Hash计算出哈希值并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上。 如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:根据一致性Hash算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上。

在这里插入图片描述
在这里插入图片描述

4 缺点 ·一致性哈希算法的数据倾斜问题

Hash环的数据倾斜问题 一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题, 例如系统中只有两台服务器:

在这里插入图片描述
在这里插入图片描述

·哈希槽分区

1 为什么出现

哈希槽实质就是一个数组,数组[0,2^14 -1]形成hash slot空间。

一个集群只能有16384个槽,编号0-16383(0-2^14-1)。这些槽会分配给集群中的所有主节点,分配策略没有要求。

在这里插入图片描述
在这里插入图片描述

58 redis 搭建集群的步骤

前提是 redis的配置文件里面都开启了集群相关的配置–cluster-enabled yes 1 启动6个redis,要将这6个节点作为集群,而且还是3主3从,我们进入启动了一个redis里面,执行命令

代码语言:javascript
复制
redis-cli --cluster create 192.168.40.129:6381 192.168.40.129:6382 192.168.40.129:6383 192.168.40.129:6384 192.168.40.129:6385 192.168.40.129:6386 --cluster-replicas 1

redis 集群主从扩容的步骤

比如已经有3主3从了,我们想要实现扩容,那么我们首先是再创建两个redis,一个为主,一个为从。

两个新的redis都启动之后;

我们进入新的主节点的redis里面,执行命令,将自己放到集群里面

代码语言:javascript
复制
redis-cli --cluster add-node 自己实际IP地址:6387   自己实际IP地址:6381

6387 就是将要作为master新增节点
6381 就是原来集群节点里面的领路人,
相当于6387拜拜6381的码头从而找到组织加入集群

以上只是将6387加入到集群里面,还没有分配槽位了,刚进去的时候,6387里面的槽位还是空的;

我们进入旧的主节点里面,执行命令,重新分配槽位

代码语言:javascript
复制
重新分派槽号
命令:redis-cli --cluster reshard IP地址:端口号
redis-cli --cluster reshard 192.168.40.129:6381

这个不是打乱分配的,是旧的节点都分一写槽位给新的;

之后执行命令,将从机分配到新的主节点上面;

redis 集群主从缩容的步骤

1 先删除一个主从的从节点 2 重新分配槽位,将主的槽位给了其他的主 3 之后删除主节点

那么为什么任意一个节点挂了(没有从节点)这个集群就挂了呢?

-> 因为集群内置了16384个slot(哈希槽),并且把所有的物理节点映射到了这16384[0-16383]个slot上,或者说把这些slot均等的分配给了各个节点。当需要在Redis集群存放一个数据(key-value)时,redis会先对这个key进行crc16算法,然后得到一个结果。再把这个结果对16384进行求余,这个余数会对应[0-16383]其中一个槽,进而决定key-value存储到哪个节点中。所以一旦某个节点挂了,该节点对应的slot就无法使用,那么就会导致集群无法正常工作。

为什么 Redis集群至少需要3个节点

Redis集群至少需要3个节点,因为投票容错机制要求超过半数节点认为某个节点挂了该节点才是挂了,所以2个节点无法构成集群。 要保证集群的高可用,需要每个节点都有从节点,也就是备份节点,所以Redis集群至少需要6台服务器。

redis集群最大部署多少个节点

16384

每一个节点一个槽位,集群一共16384个节点

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 1Redis 使用场景:
  • 2 Redis缓存和map缓存区别
  • 3Redis支持的数据类型
  • 4String 的业务场景
  • 5hash的业务场景
  • 6list的业务场景
  • 7set集合的使用场景
  • 8zset 集合的使用场景
  • 9Redis 底层是如何实现的
  • 10Redis的持久化策略
  • 11什么时候会产生RDB文件
  • 12如何恢复rdb文件
  • 13如何开启aof(什么时候产生aof文件)
  • 14两个持久化都开启,先执行哪个
  • 15rdb文件生成的底层步骤是什么
  • 16rdb底层为什么要使用一个临时区域,直接将内存中的数据同步到dump.rdb 文件不好嘛
  • 17rdb持久化,为什么最后一次持久化会丢失数据
  • 18AOF 文件过大,如何处理
  • 19主从复制的好处
  • 20Redis中缓存穿透 缓存击穿 缓存雪崩
  • 21什么是缓存穿透?怎么解决?
  • 22Redis事务
  • 23加锁(重入锁)会造成线程阻塞,如何解决
  • 24Redis是单线程的,为什么性能高,读取快
  • 25io多路复用流程
  • 26Redis中哨兵有什么作用?
  • 27redis 和 memecache 有什么区别?
  • 28redis 如何做内存优化?
  • 29redis主从复制(一主二从)当从服务器挂掉,启动之后还是从的嘛
  • 30redis主从复制(一主二从)当主的挂掉,从服务器信息还是从
  • 31主从复制的原理是什么
    • 31.1全量复制
      • 31.2部分复制
      • 32哨兵模式(就是自动将从机变为主机)
      • 33redis集群是如何分配6个节点的
      • 34当一次性录入多个键值对,集群里面会报错,那咋办
      • 35如何查看集群的状态
      • 36一个集群里面,一个主从都挂了,那这个集群还可以使用嘛
      • 37redis集群的好处
      • 38setnx 加锁之后,如果他睡着了,一直不放锁咋办
      • 39上锁之后,突然断电,无法设置过期时间,咋办
      • 40redis存在线程安全的问题嘛
      • 41redis加锁了,但是任务执行时间大于设置的时间,咋办
      • 41对一个key,加锁和释放锁不是同一个线程,这个咋处理?
      • 42主从复制中,造成锁丢失
      • 43redis 是内存数据库,如果宕机了,如何解决数据丢失的问题?
      • 44redis的集群策略
      • 45哈希表是咋存储数据的
      • 46redis 里面的set一个数据的底层实现的流程是什么
      • 47什么是跳表
      • 48缓冲出现问题:缓冲数据库双写不一致
        • 48.1什么叫缓冲数据库双写不一致
          • 48.2解决
          • 49如何查看redis的版本(命令)
          • 50 你理解的分布式锁?
          • 51redis除了做缓冲,还可以做什么
          • 52对分布式锁的实战
            • 52.1背景
              • 52.2没有加锁
                • 52.3jvm层的单机版加锁
                  • 52.3.1synchronized
                  • 52.3.2ReentrantLock
                  • 52.3.3使用哪个锁
                • 52.3用Nginx部署这两个项目,变为分布式项目
                  • 52.4出现的问题
                    • 52.5redis加分布式锁
                      • 52.6当前情况,分布式锁会出现的问题
                        • 52.7redis集群主从复制,主从复制出现异步复制造成锁丢失
                        • 53redis默认的内存是多少?在哪里查看?如何设置修改
                        • 54 redis内存满了,出现oom了,咋办
                        • 55redis的过期删除策略
                        • 56redis的内存淘汰机制
                        • 57 1~2亿条数据需要缓存,请问如何设计这个存储案例
                          • 哈希取余分区
                            • 一致性哈希算法分区
                              • 为什么会出现这个
                              • 算法构建一致性哈希环
                            • ·哈希槽分区
                            • 58 redis 搭建集群的步骤
                            • redis 集群主从扩容的步骤
                            • redis 集群主从缩容的步骤
                            • 那么为什么任意一个节点挂了(没有从节点)这个集群就挂了呢?
                            • 为什么 Redis集群至少需要3个节点
                            • redis集群最大部署多少个节点
                            相关产品与服务
                            云数据库 Redis
                            腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档