Redis面试总结

参照:https://mp.weixin.qq.com/s/t_of-qHBcKOiqicKBxyKPA
1、Redis 是什么?
Redis 是 C 语言开发的一个开源的(遵从 BSD 协议)高性能键值对(key-value)的内存数据库,可以用作数据库、缓存、消息中间件等。
它是一种 NoSQL(not-only sql,泛指非关系型数据库)的数据库。

  • 性能优秀,数据在内存中,读写速度非常快,支持并发 10W QPS。
  • 单进程单线程,是线程安全的,采用 IO 多路复用机制。
  • 丰富的数据类型,支持字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。
  • 支持数据持久化。可以将内存中数据保存在磁盘中,重启时加载。
  • 主从复制,哨兵,高可用。
  • 可以用作分布式锁。
  • 可以作为消息中间件使用,支持发布订阅。

Redis 支持五种数据类型,简单说下这五种数据类型吗?

首先 Redis 内部使用一个 redisObject 对象来表示所有的 key 和 value。
redisObject 最主要的信息如上图所示:type 表示一个 value 对象具体是何种数据类型,encoding 是不同数据类型在 Redis 内部的存储方式。
比如:type=string 表示 value 存储的是一个普通字符串,那么 encoding 可以是 raw 或者 int。
Redis的embstr编码方式和raw编码方式在3.0版本之前是以39字节为分界的,也就是说,如果一个字符串值的长度小于等于39字节,则按照embstr进行编码,否则按照raw进行编码。
而在3.2版本之后,则变成了44字节为分界。

redis的数据结构,分基本常用数据类型和底层实现结构

五大数据类型其底层数据结构:
1、字符串的底层数据结构是简单动态字符串SDS。以下特点:
① SDS 中 len 保存这字符串的长度,字符串长度时间复杂度O(1)。
② 空间预分配:字符串修改更少的内存重分配次数,通过预分配策略,即当修改之后字符串长度小于1MB的字符串自动分配字符串长度一倍的未使用空间。如:字符串长度13,其空间为13(len)+13(free)+1(末尾空字符串)。
修改后大于1MB,程序会自动分配1MB未使用空间。
③ 惰性空间释放,字符串缩短时,把缩短的字符串长度勇哥free字段记录下来,不进行内存重分配。当有需要是,真正释放未使用空间。
④ 二进制安全,保存,图片,视频,音频二进制流都可以。
⑤ 兼容部分C字符串函数。

2、列表的底层数据结构为双向链表(linkedlist)和压缩列表(ziplist)
后续版本对列表数据结构进行了改造,使用 quicklist 代替了 ziplist 和 linkedlist。

3、字典(哈希),底层结构为哈希表和压缩列表
①、字典在扩容或者压缩用到多字典表方式。逐渐进行rehash。
②、key哈希冲突,采用单向压缩列表存储。

4、ZSet(SortedSet) 有序集合,底层数据结构是跳跃表和压缩列表
①、跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。
跳表在链表的基础上,增加了多层级索引,通过索引位置的几个跳转,实现数据的快速定位,如下图所示:

当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis 就会使用整数集合作为集合键的底层实现,节省内存。

5、Set 集合的底层结构是哈希表和整型数组。

Redis过期键删除策略

1、惰性删除
概念:在获取某个 key 的时候,Redis 会检查下这个 key 是否过期了,如果过期了则删除,且不会返回任何东西。
优点:不会删除其他键,所以不会花费任何 CPU 时间在其他无关的过期键上。
缺点:大量过期键未被访问,无法自动释放,造成数据积压,可以看作是内存泄漏。

2、定期删除
概念:每隔默认的 100 ms 随机抽取一些设置了过期时间的 key,检查是否过期,如果过期就删除。
优点:
•限制操作执行的时长和频率来减少删除操作对 CPU 时间的影响。
•减少了因为过期键而带来的内存消费。
缺点:
•如果定时删除执行得太频繁,或者执行的时间太长,CPU 时间就会过多地消耗在删除过期键上面
•如果删除操作执行得太少,或者执行的时间太短,则会出现和惰性删除一样的问题,内存浪费或数据积压。

问题:为什么redis速度快?

1、基于内存实现
2、高效的底层数据结构
3、读写单线程模型(对于 Redis 的持久化、集群数据同步、异步删除等都是其他线程执行)
4、I/O 多路复用模型
并发处理连接。采用了 epoll + 自己实现的简单的事件框架。Redis 线程不会阻塞在某一个特定的监听或已连接套接字上,也就是说,不会阻塞在某一个特定的客户端请求处理上。正因为此,Redis 可以同时和多个客户端连接并处理请求,从而提升并发性。
5、Redis 全局 hash 字典
Redis 整体就是一个 哈希表来保存所有的键值对,无论数据类型是 5 种的任意一种。哈希表,本质就是一个数组,每个元素被叫做哈希桶,不管什么数据类型,每个桶里面的 entry 保存着实际具体值的指针。

而哈希表的时间复杂度是 O(1),只需要计算每个键的哈希值,便知道对应的哈希桶位置,定位桶里面的 entry 找到对应数据,这个也是 Redis 快的原因之一。
Redis 使用对象(redisObject)来表示数据库中的键值,当我们在 Redis 中创建一个键值对时,至少创建两个对象,一个对象是用做键值对的键对象,另一个是键值对的值对象。
也就是每个 entry 保存着 「键值对」的 redisObject 对象,通过 redisObject 的指针找到对应数据。
Redis 通过链式哈希 解决冲突:也就是同一个 桶里面的元素使用链表保存 。但是当链表过长就会导致查找性能变差可能,所以 Redis 为了追求快,使用了两个全局哈希表。用于 rehash 操作,增加现有的哈希桶数量,减少哈希冲突。
6、持久化方案
7、主从哨兵模式。

原文地址:https://www.cnblogs.com/stubborn-dude/p/14922700.html