其他
【我想进大厂】Redis夺命连环11问
The following article is from 科技缪缪 Author 科技缪缪
来源 | 科技缪缪
责编 | Jerry
说说Redis基本数据类型有哪些吧
字符串:redis没有直接使用C语言传统的字符串表示,而是自己实现的叫做简单动态字符串SDS的抽象类型。C语言的字符串不记录自身的长度信息,而SDS则保存了长度信息,这样将获取字符串长度的时间由O(N)降低到了O(1),同时可以避免缓冲区溢出和减少修改字符串长度时所需的内存重分配次数。 链表linkedlist:redis链表是一个双向无环链表结构,很多发布订阅、慢查询、监视器功能都是使用到了链表来实现,每个链表的节点由一个listNode结构来表示,每个节点都有指向前置节点和后置节点的指针,同时表头节点的前置和后置节点都指向NULL。 字典hashtable:用于保存键值对的抽象数据结构。redis使用hash表作为底层实现,每个字典带有两个hash表,供平时使用和rehash时使用,hash表使用链地址法来解决键冲突,被分配到同一个索引位置的多个键值对会形成一个单向链表,在对hash表进行扩容或者缩容的时候,为了服务的可用性,rehash的过程不是一次性完成的,而是渐进式的。 跳跃表skiplist:跳跃表是有序集合的底层实现之一,redis中在实现有序集合键和集群节点的内部结构中都是用到了跳跃表。redis跳跃表由zskiplist和zskiplistNode组成,zskiplist用于保存跳跃表信息(表头、表尾节点、长度等),zskiplistNode用于表示表跳跃节点,每个跳跃表的层高都是1-32的随机数,在同一个跳跃表中,多个节点可以包含相同的分值,但是每个节点的成员对象必须是唯一的,节点按照分值大小排序,如果分值相同,则按照成员对象的大小排序。 整数集合intset:用于保存整数值的集合抽象数据结构,不会出现重复元素,底层实现为数组。 压缩列表ziplist:压缩列表是为节约内存而开发的顺序性数据结构,他可以包含多个节点,每个节点可以保存一个字节数组或者整数值。
字符串对象string:int整数、embstr编码的简单动态字符串、raw简单动态字符串 列表对象list:ziplist、linkedlist 哈希对象hash:ziplist、hashtable 集合对象set:intset、hashtable 有序集合对象zset:ziplist、skiplist
Redis为什么快呢?
完全基于内存操作 C语言实现,优化过的数据结构,基于几种基础的数据结构,redis做了大量的优化,性能极高 使用单线程,无上下文的切换成本 基于非阻塞的IO多路复用机制
那为什么Redis6.0之后又改用多线程呢?
知道什么是热key吗?热key问题怎么解决?
提前把热key打散到不同的服务器,降低压力 加入二级缓存,提前加载热key数据到内存中,如果redis宕机,走内存查询
什么是缓存击穿、缓存穿透、缓存雪崩?
缓存击穿
加锁更新,比如请求查询A,发现缓存中没有,对A这个key加锁,同时去数据库查询数据,写入缓存,再返回给用户,这样后面的请求就可以从缓存中拿到数据了。 将过期时间组合写在value中,通过异步的方式不断的刷新过期时间,防止此类现象。
缓存穿透
缓存雪崩
针对不同key设置不同的过期时间,避免同时过期 限流,如果redis宕机,可以限流,避免同时刻大量请求打崩DB 二级缓存,同热key的方案。
Redis的过期策略有哪些?
惰性删除
定期删除
那么定期+惰性都没有删除过期的key怎么办?
volatile-lru:从已设置过期时间的key中,移出最近最少使用的key进行淘汰 volatile-ttl:从已设置过期时间的key中,移出将要过期的key volatile-random:从已设置过期时间的key中随机选择key淘汰 allkeys-lru:从key中选择最近最少使用的进行淘汰 allkeys-random:从key中随机选择key进行淘汰 noeviction:当内存达到阈值的时候,新写入操作报错
持久化方式有哪些?有什么区别?
RDB
AOF
当AOF持久化处于激活状态,服务器执行完写命令之后,写命令将会被追加append到aof_buf缓冲区的末尾 在服务器每结束一个事件循环之前,将会调用flushAppendOnlyFile函数决定是否要将aof_buf的内容保存到AOF文件中,可以通过配置appendfsync来决定。
everysec ##将aof_buf中内容写入到AOF文件,如果上次同步AOF文件时间距离现在超过1秒,则再次对AOF文件进行同步
no ##将aof_buf内容写入AOF文件,但是并不对AOF文件进行同步,同步时间由操作系统决定
怎么实现Redis的高可用?
主从架构
slave发送sync命令到master master收到sync之后,执行bgsave,生成RDB全量文件 master把slave的写命令记录到缓存 bgsave执行完毕之后,发送RDB文件到slave,slave执行 master发送缓存中的写命令到slave,slave执行
哨兵
初始化sentinel,将普通的redis代码替换成sentinel专用代码 初始化masters字典和服务器信息,服务器信息主要保存ip:port,并记录实例的地址和ID 创建和master的两个连接,命令连接和订阅连接,并且订阅sentinel:hello频道 每隔10秒向master发送info命令,获取master和它下面所有slave的当前信息 当发现master有新的slave之后,sentinel和新的slave同样建立两个连接,同时每个10秒发送info命令,更新master信息 sentinel每隔1秒向所有服务器发送ping命令,如果某台服务器在配置的响应时间内连续返回无效回复,将会被标记为下线状态 选举出领头sentinel,领头sentinel需要半数以上的sentinel同意 领头sentinel从已下线的的master所有slave中挑选一个,将其转换为master 让所有的slave改为从新的master复制数据 将原来的master设置为新的master的从服务器,当原来master重新回复连接时,就变成了新master的从服务器
能说说redis集群的原理吗?
节点
节点A收到客户端的cluster meet命令 A根据收到的IP地址和端口号,向B发送一条meet消息 节点B收到meet消息返回pong A知道B收到了meet消息,返回一条ping消息,握手成功 最后,节点A将会通过gossip协议把节点B的信息传播给集群中的其他节点,其他节点也将和B进行握手
槽slot
故障转移
了解Redis事务机制吗?
服务端收到客户端请求,事务以MULTI开始 如果客户端正处于事务状态,则会把事务放入队列同时返回给客户端QUEUED,反之则直接执行这个命令 当收到客户端EXEC命令时,WATCH命令监视整个事务中的key是否有被修改,如果有则返回空回复到客户端表示失败,否则redis会遍历整个事务队列,执行队列中保存的所有命令,最后返回结果给客户端