Redis的key和value可以存储的最大值分别是多少
虽然Key的大小上限为512M,但是一般建议key的大小不要超过1KB,这样既可以节约存储空间,又有利于Redis进行检索,value的最大值也是512M,对于String类型的value值上限为512M,而集合、链表、哈希等key类型
单个元素的value上限也为512M。
Redis的主从模式,一主两从有几种方式,有什么优缺点
- 一个master下挂两个slave,优点是slave同步速度快,缺点是master压力大
- 一个master下挂一个slave,这个slave下再挂一个slave,优点是master压力小,缺点是后者slave同步速度慢
Redis的哨兵模式,当master挂了之后,是怎么从剩余的slave中选择新的master的
- 先比较优先级,默认为100,数字越小优先级越高,越容易成为master
- 再比较数据的新旧程度
- 比较id
Redis的集群模式的优缺点
- 方便扩容和缩容
- 方便快速定位,插入时是哪个槽,查询时就是哪个槽
- 有可能丢数据,某个master节点没来得及同步数据给slave时,master节点挂掉了
如何用Redis来实现一个抽奖程序,你会怎么实现?
- 利用set
- sadd添加uid进set
- smembers查看所有uid,
- randmember从set随机选一个uid(可以指定选1个,还是选3个),不会删除uid
- spop也有随机的效果,但是会删除uid
Redis有哪些数据结构?分别有哪些典型的应用场景?
Redis的数据结构有:
- 字符串:可以用来做最简单的数据,可以缓存某个简单的字符串,也可以缓存某个json格式的字符串,Redis分布式锁的实现就利用了这种数据结构,还包括可以实现计数器、分布式ID
- 哈希表:可以用来存储一些key-value对,更适合用来存储对象
- 列表:Redis的列表通过命令的组合,既可以当做栈,也可以当做队列来使用,可以用来缓存类似微信公众号、微博等消息流数据
- 集合:和列表类似,也可以存储多个元素,但是不能重复,集合可以进行交集、并集、差集操作,从而可以实现类似,我和某人共同关注的人、朋友圈点赞等功能
- 有序集合:集合是无序的,有序集合可以设置顺序,可以用来实现排行榜功能
Redis分布式锁底层是如何实现的?
- 首先利用setnx来保证:如果key不存在才能获取到锁,如果key存在,则获取不到锁
- 然后还要利用lua脚本来保证多个redis操作的原子性
- 同时还要考虑到锁过期,所以需要额外的一个看门狗定时任务来监听锁是否需要续约
- 同时还要考虑到redis节点挂掉后的情况,所以需要采用红锁的方式来同时向N/2+1个节点申请锁,都申请到了才证明获取锁成功,这样就算其中某个redis节点挂掉了,锁也不能被其他客户端获取到
Redis主从复制的核心原理
全量同步:
- 一般发生在从节点初始化的时候
- 从节点发送SYNC命令连接主节点
- 主节点接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件,并使用缓冲区replication buffer记录在这个过程中接收到的写命令
- 主节点BGSAVE命令执行完后,向所有从节点发送RDB文件,并在发送缓冲区replication buffer记录的写命令
- 从节点收到RDB文件后丢弃所有旧数据,载入收到的RDB文件中的数据
- 主节点RDB文件发送完毕后,开始向从节点发送缓冲区replication buffer中的写命令
- 从节点完成RDB的载入后,开始接收客户端命令,并执行来自主节点缓冲区replication buffer的写命令
增量同步:
Redis主节点每执行一个写命令就会向从节点异步发送相同的写命令,从节点接收并执行收到的写命令
缓存穿透、缓存击穿、缓存雪崩分别是什么
缓存中存放的大多都是热点数据,目的就是防止请求可以直接从缓存中获取到数据,而不用访问Mysql。
- 缓存雪崩:如果缓存中某一时刻大批热点数据同时过期,那么就可能导致大量请求直接访问Mysql了,解决办法就是在过期时间上增加一点随机值,另外如果搭建一个高可用的Redis集群也是防止缓存雪崩的有效手段
- 缓存击穿:和缓存雪崩类似,缓存雪崩是大批热点数据失效,而缓存击穿是指某一个热点key突然失效,也导致了大量请求直接访问Mysql数据库,这就是缓存击穿,解决方案就是考虑这个热点key不设过期时间
- 缓存穿透:假如某一时刻访问redis的大量key都在redis中不存在(比如黑客故意伪造一些乱七八糟的key),那么也会给数据造成压力,这就是缓存穿透,解决方案是使用布隆过滤器,它的作用就是如果它认为一个key不存在,那么这个key就肯定不存在,所以可以在缓存之前加一层布隆过滤器来拦截不存在的key
Redis和Mysql如何保证数据一致
- 先更新Mysql,再更新Redis,如果更新Redis失败,可能仍然不一致
- 先删除Redis缓存数据,再更新Mysql,再次查询的时候在将数据添加到缓存中,这种方案能解决1方案的问题,但是在高并发下性能较低,而且仍然会出现数据不一致的问题,比如线程1删除了Redis缓存数据,正在更新Mysql,此时另外一个查询再查询,那么就会把Mysql中老数据又查到Redis中
- 延时双删,步骤是:先删除Redis缓存数据,再更新Mysql,延迟几百毫秒再删除Redis缓存数据,这样就算在更新Mysql时,有其他线程读了Mysql,把老数据读到了Redis中,那么也会被删除掉,从而把数据保持一致
1、什么是redis?
redis是一个内存数据库,数据的读写操作都在内存中进行,因此速度非常快,常用于缓存,消息队列,分布式锁等场景。
2、Redis 和 Memcached 有什么区别?
首先两者都是内存数据库,性能非常高,但是redis 有更丰富的数据结构,数据可以持久化,支持集群,还有发布订阅、lua脚本、事务等功能,因此使用redis更多一点。
3、为什么用 Redis 作为 MySQL 的缓存?
redis兼具高性能、高并发两大特性,高性能是因为redis对于数据的读写操作都是在内存中进行的,因此性能非常高,高并发是指redis的单机吞吐率是10w,大约是mysql的10倍左右。
4、Redis 数据类型以及使用场景分别是什么?
String,主要用于缓存对象等;
list,主要用于消息队列,但是存在着生产者无法自动生成全局唯一ID,无法以消费组形式消费等问题;
hash,主要用于缓存对象等;
set,主要用于聚合计算,例如点赞,共同关注等;
zset,主要用于排行榜,电话,姓名排序等;
bitmap,主要用于记录签到情况,判断登录状态等;
hyperloglog,主要用于百万的数据统计等;
geo,主要用于存储位置;
stream,主要用于消息队列,相对于list,能解决list存在的问题。
5、五种常见的 Redis 数据类型是怎么实现?
String:sds
list:quicklist
hash:listpack 和 哈希表
set:哈希表和整数集合
zset:listpack 和 跳表
6、listpack是什么?
listpack也叫紧凑列表,是用一块连续的内存空间来保存数据,为了节省内存空间,还使用多种编码方式来表示不同长度的数据。
7、Redis 是单线程吗?
不是单线程,redis的单线程是指接收请求,解析请求,处理请求内容,返回结果这个过程是单线程的,但是redis还会在后台创建关闭文件,aof刷盘,释放内存的线程,主要也是因为这些操作比较费时。
8、Redis 单线程模式是怎样的?
当有多个客户端链接时,会采用IO多路复用,epoll wait会发现事件然后分发给事件处理器,然后通过连接事件处理函数、读事件处理函数、写事件处理函数分别进行处理,连接事件处理函数会调用accept接收连接,然后将已连接的socket添加到epoll中,并注册读事件处理函数或写事件处理函数,读事件处理函数会调用read接收数据,写事件处理函数会调用write发送数据。写事件处理函数会将准备好的的数据发送到队列中,读事件处理函数,也会在数据准备完成后添加到发送队列,然后同时将执行结果加入到缓存中。
9、Redis 采用单线程为什么还这么快?
redis 的大部分操作都在内存中完成,并采用了高效的数据结构;redis是单线程的,避免线程之间的竞争;redis采用了IO多路复用机制处理大量的客户端socket请求,因此速度比较快。
10、Redis 6.0 之前为什么使用单线程?Redis 6.0 之后为什么引入了多线程?
因为制约redis性能的一直不是cpu,因此单线程就足够,6.0之后考虑到redis的性能瓶颈受限于网络IO,因此引入多个IO线程处理网络请求,但对任务的处理过程仍然是单线程。
11、Redis 如何实现数据不丢失?
一共有三种方式, 第一种是RDB,其是将写命令以追加写的方式写入到文件中,第二种是RDB,它是将某一个时刻的数据以二进制的形式写入到磁盘,第三种是混合存储模式,集成了RDB和AOF的优点,是4.0新增的方式。
12、AOF 日志过大,会触发什么机制?
当写操作命令越来越多时,会导致AOF日志过大,此时会触发重写机制,缩小AOF日志的大小,举个例子:对同一个key值的两次value更新,只会保存最后一个。
13、重写 AOF 日志的过程是怎样的?
为了减少对于主线程的阻塞,这个过程通常是由子线程来完成的,为了保证主线程和子线程的内存数据的一致性,在子线程重写的过程时,会同时将数据发送到AOF缓冲区和AOF重写缓冲区,然后当子线程重写完成后,会给主线程发送指令,此时主线程会有两个操作,第一个操作是读取重写缓冲区的内容,将其加入到AOF文件中,第二个操作是将新的AOF文件覆盖原来的AOF文件,从而实现主线程和子线程的数据一致。
14、RDB 快照是如何实现的呢?
AOF日志是记录操作指令,因此当redis故障恢复时,一旦AOF文件过大,就会导致恢复缓慢,那么RDB就登场了,RDB是存储某一时刻的数据的二进制文件,这也当恢复时,采用RDB的效率会更高一点,直接将RDB文件读入内存即可。
15、RDB 在执行快照的时候,数据能修改吗?
可以的,关键在于写时复制技术,但此时RDB出来的数据就不是最新的数据了,只能当下一次快照时,才能读取到最新的数据。
16、为什么会有混合持久化?
RDB的优点在于恢复数据很快,但缺点在于快照的间隔很难保证,太快会导致对性能的负荷较大,太慢又会导致数据的缺失较多。
AOF的优点在于数据的缺失较少,但恢复数据的过程较慢。
因此为了结合二者的优点,在进行AOF日志重写的过程时,前半段会通过RDB的方式,后半段追加写入的内容采用AOF的方式,因此新的AOF日志前半段是RDB的格式,后半段是AOF的格式,优点就是让redis能更快的启动,但是缺点是让AOF的文件可读性变得较差。
17、Redis 如何实现服务高可用?
①主从复制,同时主节点进行写操作或读操作,从节点只进行读操作,读写分离。
②哨兵模式,为了避免主从复制出现问题手动恢复的情况出现,通过哨兵模式监控主从节点的工作情况,并进行故障转移。
③切片集群,当单机存储的缓存数据太大时,可以采用切片集群的方式将数据分散到多台机器上,从而避免对单机的负荷太大,提高读写性能。
18、集群脑裂导致数据丢失怎么办?
脑裂是指当主从断开后,由于只是网络问题,客户端认为当前主还未下线,故还在向主发送数据,但由于网络问题,这些数据都无法同步给从节点,这时哨兵发现主出问题,故将其中一个从升为新主,而主则降为从,此时进行全量同步时,就会导致旧主的缓冲区的数据全部丢失。
解决方法:通过设置参数,如延迟的时间和从连接的数目等,进而可以限制当主心跳监测不到时,禁止向原旧主发送数据,并且只将数据写到新主上。
19、Redis 使用的过期删除策略是什么?
惰性删除+定期删除策略。
惰性删除:不主动检测过期的key,只要当要使用时,发现其过期,旧删除该key
定时删除:按照一定的时间间隔删除过期key
定期删除:每隔一定时间,随机选取20个key检测是否过期,如果超过其1/4过期,则重新选择20个key进行检测,如果不超过1/4,则结束该过程
使用惰性删除+定期删除策略也是为了平衡cpu的使用以及对于内存的浪费。
20、Redis 内存满了,会发生什么?
当redis运行内存达到某一个阈值时,就会触发内存淘汰机制,一共有八种。
①不进行数据淘汰
②随机淘汰过期的键值
③优先淘汰更早过期的键值
④优先淘汰最久未被使用的设置了过期时间的键值
⑤优先淘汰最少使用的设置了过期时间的键值
⑥随机淘汰任意键值
⑦优先淘汰最久未被使用的键值
⑧优先淘汰最少使用的键值
21、LRU 算法和 LFU 算法有什么区别?
LRU是指淘汰最近最少使用的数据(时间)
LFU是指淘汰最近最少次数使用的数据(次数)
LRU是通过链表实现的,LFU是通过在结构体中增加数据的访问频次信息来实现的。
22、了解缓存雪崩、缓存击穿、缓存穿透吗?
缓存穿透是指该数据都不存在于数据库和缓存中,避免缓存穿透的方法主要有设置布隆过滤,或者缓存空对象来解决。
缓存击穿是指某热点数据过期,此时大量的请求打到数据库上,给数据库造成了巨大的压力,解决方法主要有互斥锁和逻辑过期,逻辑过期的一致性较差。
缓存雪崩主要是指大量的key同时失效造成的访问压力过大,解决方法主要有给不同的key随机设置过期时间,若是redis宕机引发的,可以设置集群或者增加多级缓存策略来解决。
23、如何保证数据库和缓存的数据一致性?
先更新数据库,再删除缓存。(也会出现数据不一致的情况,但由于更新缓存的速度远远快于写入数据库的速度,故出现的概率很低) 解决方案:可以通过加分布式锁或者加入较短的过期时间来保证
先删除缓存,再更新数据库。 会有极大可能发生数据不一致的情况,解决方案:延迟双删
24、redis的大key如何处理?
大key指的是key 所对应的value很大,它的危害主要有:会造成内存分布不均,会造成客户端超时阻塞,从客户端反应就是迟迟未能响应,可以通过scan命令或一些工具查找大key,解决方案可以通过分批次删除或异步删除来解决。
25、redis的管道有什么用?
可以解决多个命令执行时的网络等待
26、为什么redis不支持事务回滚?
设计理念主要是简单高效,支持事务回滚这种功能与设计理念相悖,其次发生错误主要是编程错误,主要是在开发阶段,生产环境中很少会出现,因此没必要设计这个功能。
27、如何使用redis实现分布式锁?
使用set nx ex 指令,优点在于性能高效,实现简单, 但是缺点在于超时时间不好设置,以及在集群模式下,很容易出现给主加锁,但是没同步到其他节点,就宕机了,仍然还能给新主加锁,就是所谓的分布式锁不可靠,因此在集群模式下,我们可以设置,当主节点和半数以上的从节点加锁成功才认为分布式锁加锁成功,否则就认为失败,回滚之前加锁成功的节点。