前言
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命令手册,详见官方网站:https://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(跳表)