Redis的常用键值对
Redis的键值对
Redis是以键值(Key-Value)为基础,支持不同类型值(value)的数据结构服务器。在传统键值存储中,一般将字符串键与字符串值相关联,而在Redis中,该值不仅限于简单的字符串,还可以容纳列表、有序列表、哈希、二进制等数据结构。
redis的数据库存储结构如下:
typedef truct redisDb {
dict *dict; // 数据库键空间,保存数据库中的所有键值对
dict *expires; // 过期字典,保存着键的过期时间 键是键空间的键的指针,值是unix时间戳
}redisDb ;
dict数据包含了哈希表、哈希函数类型私有数据等数据,键值(Key-Value)就存储在hash表中
可以将这种数据结构想象成Java中的HashMap,在进行查找时,首先计算出键的hash值,通过hash找到存储数组的下标,然后通过匹配值找到对应的键值对元素。Redis通过链地址法解决哈希冲突。
有关redis底层数据结构的内容可以参考:
Redis基础知识 底层数据结构的实现
Redis-Key
Redis的键(Key)是二进制安全的字符串,在Redis的底层中由SDS实现。
二进制安全字符串:即支持任意类型的数据作为键。从“ foo”之类的字符串到JPEG文件的内容,都可以是有效的redis键,同时空字符串也包含在内。
一个SDS(simple dynamic string)的存储定义如下:
struct sdshdr {
int len; // 记录buf数组中已使用的字节数量,等于SDS所保存字符串的长度
int free; // 记录buf数组中未使用的字节数量
char buf[]; // 字节数组,用于保存字符串
}
设置键的注意点:
-
key使用的字节不宜过长:键太长时,不仅在内存方面是个负担,并且在redis服务器为了查找这个键,可能需要进行一些代价高昂的哈希值计算。
-
key也不宜设置太短:与“ user:1000:followers”对比,使用“ u1000flw”作为键毫无意义,前者往往更具可读性。且与键对象本身和值对象使用的空间相比,单单添加key消耗的空间更少。
-
key使用同一种设置类型:使用形如“ object-type:id”的格式,不仅在可读性方面更佳,也能有效的降低键重复时造成的值覆盖。例如“ user:1000”。点或破折号通常用于多字段的连接,例如“ comment🔢reply.to”或“ comment🔢reply-to”中。
-
键允许的最大大小为512 MB。
Redis-Value
Redis的值(Value)支持以下几种类型:
-
Binary-safe strings:二进制安全字符串。
-
Lists:根据插入顺序排序的字符串元素的集合。它们基本上是链表。
-
Sets:唯一,未排序的字符串元素的集合。
-
Sorted sets:类似于集合,但是每个字符串元素在存入时都将于一个浮点数值的分数相关联,元素总是按照它们的分数排序,因此与Sets不同,可以检索一系列元素
-
Hashes:键值组成的哈希映射,键值都是字符串。
-
Bit arrays (or simply bitmaps):可以使用特殊命令像位数组一样处理字符串值:可以设置和清除单个位,计数所有设置为1的位,找到第一个设置或未设置的位,等等。
-
HyperLogLogs:这是一个概率数据结构,用于估计集合的基数。
-
Streams:提供抽象日志数据类型的类地图项的仅追加集合。
redis值的内部实现结构如下:
type类型 | encoding编码 | ptr指向的数据结构 |
---|---|---|
REDIS_STRING | REDIS_ENCODING_INT | 整数值的实现的字符串对象 |
REDIS_STRING | REDIS_ENCODING_EMBSTR | embstr编码的sds实现的字符串对象 |
REDIS_STRING | REDIS_ENCODING_RAW | sds字符串实现的字符串对象 |
REDIS_LIST | REDIS_ENCODING_ZIPLIST | 压缩列表实现 |
REDIS_LIST | REDIS_ENCODING_LINKEDLIST | 链表实现 |
REDIS_HASH | REDIS_ENCODING_ZIPLIST | 压缩表实现 |
REDIS_HASH | REDIS_ENCODING_HT | 字典实现 |
REDIS_SET | REDIS_ENCODING_INTSET | 整数集合实现 |
REDIS_SET | REDIS_ENCODING_HT | 字典实现 |
REDIS_ZSET | REDIS_ENCODING_ZIPLIST | 压缩表实现 |
REDIS_ZSET | REDIS_ENCODING_SKIPLIST | 跳跃表和字典实现 |
Redis值的常用数据类型
- 字符串:String
Redis字符串类型是与Redis键关联的最简单的值类型。它也是Memcached中唯一的数据类型。
值是二进制安全的字符串,意味着redis的string可以包含任何数据。比如jpg图片或者序列化的对象。与键相同,值最大能存储512 MB的数据。
- 列表:List
redis是由双向链表(Linked List)的方式实现,而非数组形式。它能从链表的头尾进行操作。它是根据插入的顺序进行排序的有序列表。
列表的常用案例:记住用户发布到社交网络上的最近更新。频繁查看的日志。
- 集合:Set
set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。
可以理解为一堆值不重复的列表,类似数学领域中的集合概念,且Redis也提供了针对集合的求交集、并集、差集等操作。
- 有序集合:Sorted Set
Redis有序集合类似Redis集合,不同的是增加排序的功能。一个有序集合的每个成员带有分数属性,排序时根据分数来拍续。
Redis有序集合添加、删除和测试的时间复杂度均为O(1)(固定时间,无论里面包含的元素集合的数量)。列表的最大长度为2^32- 1(4294967295)。
Redis有序集合的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。
- 哈希表:Hash
对应值内部实际就是一个HashMap,这里与redis数据库字典下的哈希表使用的是同一种数据类型。
实际上,哈希表根据数据量大小会有2种不同实现方式:
- 当成员比较少时,Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应值的encoding为REDIS_ENCODING_ZIPLIST
- 当成员数量增大时,会自动转成真正的HashMap,此时encoding为REDIS_ENCODING_HT。
每个 hash 可以存储 2^32 -1 键值对。
参考: