redis面试题


谈谈对Redis的了解?

Redis:remote dictory server。C编写、支持网络、内存键值对数据库、可以持久化、多种语言API支持。

Redis使用场景

缓存、排行榜、计数器、好友关系,session服务器。

不适合:数据访问频率低、数据量大。

Redis数据类型

string、hash、list、set、zset。

ziplist

image-20220221180259164

  • zlbytes: ziplist的长度(单位: 字节),是一个32位无符号整数

  • zltail: ziplist最后一个节点的偏移量,反向遍历ziplist或者pop尾部节点的时候有用。

  • zllen: ziplist的节点(entry)个数

  • entry: 节点

  • zlend: 值为0xFF,用于标记ziplist的结尾

ziplist为了节省内存空间,将偏移量信息记录在每个节点里。

hash元素的个数很少(比如只有几十个),那么用这个结构来存储则可以在性能损失很小的情况下节约很多内存。

hash

键值对数量小、键和字符串长度小于64字节时,采用ziplist,否则hashtable。

zset为啥用跳表?

zset有序集合。数据量小时用ziplist:

  • 元素数量小于128
  • 所有元素长度小于64字节

否则用skiplist。

image-20220221180828518

对比红黑树?

复杂度都是log级别。容易实现。区间查找

缓存穿透

查找不存在的数据,所以不会缓存,一直访问数据库。解决:布隆过滤器。

缓存雪崩

缓存在一段时间内集中失效。

解决:

控制读写线程数量。

数据预热。

二级缓存。

过期时间加随机值。

怎么保证缓存和数据库数据的一致性?

先更新缓存,再更新数据库

image-20220221182236802

先更新数据库,再更新缓存

image-20220221182301310

先删除缓存,再更新数据库

image-20220221182357873

可能存在问题,如果不采用缓存过期时间,将一直是脏数据。

解决:

延时双删

(1)先淘汰缓存 (2)再写数据库(这两步和原来一样) (3)休眠1秒,再次淘汰缓存,这么做,可以将1秒内所造成的缓存脏数据,再次删除。

先更新数据库,再删除缓存

image-20220221182523570

还有一种降低概率的方式:延时删除。就是你更新完数据库后,删除缓存这个逻辑可以待会在执行,就是让线程睡一会,然后再更新缓存。

过期键清除策略

定时、访问到判断。

Redis哈希冲突解决办法

有两个哈希表,专供扩容使用。

  • 分配空间,二倍
  • 重新映射并拷贝
  • 释放原表

image-20220221201132126

每处理一个请求拷贝一个哈希桶。

Redis如何做内存优化

利用数据结构,减少key的数量。

减小key和value长度。

Redis线程模型

image-20220221202314743

Redis事务

  1. 事务开始 MULTI
  2. 命令入队
  3. 事务执行 EXEC

隔离性

redis单进程,执行事务时不会中断,天然隔离性。

原子性

单条指令原子,事务不保证原子性,没有回滚。任意命令执行失败不影响事务中其他命令。

Redis分区

将数据拆分,放到不同的Redis实例中。提升服务器性能和数据存储能力。

方案

  • 客户端分区:客户端决定存在哪。
  • 代理分区:加层代理,代理决定去哪里写、读。
  • 查询路由:访问任意redis实例,redis转发给正确的redis结点。

缺点

多个redis实例不能对集合直接求交集。

事务。

数据处理备份复杂。

动态扩容或者缩容。(客户端分区、代理分区不支持)

Redis并发竞争key问题

多个系统对一个key同时操作,执行顺序可能乱七八糟。

解决方法:分布式锁。消息队列。

为何用Redis不用map

  • 专用工具。
  • 可用几十个G来缓存
  • 分布式
  • 高并发
  • 丰富的数据结构,API
  • 管理缓存。

缓存降级

缓存失效或者缓存服务器挂掉时,不去访问是数据库,而是直接返回默认数据,减少对业务的影响程度。

Redis单线程

核心执行命令是单线程。

如网络数据读写和解析在6.0是多线程,还有备份线程之类的。

原因

单线程模式很多CPU时间花费在网络IO。

据说引入多线程后性能翻倍。

多线程是否有安全问题

Redis多线程仅仅用来处理网络读写和协议解析,命令还是单线程。

多副本

主从、读写分离。

哨兵

主服务器宕机,哨兵自动选举master并指向新的master。

redis slave节点作为备份节点不提供服务。

image-20220221211557539

哨兵如何工作

每个哨兵向其它master,slave,哨兵,定时发送PING。如果回复超过一定时间,就标记下线。如果被标记下线了,所有哨兵再次确认它,一定数量哨兵标记下线,就会确认下线。哨兵会由10s一次改为1s一次发送INFO。投票选取主节点。

选举master标准

网络、优先级、偏移(是否复制了更多的数据)、id号。

同步配置时,其他哨兵根据什么更新配置

会从新master那里得到一个版本号,每次切换的版本号唯一。如果第一个选举的哨兵切换失败了,其他哨兵等待一段时间后继续执行切换,会重新获取版本号。哨兵根据自己的版本号更新master配置。

为什么两个哨兵不行?

两个节点 A 说 B 下线,B 认为 A 下线,两个人互相说我连接不上你,没有定论。

集群

分布式存储。使用一致性哈希

集群节点最小配置三主三从,主节点提供读写操作,从节点备用,不提供请求,只是故障转移用。

image-20220221212013703

优点

无中心架构。

分布在多个节点,可扩展性。

高可用。

节点之间相互通信,相互选举,不再依赖sentinel

缺点

实现复杂,数据异步复制,不保证强一致性。slave纯备份,跨槽问题,多个key位于不同节点的问题。

通信

gossip协议,每个节点有一份元数据,出现变化,就会发给其他节点,不断通信。如故障信息,节点的变更,哈希槽信息。

Redis主从复制原理

image-20220221220050880

Redis主从,从节点过期数据

主节点读取时会检查是否超时,超时就del,异步发送给从节点。从节点不会主动删除超时数据

主节点定时删除。

或者使用scan命令,相当于访问了,会做过期检测。

主从复制因为网络停止了怎么样

它会自动重连,也有断点续传。维护一个偏移量。

主从架构数据会丢失吗

会。

  • 异步复制,master挂了。
  • 脑裂。master脱离网络,但是实际还在运行,其他slave成了master,client还没来得及切换,还在向原来的master写入数据,就丢失了。重新作为slave挂上时,数据会清空,重新复制。

如何解决

不可避免,只能减少。

设置数据复制和同步时间。client暂时写入本地,之后重新写入master。