=Redis数据结构=
Redis有哪些数据结构?:代码实现
字符串:value是string、整数、浮点数。整数、浮点数可以做++or--。缓存对象、常规计数、分布式锁
哈希:包含键值的无序散列表。缓存对象、购物车
列表:链表,节点包含字符串。消息队列
集合:基于哈希。string的无序集合。聚合计算场景:点赞、共同关注、抽奖
有序集合:元素对应分数,用于排序。排序场景,排行榜。
Bitmap:二值状态,签到,判断用户登录状态
Stream:消息队列。自动生成全局唯一ID,支持按组消费数据
对数据类型的操作都是原子性的,因为执行命令由单线程负责
Zset使用了什么数据结构/底层是如何实现的?
跳表
Zset用过吗?使用场景:代码实现
实现排行榜功能
SkipList了解吗?:代码实现 区分度
多层的有序链表,解决链表查找时只能逐一查找,效率低的问题
多个头节点,指向不同的层级,快读定位数据
深挖:跳表如何实现多层?
对象元素值 元素权重值
后向指针(倒序查找)
节点level数组(元素代表跳的层),保存每层上的前向指针和跨度
跳表是怎么设置层高的?
创建节点时,生成0-1的随机数,小于0.25就+1层,循环往复,直至随机数大于0.25
跳表的时间复杂度是多少?
时间复杂度是O(logn),空间复杂度是O(n)
Redis为什么使用跳表而不是B+树?
对于内存访问:跳表符合CPU缓存局部性,指针跳转效率更高,B+树节点结构复杂,缓存不优化。
实现复杂度:跳表无复杂平衡操作,B+树节点分裂/合并逻辑复杂,代码量大。
写入性能,跳表插入/删除仅需要调整局部指针,B+树插入可能触发递归节点分裂,成本高
内存占用:跳表结构紧凑,无内存碎片,B+树节点预分类可能浪费内存
为什么MySQL不用SkipList?
B+树3-4层就能实现千万级别数据的存储,但同样的数据量跳表存储就会有太多的层数,导致磁盘io次数增多
哈希表是怎么扩容的?深入理解哈希表结构代码实现
用到两个哈希表
正常请求阶段,只向哈希表1中插入数据,哈希表2没有分配空间
随着数据增多,给哈希表2分配空间,一般比表1大两倍。将表1中的数据转移到表2中,直至全部转移完,清除表1,空间,将表2设置为表1,创建一个空白的哈希表2,为下次rehash做准备。
渐进式哈希?
解决表1数据迁移到表2时候大量的拷贝操作,造成Redis阻塞。
给哈希表2分配空间
每次对元素操作,顺序讲表1中的元素迁移到表2
随着请求增多,最终会全部迁移完成
渐进式哈希过程中的写/删除,查找更新操作怎么进行?
删除、查找、更新 在两个表同时操作。表1没找到,去表2找
写只保存在表2,确保表1的元素越来越少。
String是使用什么存储的?为什么不使用C语言中的字符串?
SDS数据结构:
len:字符串长度 查询时直接返回,时间复杂度O(1)
alloc:分配的空间长度 。修改字符串时,allc-len判空间,不足扩容,不会出现缓冲区溢出
flags:sds类型 。一共有5种
buf[]:字节数组 。保存实际数据,字符串/二进制
比起C:查询字符串长度快。二进制安全,用len存储长度,可以存储\0,SDS的api都是以二进制的方式对buf中的数据处理。可以保存任意格式的二进制。
不会发生缓冲区溢出,C的大多数stirng操作函数不安全,程序内部不会判断缓冲区是否够用,溢出会造成程序的异常结束。