什么是Redis?
- 首先他是一个非关系型数据库,可以根据键以 O(1) 的时间复杂度插入或者取出关联值。
- Redis 是一个内存数据库,所以数据是存在内存中的。
- 键值对中的键有不同的数据类型,可以是字符串,整型,浮点型等,且键是唯一的。
- 值的类型就多了,有 **
string、hash、list、set、zset
**等。 - Redis 内置了赋值,磁盘持久化,智齿 LUA 脚本,事务,SSL,客户端代理等功能。
- 通过 Redis 哨兵和自动分区提供高可用。
说一说 RedisDB 的基本数据结构(不是基本数据类型)?
我们来看一张图:
- redisDb结构体:
- redis 的默认初始是十六个数据库,每个数据库的数据结构体就是 redisDb,里面比较重要的就是:dict指针(字典),所有的数据都是靠这个字典来的。
- dict结构体:
- 与我们每种类型相关的结构体。
- dictht结构体:
- 字典hashtable,后三个字段对应,O(1)复杂度获取hashtable中的数据个数,长度标记,用了多少空间(已经拥有了多少元素)。
- 内部包含了指向正真存储数据的 dictEntry 链表的头节点。
- dictEntry结构体:
- 代表我们的每一个元素。
- 正真存储数据的地方。
- key字段:存入的键值对的键。
- value字段:存入的键值对的值(重要内容),指向 redisObject 结构体。
- redisObject结构体:
- type:string、hash、set、list这些类型都是通过它来指向的,是对外的。
- encoding:编码方式。
- LRU:内存淘汰策略需要了解。
- refcount:内存管理计数器,用来判断一个内存数据是否存活。
- ptr:指向我们真实的数据的存储,指向数据最终编码的对象。
Redis的值基本数据类型?
在这里我们说的是值的数据类型,键的话目前就支持字符串。
字符串
为什么 Redis 不去采用 C 语言的字符串直接使用呢?
我们来说一下缺点:
- 没有较好的扩容机制。
- 特殊字符无法处理。
- O(n) 复杂度获取长度,也就是从头到尾遍历到\0结束,才知道长度。
数据结构体
左边是 redis 3.0 之前,右边是之后:
- 左边:
len(已用空间长度) + free(剩余空闲空间) = 整个字符串申请的内存空间。
- buf[] 就是字符串存取的正真地点。
- 右边:
- len,字符串已使用长度。
- alloc,给这个字符串(sds)分配的长度。
- flags,标记当前字符串采用的是哪种 sds 结构体的(看下图)。
Redis为了保证不同长度的字符串都有可以对应的结构体去存储,它把不同长度的字符串可能需要的存储空间提取出来不同的 sds 结构体来对应接收存储。
总结
Redis的字符串类型本质上就是C语言的字符数组,但是额外增加了一点别的标识属性的结构体。
- 字符串长度获取时间复杂度从 O(n) 降为了 O(1),因为有标记字段。
- 减少了字符串扩容引起的数据搬运次数,提前分配合适的空间。
- 可以存储更加复杂的二进制数据。
实战场景
- 缓存:我个人使用最多的,把常用的信息,字符串,图片等信息变成字符串的形式序列化后放入 redis 中,比如 token。
- 计数器:redis在6.0前是单线程的,而且一般都不用高版本,所以我们可以用它来做计数器。
- session:我们可以用 redis 来实现分布式会话,大家都来这个地方读取 session,比直接存到数据库好多了。
List
List实现?
底层是双向链表和压缩链表实现的。