Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Latest commit

 

History

History
History
132 lines (96 loc) · 9.15 KB

File metadata and controls

132 lines (96 loc) · 9.15 KB
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
(PS扫描[首页里面的二维码](README.md)进群分享我自己在看的技术资料给大家希望和大家一起学习进步!)
下面是主要是自己看完Redis设计与实现》,《Redis深度历险核心原理与应用实践为了更好得掌握Redis网上找了一些面试题查阅书籍和资料后写的解答
#### [1.Redis常见的数据结构有哪些?](#Redis常见的数据结构有哪些?)
#### [2.谈一谈你对Redis中简单动态字符串的理解?](#谈一谈你对Redis中简单动态字符串的理解?)
#### [3.谈一谈你对Redis中hash对象的理解?](#谈一谈你对Redis中hash对象的理解?)
#### [4.谈一谈你对Redis中List的理解?](#谈一谈你对Redis中List的理解?)
#### [5.谈一谈你对Redis中Set的理解?](#谈一谈你对Redis中Set的理解?)
#### [6.谈一谈你对Redis中有序集合ZSet的理解?](#谈一谈你对Redis中有序集合ZSet的理解?)
#### [7.布隆过滤器是什么?](#布隆过滤器是什么?)
### Redis常见的数据结构有哪些
Redis中主要的数据结构有String字符串Hash哈希表List列表Set集合ZSet有序集合
### 谈一谈你对Redis中简单动态字符串的理解
Redis中的简单动态字符串其实是对C语言中的字符串的封装和优化
##### 因为C语言的字符串有两个缺点
1.不是二进制安全的因为字符串以空字符作为结束的标志字符串中间不能有空字符)。
2.频繁修改一个字符串时会涉及到内存的重分配比较消耗性能。(Redis中的简单动态字符串会有内存预分配和惰性空间释放)。
所以Redis中的简单动态字符串结构除了包含一个字符数组的属性还包含数组的长度数组的实际使用长度等属性通过增加长度属性可以保证字符串是二进制安全的从而可以保存任意类型的数据例如一张图片对象序列化后的数据等等
##### 字符串使用场景如下
1.字符串可以保存一些字符串数据也可以保存一些数字类型的数据所以可以使用INCR, DECR, INCRBY对数字进行加减所以可以把字符串当成计数器使用
2.同时因为在C语言中每个字符是一个字节是8个二进制位所以可以把简单动态字符串作为一个位数组来使用通过setbitgetbit命令来对位数组进行赋值取值可以以很小的空间来保存用户一年的每日签到数据以及Redis中的布隆过滤器也是通过位数组来实现的
##### 字符串的底层存储
在Redis中每一个Value都是一个Redis对象对应的都是RedisObject结构在RedisObject结构中保存了对象的类型type底层的编码encoding等一些属性也拥有一个ptr指针指向对象具体的存储地址
```
struct RedisObject {
int4 type;
int4 encoding;
int24 lru;
int32 refcount;
void *ptr;
} robj;
```
在Redis中字符串有两种存储方式int编码embstr编码和raw编码
##### int编码
当value是一个整数并且可以使用long类型8字节来表示时那么会属于int编码ptr直接存储数值。(并且Redis会进行优化启动时创建0~9999的字符串对象作为共享变量。)
##### embstr和raw编码
两种存储方式下都RedisObject和SDS结构(简单动态字符串)来存储字符串区别在于embstr对象用于存储较短的字符串embstr编码中RedisObject结构与ptr指向的SDS结构在内存中是连续的内存分配次数和内存释放次数均是一次而raw编码会分别调用两次内存分配函数来分别创建RedisObject结构和SDS结构
### 谈一谈你对Redis中hash对象的理解
在Redis中value可以是一个hash表底层编码可以是ziplist也可以是hashtable默认情况下当元素小于512个时底层使用ziplist存储数据
#### ziplist
元素保存的字符串长度较短且元素个数较少时(小于64字节个数小于512),出于节约内存的考虑hash表会使用ziplist作为的底层实现ziplist是一块连续的内存里面每一个节点保存了对应的key和value然后每个节点很紧凑地存储在一起优点是没有冗余空间缺点插入新元素需要调用realloc扩展内存。(可能会进行内存重分配将内容拷贝过去也可能在原有地址上扩展)。
#### hashtable
元素比较多时就会使用hashtable编码来作为底层实现这个时候RedisObject的ptr指针会指向一个dict结构dict结构中的ht数组保存了ht[0]和ht[1]两个元素通常使用ht[0]保存键值对ht[1]只在渐进式rehash时使用hashtable是通过链地址法来解决冲突的table数组存储的是链表的头结点添加新元素首先根据键计算出hash值然后与数组长度取模之后得到数组下标将元素添加到数组下标对应的链表中去)。
```
struct dict {
int rehashindex;
dictht ht[2];
}
struct dictht {
dictEntry** table; // 二维
long size; // 第一维数组的长度
long used; // hash 表中的元素个数 ...
}
typedef struct dictEntry {
//键
void *key;
//值,可以是一个指针,也可以是一个uint64_t整数,也可以是int64_t的整数
union {
void *val;
uint64_tu64;
int64_ts64;
} v
//指向下一个节点的指针
struct dictEntry *next;
} dictEntry
```
#### 渐进式rehash
进行当负载因子>=1会进行哈希表扩展操作如果是在执行BGSAVE或BGREWRITEAOF命令期间那么需要>=5才会进行扩展)。
进行当负载因子<0.1会进行哈希表收缩操作
因为直接一次性完成rehash会对性能产生影响所以可以渐进式rehash具体执行步骤是:
##### 初始化
1.首先将对dict结构中ht[1]哈希表分配空间(大小取决于最接近实际使用空间的2的n次方幂),然后将rehashindex属性设置为0
##### 转移
2.然后每次对ht[0]中的元素查找修改添加时除了执行指定操作外还会将对应下标的所有键值对rehash到ht[1],并且会将rehashindex+1
##### 更改指针指向
3.当ht[0]中所有键值对都是rehash到ht[1]中后那么会ht[1]和ht[0]的指针值进行交换将rehashindex设置为-1代表rehash完成
整个rehash期间查找更新删除会先去ht[0]中执行没有才会到ht[1]中执行新添加键值对是会被保存到ht[1])。
### 谈一谈你对Redis中List的理解
在Redis中存储的value可以是一个列表List跟Java中的LinkedList很像底层数据结构是一个链表插入和删除很快随机访问较慢时间复杂度是O(N)。Java中的列表数据进行缓存时一般是序列化成JSON以字符串的形式存储在Redis上而不是使用Redis中的List来进行存储Redis中的List可以作为一个队列来使用也可以作为一个栈来使用在实际使用中常用来做异步队列使用将可以延时处理的任务序列化成字符串塞进Redis的列表另外一个线程从列表中轮询数据进行处理
#### quicklist
老版本中的Redis元素较少时使用ziplist来作为底层编码元素较多时使用双向链表linkedList作为底层编码因为链表每个节点需要prevnext指针需要占用16字节而且每个节点内存都是单独分配加剧内存碎片化所以新版本使用quiklist作为底层编码quicklist的是一个双向链表但是它的每一个节点是一个ziplist。(默认每个ziplist最大长度为8k字节
### 谈一谈你对Redis中Set的理解
Set是一个无序的不重复的字符串集合底层编码有inset和hashtable两种
##### inset
当元素都为整数且元素个数较少时会使用inset作为底层编码inset结构中的有一个contents属性content是是一个整数数组从小到大保存了所有元素
##### hashtable
当元素个数较多时Set使用hashtable来保存元素元素的值作为keyvalue都是NULL
### 谈一谈你对Redis中有序集合ZSet的理解
Zset与Set的区别在于每一个元素都有一个Score属性并且存储时会将元素按照Score从低到高排列
##### ziplist
当元素较少时ZSet的底层编码使用ziplist实现所有元素按照Score从低到高排序
##### skiplist+dict
当元素较多时使用skiplist+dict来实现
skiplist存储元素的值和Score并且将所有元素按照分值有序排列便于以O(logN)的时间复杂度插入删除更新及根据Score进行范围性查找
dict存储元素的值和Score的映射关系便于以O(1)的时间复杂度查找元素对应的分值
### 布隆过滤器是什么
布隆过滤器可以理解为一个有误差的set结构使用布隆过滤器来判断元素是否存在其中时如果返回结果是存在实际可能存在也可能不存在返回结果不存在时实际结果肯定是不存在布隆过滤器实际上是一个大型的位数组添加key时通过几个hash函数对key计算得到一个下标然后根据下标将位数组中对应的值设为1
Morty Proxy This is a proxified and sanitized view of the page, visit original site.