2009年,Redis由Salvatore Sanfilippo开拓并发布在Github上。最初,Redis是一个键值对存储系统,支持字符串类型、列表类型、凑集类型和哈希类型等数据构造。
2010年,Redis开始盛行,并成为一个盛行的数据存储和缓存办理方案。Redis2.0发布,加入了VM I/O异步优化、持久化等新特性。
2012 年,Redis 2.6发布,引入了限流限速、事务、Lua 脚本等诸多新特性。Redis2.6变得更加稳定和安全,并且Redis2.6开始盛行作为缓存和行列步队办理方案。

2014年,Redis3.0发布,支持了集群模式、多种新的数据构造、复制和分区等新功能。Redis3.0开始得到广泛运用,特殊是在大规模互联网运用上,受到了极大的关注和支持。
2016年,Redis4.0发布,支持模块化、快照异步和集群等扩展浩瀚特性。
目前,Redis 已经成为一个成熟、盛行、高性能的键值存储系统,被广泛运用于各种web运用和企业级运用处景,目前最近的redis版本可以支持的数据类型有9种,分别是:
String
字符串(String)数据类型是Redis最基本的数据类型,用于存储一串字符,其最大长度为 512 MB。String类型是Redis中最大略的数据类型,在Redis 中,String类型不仅仅可以存储字符串,还可以存储数字、图片、序列化后的工具等任何数据类型。
Redis中的字符串类型的底层数据构造是SDS(Simple Dynamic String),SDS是Redis所利用的字符串库,比较C措辞原生的字符串,SDS更加灵巧和高效。以下是Redis中字符串类型的底层数据构造图:
redisStringObject {
+--------+
| type |
+--------+
| 1Byte |
+--------+
| encode|
+--------+
| 1Byte |
+--------+
| length|
+--------+
| 4Byte |
| |
| |
+--------+
| buf[] |
| |
| |
+--------+
}
个中,type 表示字符串类型,为 0x1。encode 表示字符串编码办法,Redis中有两种编码办法:int 和 raw。int 表示该字符串可以被阐明为整数,raw 表示是纯字符串类型。为了节省空间,Redis 会考试测验将可以被阐明为整数的字符串存储为整数类型,从而节约空间。length 表示字符串的长度。buf[] 表示字符串的内容,底层利用char 数组存储。
总体来说,Redis 的字符串类型利用了一些比较底层的数据构造,例如 char 数组和整数类型,使得字符串类型更加高效和灵巧。
Hash
Hash 数据类型用于存储字段和字段值的映射,类似于关联数组或者哈希表,个中字段是字符串类型,字段值可以是 String 类型、Hash 类型或者 List 类型。
类型利用的底层数据构造是哈希表,以下是 Redis 中哈希表的底层数据构造示意图:
redisHashTable {
+--------+
| size |
+--------+
| used |
+--------+
| dict |
+--------+
}
个中,size 表示哈希表数组的大小,used表示哈希表中已利用的节点数量。
dict 表示哈希表数组,其底层数据构造是一个数组和链表。详细来说,哈希表数组中的每个元素都指向一个链表头,而每次插入数据时,会根据key的哈希值打算出数组下标,并在对应链表中插入一个新的节点。当哈希表冲突时,多个不同的 key 可能司帐算出相同的哈希值,此时它们会被插入到同一个链表中,这便是所谓的拉链法(open addressing with chaining)。哈希表的优点是其插入、删除和查找操作的韶光繁芜度均为 O(1),即常数韶光,因此非常高效。其余,哈希表还支持动态扩容和缩容,可以根据插入数据的情形自动调度大小,从而使得哈希表利用起来非常方便。
List
列表(List)数据类型是 Redis 存储有序元素的凑集,个中每个元素都包含一个字符串。List类型支持从左边或右边进行元素的添加和删除操作。
列表类型利用的底层数据构造是双端链表,以下是Redis 中双端链表的底层数据构造示意图:
redisList {
+--------+
| head |
+--------+
| tail |
+--------+
| len |
+--------+
}
个中,head 表示双端链表的头结点,tail 表示双端链表的尾结点,len 表示双端链表的长度。
双端链表是一种分外的链表,它除了存储数据外,还同时存储了先驱节点和后继节点的地址。这个特性使得它支持快速的尾部插入和头部插入操作,以及快速的尾部删除和头部删除操作。在Redis中,列表类型还支持基于双端链表实现的双向循环链表,即列表尾部的下一个节点是列表头部,列表头部的前一个节点是列表尾部。这样可以使得某些操作的繁芜度更低,例如将列表尾部的数据插入到列表头部。其余,Redis 还供应了一种名为 quicklist 的列表存储办法,它将一个列表分成多少个小块,每个小块以压缩列表的形式存储。这样可以有效地节省内存空间,提高查询性能,但会导致增删操作的繁芜度略有增加。
Set
凑集(Set)数据类型是 Redis 存储无序且不重复元素的凑集,每个元素都是唯一的。Set 类型支持添加、删除和检讨元素是否存在等操作。
Set 类型利用的底层数据构造是哈希表(Hash Table),以下是Redis中哈希表的底层数据构造示意图:
redisSet {
+--------+
| dict |
+--------+
| len |
+--------+
}
个中,dict表示底层利用的哈希表,len表示凑集中元素的数量。哈希表是一种基于数组的数据构造,它通过散列函数将数据映射到数组中的一个位置,以达到快速访问元素的目的。Redis 中的哈希表利用链表法来办理哈希冲突问题,即当多个元素映射到同一个位置时,将这些元素放在同一个链表中,实现了高效的增、删、查操作。Set 类型中的元素是无序、不重复的,利用哈希表来存储可以使得元素的插入、删除和查找等操作均摊韶光繁芜度为 O(1),非常高效。同时,Redis 还供应了一些基于凑集的操作,例如求交集、并集和差集等,这些操作也可以通过哈希表来实现。
Sorted set
有序凑集(Sorted Set)是 Redis 的一个独特数据类型,类似于凑集(Set)数据类型,但是每个元素都有一个干系的分数,用于对元素进行排序。
sorted Set 类型底层利用的是两种数据构造:跳跃表(Skip List)和哈希表(Hash Table)。
以下是 Redis Sorted Set 的底层数据构造示意图:
redisSortedSet {
+--------+
| dict |
+--------+
| skiplist|
+--------+
}
个中,dict表示底层利用的哈希表,skiplist表示底层利用的跳跃表。跳跃表是一种随机化数据构造,它在保持有序性的同时,实现了高效的查找和插入操作。跳跃表利用多级索引的办法,以空间换韶光,大大提高了查找的效率。在Redis 中,Sorted Set利用跳跃表来实现有序性,并且跳跃表中的每个节点都存储了获取元素的指针,以是在元素的查找上也非常高效。哈希表是用于保存 Sorted Set 中元素名与分值之间的对应关系的。它供应了 O(1) 繁芜度的元素插入、删除和查找操作。哈希表在插入和删除操作上具有很高的效率。Redis的Sorted Set 既具有字典(Hash Table)的高效性,又具有有序列表(Skip List)的快速查找、插入、删除操作的特点。这种构造为Sorted Set 供应了强大的功能,如范围查询(按照分值的范围来查询元素)、排行榜等。
Bitmaps
是一种分外的字符串类型,其值仅包含二进制位,每个位的值只能是0 或 1。Redis 的 Bitmaps 模块供应了一组分外的操作命令,Bitmaps 可以用于位图、计数器、邮件系统中邮件是否已读等场景。
Redis中的Bitmaps指的是位图数据构造,用于高效地存储和操作二进制位。底层实现采取了内存位图的办法,非常适宜于存储和操作大量的二进制位信息。下面是 Redis Bitmaps 的底层数据构造示意图:
Key: online_users
+----+--------+--------+--------+--------+--------+--------+--------+--------+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ...
+----+--------+--------+--------+--------+--------+--------+--------+--------+
| 00 | 010001 | 101101 | 000011 | 110000 | 011011 | 101010 | 111111 | 000000 | ...
+----+--------+--------+--------+--------+--------+--------+--------+--------+
上面的示意图是一个 Bitmaps 工具,个中每一位存储了一个二进制数值(0 或 1),可以表示某个元素的存在与否等信息。在 Redis 中,位图数据构造可以通过 SETBIT、GETBIT 等命令进行位的存取,还可以通过 BITOP 等命令进行位运算,包括 AND、OR、XOR 等操作。
在实际运用中,Redis 位图数据构造常用于统计在线用户、标记用户行为等场景,通过对二进制位的操作来快速、高效地完成干系任务。由于位图数据构造在底层采取了内存位图的形式,因此非常紧凑,可以高效地处理大量的二进制位信息,而且操作效率很高,是一种非常精良的存储和操作二进制信息的数据构造。
Hyperloglog
Redis 中的 HyperLogLog 是一种基数统打算法,用于高效地统计凑集中的元素数目。HyperLogLog 可以在 O(1) 的韶光繁芜度内完成对不同元素数量的估算,而且空间利用率非常低。HyperLogLog 利用的事理非常大略,它将每个元素映射到一个哈希值上,并对哈希值进行操作,以得到元素的数量估算值。HyperLogLog 中利用的算法基于 PFCM 或 Linear Counting 算法,它可以通过打算位图中前导 0 位数的均匀值来估算元素数量,从而有效地降落内存空间利用率。
Redis 中的 HyperLogLog 数据构造用于实现基数统计,底层采取稀疏精度优化法 (Sparse Precision Optimization),可以用很小的内存空间对高基数(cardinality)做近似计数。HyperLogLog 的基本思想是保存一些随机 hash 值的最大前导零的数量,根据这个数量近似打算基数。
下面是 HyperLogLog 底层数据构造实现示意图:
Key: counter
+-------+----------------------+
| Index | Value |
+-------+----------------------+
| 0 | 0001001 |
| 1 | 0010000 |
| 2 | 0000010 |
| 3 | 0000101 |
| ... | ... |
| N-1 | 1001010 - (max(29, 0))|
+-------+----------------------+
上面的示意图是一个 HyperLogLog 的计数器,个中以二进制位存储 hash 值的最大前导零数量,即 leading zero count (LZC)。每个 LZC 都存储在一个单独的索引位置上,可以通过索引位置来进行快速计数和合并操作。在 Redis 中,HyperLogLog 的底层实现采取了稀疏精度优化法,只会记录 LZC 不为 0 的 hash 值,这样可以大大节省内存空间,并且不会对计数结果产生过大的偏差。HyperLogLog 的精度紧张由内部的 LZC 位数和插入的 hash 值数量决定。通过调度这两个成分,我们可以得到不同精度的计数结果。HyperLogLog 的基数统计偏差一样平常在 1% 以内,纵然是千万级别的基数也可以利用不到 1 KB 的内存来进行计数。
Geo
Redis中供应了Geo数据类型,用于处理地理空间坐标信息。Geo数据类型支持将坐标点和对应的名称存储在 Redis 的有序凑集中,同时供应了一些基于地理位置的功能,如打算两个地理位置之间的间隔、查找某个地理位置的附近的位置等。通过利用Geo数据类型,用户可以更方便地处理基于地理位置的业务场景,如舆图运用中的位置查找、城市做事中的附近店铺搜索、出租车做事中的车辆调度等。
Redis中的GEO数据类型是用来存储地理位置信息的数据类型,它基于 zset 实现。在zset中,每个成员都会带有一个称为score的分值来进行有序排序,而 GEO 数据类型中,分值就表示成员的经度或纬度,成员则是一个地点的名称。Redis采取zset来存储地理位置信息,底层利用了Ziplist和Skiplist。
下面是 GEO 底层数据构造实现示意图:
Key: city
+-------+----------+-----------+
| Score | Longitude| Latitude |
+-------+----------+-----------+
| 29.0 | 112.0 | 34.0 |
| 31.0 | 130.0 | 45.0 |
| 37.0 | 23.0 | 53.0 |
| 41.0 | 125.5 | 39.5 |
| 45.0 | -79.0 | 43.5 |
+-------+----------+-----------+
上图中展示了一个名为city的GEO数据类型,它包含了五个地点的经纬度信息。个中每个地点由一个分值和两个数据项组成,分值是经度或纬度信息,经度和纬度则是地点的位置。对付GEO数据类型,用户可以通过经度、纬度和半径的组合快速地查找周围其他地点。通过zset的score和member,我们可以直接对 GEO 数据类型进行排序和范围查询操作。
Stream
Redis Stream是Redis5.0版本新增的数据类型,用于支持行列步队等场景。Redis Stream类似于Kafka的模型,可以支持可靠的传输和多个消费者的并行消费等功能。
Redis Stream 的底层实现采取了类似跳表(Skip List)的数据构造,每个 Stream 对应一个长度可变的双向链表,每个对应链表中的一个节点。跳表的每一层都是一个由多少节点组成的双向链表,每个节点包含了下一层的起始节点指针等信息,可以快速地进行查找和插入操作,同时也担保了数据的有序性。
Redis Stream 的数据构造示意图如下:
Stream N(名字)
+- Message 1
| +-------- Key1: Value1
| | +---- Key2: Value2
| | | + Timestamp
| | | |
| | | v
| v v v
+- Message 2 ---+
| +-------- Key1: Value1
| +---- Key2: Value2
| + Timestamp
|
v
在上面的数据构造示意图中,Stream N 表示一个 Stream 的名称,每个 Message 代表一个,Key-Value 表示中的数据,Timestamp 表示的韶光戳。在实际的运用中,用户可以向 Stream 中添加、读取消息、删除等,通过利用 Stream 数据类型可以方便地实现行列步队等功能。