带你走进Redis的世界 - Redis的数据结构

133 阅读5分钟

带你走进Redis的世界 - Redis的数据结构

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情

写在前面

前言

Redis(Remote Dictionary Server)是一个Key-value存储系统,使用C语言编写,遵守BCD协议(BCD协议提供给使用者很大自由)。

Redis运行于独立的进程,通过网络协议和应用进行交互,将数据保存至内存中,提供多种方式,进行数据的持久化保存。Redis具有跨服务器的水平拆分、复制的分布式特性。Redis不同于一般key-value数据库,value本身具有结构化。

数据结构

图片

Redis数据结构如上图所示。

Redis是典型的NoSql 非关系型数据库,没有传统的table结构。数据库db以编号作为定义,默认为db0。

/**
* Redis 内部对象数据结构定义
*/
typedef struct redisObject{
unsigned type:4;
unsigned encoding:4;
unsigned 1ru:REDIS_LRU_BITS;
int refcount;
void *ptr;
} robj;

type: redis的数据结构类型,string list map set sorted-set

encoding: redis数据结构具体的实现方式,比如string可以由int、char[] 来实现

lru:表示本对象空转时间,有限内存下长期不访问对象清理

refcount: 应用计数,用于对象的垃圾回收

ptr:指的使用encoding作为实际的实现方式所在实际地址

string

redis的string类型,可以表示以下三种数据

  • 字符串
  • 整数
  • 浮点数

浮点数,限于双精度

整数、浮点数,类型的value,具有自增、自减等数字型操作,并且redis自动识别精度、值域范围,根据精度、值域自动进行类型升级

127.0.0.1:6379> set test 123
OK
127.0.0.1:6379> incr test
(integer) 124

相关的redis命令手册,详见官方网站:www.redis.net.cn/order/

图片

string类型,在内存中,以字节串作为承载的,在内部以int、SDS作为结构存储。

int,存储整数型数据;SDS存放字节、浮点型数据

List

list即列表对象,用于存储string序列

主要操作如下:

RPUSH/LPUSH: 将指定的string内容添加到给定的key的开头或者结尾

127.0.0.1:6379> rpush test "nihao"
(integer) 1

RPOP/LPOP:取出指定的key对应的开头或结尾

127.0.0.1:6379> Rpop test
"nihao"

LINDEX: 取出指定的key的索引下标下的值

127.0.0.1:6379> del test
(integer) 0
127.0.0.1:6379> rpush test "123"
(integer) 1
127.0.0.1:6379> rpush test "456"
(integer) 2
127.0.0.1:6379> rpush test "12312"
(integer) 3
127.0.0.1:6379> lindex test 2
"12312"
127.0.0.1:6379> lindex test 0
"123"

LRANGE: 取出指定的key范围内的值

127.0.0.1:6379> Lrange test 0 -1
1"123"
2"456"
3"12312"
127.0.0.1:6379> Lrange test 0 2
1"123"
2"456"
3"12312"

下标 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。

更多操作,感兴趣的可以去官网了解下。

List类型的value对象,内部以LinkedList或者ziplist实现,当list的元素个数或者单个元素长度很小时,会采用ziplist实现,否则将会使用linkedlist实现。

LinkedList是一个双向链表。ZipList采用的可变长度的压缩方法,针对值较小的整数、较短的string具有很好的压缩效果。

Map

Map又叫hash,维护的是一个hash表。维护了多个key-value ,且key不重复。

Redis本身数据结构为key-value,值也可以是key-value,但是值内的value不能再嵌套map,只能是string类型能表达的内容(整形、字节型、浮点型)。

图片

map类型的数值,redis提供了以上的操作实现。

HSET: 为指定的key,设置key -value值

HGET:获取指定的key的字段中key的值

127.0.0.1:6379> hset test nihao "123"
(integer) 1
127.0.0.1:6379> hget test nihao
"123"

map在内部实现包括ziplist和hashtable两种,对于数据量比较小的,采用ziplist实现。

哈希表,在Redis中分为三个层级,由低向上:

dictEntry:管理一个key-value对,同时保留同一个桶中的相邻元素的指针

dictht:维护所有的桶链

dict:当桶链需要扩容或者缩容时,管理迁移

大致上,如图所示理解

图片

Set

类似List,是一个无序集合,元素不重复。

基本操作命令如下图所示,具体使用,照例查找官方说明

图片

SADD:为指定的key,添加新的值

SMEMBERS:获取指定的key的所有值

127.0.0.1:6379> sadd test "nihaoa"
(integer) 1
127.0.0.1:6379> sadd test "woca"
(integer) 1
127.0.0.1:6379> SMEMBERS test
1"woca"
2"nihaoa"

Set在内部以intset或者hashtable来实现。对于采用hashtable实现,其中value永远为null,当set中只包含整形元素,采用intset实现。

intset核心元素是一个字节数组,从小到大有序存放set的元素。

typedef struct intset {
uint32_t encoding;
uint32_t length;
int8_t contents[];
} intset;

intset,由于是有序的整型数据存储,所以采用了二分查找法进行数据的操作。

查找时间复杂度为O(log(N)),插入时间复杂度为O(N)

Sorted-set

Sorted-set 是redis 独有的数据结构,类似map是一个key-value对。但是它是一个有序的key-value对。

key:key-value中的键,在一个sorted-set中不重复

value:是一个浮点数,成为score

有序:sorted-set 内部按照score从小到大排序

图片

ZADD: 为指定的key添加值,注意格式为 ZADD KEY_NAME SCORE1 VALUE1.. SCOREN VALUEN\

127.0.0.1:6379> zadd test 1 "nihao"
(integer) 1
127.0.0.1:6379> zadd test 1 "nihaoa"
(integer) 1
127.0.0.1:6379> zrange test 0 1
1"nihao"
2"nihaoa"
127.0.0.1:6379> zadd test 4 "woshishui" 3 "hahah"
(integer) 2
127.0.0.1:6379> zrange test 0 -1
1"nihao"
2"nihaoa"
3"hahah"
4"woshishui"

Sorted-set内部以ziplist或者skiplist+hashtable实现。

感兴趣的可以多了解下,skiplist(跳表)