Redis的字符串类型底层利用的是大略动态字符串(Simple Dynamic String,SDS)作为其数据构造。SDS是Redis自己实现的一种字符串表示,它具有一些传统C措辞字符串不具备的特性,例如预分配、自动扩展和内存重用等。
在SDS中,字符串被存储在一个字节数组中,数组的头部包含了一个指向字符串内容的指针,以及一些其他元数据,如字符串长度、空闲空间等。当字符串增长时,SDS会自动分配更多的内存,并将指针指向新的内存位置。此外,SDS还支持开释未利用的空闲空间,以避免内存摧残浪费蹂躏。
这种数据构造的设计使得Redis字符串在处理大量数据时能够保持高效和快速。例如,对付包含大量元素的列表和凑集,Redis可以利用SDS来存储和操作这些数据,避免了传统字符串处理中可能涌现的内存分配和复制问题。

Golang仿照演示
package mainimport ("fmt""unsafe")type RedisSDS struct {len intfree intbuf []byte}func NewRedisSDS(s string) RedisSDS {sds := &RedisSDS{}sds.init(len(s))copy(sds.buf, s)return sds}func (sds RedisSDS) init(size int) {sds.len = sizesds.free = 0sds.buf = make([]byte, size+1)}func (sds RedisSDS) Free() int {return sds.free}func (sds RedisSDS) Len() int {return sds.len}func (sds RedisSDS) Append(s string) {sds.len += len(s)sds.free -= len(s)copy(sds.buf[sds.len:], s)}func main() {sds := NewRedisSDS("Hello")fmt.Printf("sds: %v\n", sds)fmt.Printf("sds.Len(): %v\n", sds.Len())fmt.Printf("sds.Free(): %v\n", sds.Free())sds.Append(" World")fmt.Printf("sds: %v\n", sds)fmt.Printf("sds.Len(): %v\n", sds.Len())fmt.Printf("sds.Free(): %v\n", sds.Free())}
特点
内存分配:Redis SDS利用预分配和自动扩展的策略,避免了频繁的内存分配和复制操作。在创建字符串时,会预先分配一定大小的内存空间,并将字符串内容存储在个中。当字符串长度增加时,会自动扩展内存空间,避免了频繁的内存分配和开释操作,提高了性能。内存重用:Redis SDS还支持内存重用,当字符串长度减少时,会开释多余的内存空间,以便后续重新利用。这种内存重用的策略可以有效减少内存摧残浪费蹂躏,提高内存利用率。高效操作:由于Redis SDS构造的设计,使得对字符串的操作更加高效。通过直接操作字节数组,可以避免传统字符串处理中的复制和拼接操作,提高了字符串操作的性能。方便扩展:Redis SDS构造的设计使得其可以方便地扩展其他功能。例如,可以通过在构造中添加额外的字段来支持字符串的编码和解码操作,或者支持字符串的子串查找等功能。这种可扩展性使得Redis的字符串类型具有更强的适应性和灵巧性。列表Redis的列表类型(List)底层利用的是双端行列步队(Double-Ended Queue,也称为Deque)作为其数据构造。在Redis中,双端行列步队被实现为两个双向链表,一个用于存储数据,另一个用于指向行列步队的头部和尾部。
Golang仿照演示
package main import "fmt" type RedisList struct { data []interface{} } func (l RedisList) LeftPush(value interface{}) { l.data = append(l.data, value) } func (l RedisList) RightPush(value interface{}) { l.data = append(l.data, value) } func (l RedisList) LeftPop() interface{} { if len(l.data) == 0 { return nil } value := l.data[0] l.data = l.data[1:] return value } func (l RedisList) RightPop() interface{} { if len(l.data) == 0 { return nil } value := l.data[len(l.data)-1] l.data = l.data[:len(l.data)-1] return value } func main() { list := RedisList{} list.LeftPush("foo") list.RightPush("bar") fmt.Println(list) // Output: [bar foo] fmt.Println(list.LeftPop()) // Output: foo fmt.Println(list.RightPop()) // Output: bar }
特点
高效插入和删除:双端行列步队支持在行列步队的头部和尾部高效地插入和删除元素。这使得Redis列表可以快速地在两端添加或删除元素。灵巧的操作:利用双端行列步队,Redis可以实现从列表的两端进行添加和删除操作。这使得Redis列表适用于须要从两端处理数据的场景,如谈天室的行列步队、缓存等。内存利用效率高:双端行列步队通过利用链表实现了空间的复用。当删除元素时,只须要调度指针指向,而不须要移动其他元素。这使得Redis列表在处理大量数据时能够更高效地利用内存资源。利用场景
发布/订阅模型:Redis的发布/订阅功能可以用于实现的广播和监听。发布者可以向一个或多个频道发布,而订阅者则可以订阅一个或多个频道来吸收。这种模型可以用于实现实时通信、推送等运用。任务行列步队:Redis可以作为一个大略的任务行列步队利用。任务行列步队常日用于将任务添加到一个行列步队中,然后由后台事情线程或进程实行。这种模型可以用于实现异步任务处理、后台任务调度等运用。缓存行列步队:Redis可以作为一个缓存行列步队利用,将数据暂时存储在行列步队中,然后由其他系统进行消费和处理。这种模型可以用于减轻数据库压力、加速数据访问等运用。日志处理:Redis可以作为一个高速的日志处理平台,将日志数据添加到行列步队中,然后由其他系统进行实时剖析和处理。这种模型可以用于实现实时监控、非常检测等运用。事宜驱动架构:Redis可以作为一个事宜驱动架构的组成部分,实现事宜发布和订阅、事宜处理等环节。这种模型可以用于实现相应速率快、可扩展性强的事宜驱动运用。凑集Redis的凑集类型(Set)底层利用的是哈希表(Hash Table)作为其数据构造。
Golang仿照实现
package main import "fmt" type RedisSet struct { hashTable map[string]bool } func NewRedisSet() RedisSet { return &RedisSet{ hashTable: make(map[string]bool), } } func (set RedisSet) Add(member string) { set.hashTable[member] = true } func (set RedisSet) Remove(member string) { delete(set.hashTable, member) } func (set RedisSet) Contains(member string) bool { return set.hashTable[member] } func (set RedisSet) Size() int { count := 0 for key := range set.hashTable { count++ } return count } func main() { set := NewRedisSet() set.Add("member1") set.Add("member2") set.Add("member3") fmt.Println("Set size:", set.Size()) fmt.Println("Contains member1:", set.Contains("member1")) set.Remove("member1") fmt.Println("Set size after removing member1:", set.Size()) }
特点
快速查找:哈希表在均匀情形下具有靠近O(1)的查找繁芜度,这意味着无论凑集中有多少成员,查找成员的操作都可以在险些恒定的韶光内完成。这使得Redis的凑集类型非常适宜于须要快速查找操作的数据。动态扩容:哈希表可以动态地分配内存空间,根据须要自动扩展或紧缩。当凑集中成员数量增加时,哈希表可以自动扩展以容纳更多成员;当凑集中成员数量减少时,哈希表可以自动紧缩以开释内存。这种动态扩容的能力使得Redis的凑集类型可以高效地处理数据的变革。空间利用率高:哈希表的空间利用率常日较高,由于它们可以很好地利用内存空间,使得每个槽位(bucket)都尽可能地被利用。这有助于减少内存摧残浪费蹂躏,提高凑集类型的空间效率。利用场景
存储一些凑集性的数据,例如在微博运用中,可以将一个用户所有的关注人存在一个凑集中,将其所有粉丝存在一个凑集。利用Redis供应的凑集数据构造进行求交集、并集、差集等操作,可以非常方便地实现如共同关注、共同喜好、二度好友等功能。有序凑集Redis的有序凑集(Sorted Set)底层利用的是一种称为跳跃列表(Skip List)的数据构造来实现。跳跃列表是一个随机化的数据构造,它许可在O(log N)的韶光繁芜度内实现元素的插入、删除和查找操作。
跳跃列表是一个随机化的数据构造,它通过多级索引实现高效的插入、删除和查找操作。每个节点包含一个值、一个分数(Score)和一个指向下一层节点的指针。通过这种分层构造,跳跃列表可以在log(N)的韶光繁芜度内完成元素的插入、删除和查找操作。
在Redis的有序凑集中,每个节点还包含一个分数(Score)字段,用于对元素进行排序。跳跃列表的每个节点都有一个指向下一层相同值节点的指针,形成一个双向链表构造,这样可以方便地进行遍历和排序操作。
利用跳跃列表作为底层数据构造,Redis的有序凑集可以高效地处理大量有序的元素,并供应类似ZADD、ZRANGE等操作来对凑集进行排序和查找。跳跃列表还支持反向查找功能,可以通过给定的值和指针反向查找上一层中具有相同值的节点。
此外,Redis有序凑集还支持一些常用的操作,如ZREM、ZINCRBY等,用于删除元素、增加元素的分数等。这些操作的韶光繁芜度常日是O(log N),个中N是有序凑集中元素的数量。
Golang仿照演示
package mainimport ("fmt""math/rand""time")// SkipListNode 表示跳跃列表中的节点 type SkipListNode struct {Value string // 节点值 Score float64 // 节点分数 Right SkipListNode // 右指针 Left SkipListNode // 左指针 Down SkipListNode // 下指针 Level int // 节点所在的层数 }// SkipList 表示跳跃列表 type SkipList struct {Head SkipListNode // 头节点 }// NewSkipList 创建一个新的跳跃列表 func NewSkipList() SkipList {return &SkipList{Head: &SkipListNode{}}}// Insert 插入一个元素到跳跃列表中 func (sl SkipList) Insert(value string, score float64) {level := sl.Head.Level + 1 // 打算层数 for level > 0 {// 随机决定向左或向右插入节点 if rand.Float64() < 0.5 {right := sl.Head.Rightif right == nil || right.Level < level-1 {newNode := &SkipListNode{Value: value, Score: score, Right: nil, Left: nil, Down: sl.Head, Level: level}right = newNode} else {for right != nil && right.Level == level-1 {right = right.Right}right = &SkipListNode{Value: value, Score: score, Right: nil, Left: nil, Down: sl.Head, Level: level}}right.Right = newNodenewNode.Left = rightnewNode.Down = newNode.Right.DownnewNode.Right.Down = newNode.Left.Downsl.Head.Right = newNode.Right.Right} else {left := sl.Head.Leftif left == nil || left.Level < level-1 {newNode := &SkipListNode{Value: value, Score: score, Right: nil, Left: nil, Down: sl.Head, Level: level}left = newNode} else {for left != nil && left.Level == level-1 {left = left.Left}left = &SkipListNode{Value: value, Score: score, Right: nil, Left: nil, Down: sl.Head, Level: level}}left.Left = newNodenewNode.Right = leftnewNode.Down = newNode.Left.DownnewNode.Left.Down = newNode.Right.Downsl.Head.Left = newNode.Left.Left}level-- // 层数递减,连续向下插入节点直达到到顶层或无法插入为止 }}
特点
有序:底层数据构造是有序的,每个节点都包含一个分数(Score)字段,用于对元素进行排序。多层:跳跃列表是一个分层构造,每个节点都有一个指向下一层相同值节点的指针,形成一个双向链表构造。去重:底层数据构造中的每个元素都是唯一的,不会涌现重复的情形。构成有序凑集的底层构造(ZSET):有序凑集是跳跃列表的一种运用,它底层的数据构培养是跳跃列表。查询效率高:由于跳跃列表的分层构造和每个节点包含指向下一层相同值节点的指针,使得它可以在log(N)的韶光繁芜度内完成元素的插入、删除和查找操作。支持反向查找:跳跃列表还支持反向查找功能,可以通过给定的值和指针反向查找上一层中具有相同值的节点。压缩列表:Redis为了节省内存,自行设计了一种数据构造——压缩列表,它是对付数组的每一个元素,都带有前一元素占用内存的大小,从而减少内存开销。利用场景
带有权重的元素:例如,一个游戏的用户得分排行榜。比较繁芜的数据构造:一样平常用到的场景不算太多,和Sets比较,Sorted Sets是将Set中的元素增加了一个权重参数score,使得凑集中的元素能够按score进行有序排列。带权重的行列步队:Sorted Set还可以用来做带权重的行列步队,比如普通的score为1,主要的score为2,然后事情线程可以选择按score的倒序来获取事情任务,让主要的任务优先实行。共同好友、共同喜好、二度好友等场景:可以利用Sorted Set统计网站访问IP(利用唯一性,统计访问网站的所有独立IP)以及进行好友推举(好友推举时,根据tag求交集,大于某个阈值就可以推举)。HashRedis的Hash类型底层利用的是哈希表作为其数据构造。在Redis中,哈希表用于存储键值对,个中键用于唯一标识每个值,而值可以是任何类型的数据。
哈希类型常用的方法包括:HSET、HGET、HDEL等。这些方法用于设置、获取和删除哈希表中的键值对。利用场景包括但不限于存储用户信息、缓存工具等。韶光繁芜度常日是O(1),即对单个键值对的操作是常数韶光繁芜度。
Golang仿照演示
package mainimport "fmt"// Hash 表示Redis的哈希表 type Hash map[string]interface{}// NewHash 创建一个新的哈希表 func NewHash() Hash {return make(map[string]interface{})}// Get 获取哈希表中指定键的值 func (h Hash) Get(key string) interface{} {value, ok := h[key]if ok {return value}return nil}// Set 设置哈希表中键值对的值 func (h Hash) Set(key string, value interface{}) {h[key] = value}// Delete 删除哈希表中指定的键值对 func (h Hash) Delete(key string) {delete(h, key)}// Keys 返回哈希表中所有键的列表 func (h Hash) Keys() []string {keys := make([]string, 0, len(h))for key := range h {keys = append(keys, key)}return keys}// Values 返回哈希表中所有值的列表 func (h Hash) Values() []interface{} {values := make([]interface{}, 0, len(h))for _, value := range h {values = append(values, value)}return values}
特点
快速访问:哈希表供应快速的键值查找操作,使得在Redis中访问哈希类型的元素非常高效。动态增长:哈希表可以动态地增长以适应存储的数据量,无需预先分配固天命量的内存空间。内存高效:哈希表在内存中以紧凑的形式存储键值对,使得Redis能够高效地利用内存资源。利用场景
数据库:Redis的哈希类型可以用于实现数据库的底层构造,例如实现表和列的映射关系,或者作为数据库中的数据项的存储构造。缓存:哈希类型可以用于缓存数据库查询结果或其他打算结果,以供应快速访问。会话管理:哈希类型可以用于存储和管理用户会话信息,包括用户ID、登录状态等信息。配置管理:Redis的哈希类型可以用于存储和管理运用程序的配置信息,例如配置参数、环境变量等。工具存储:哈希类型可以用于存储工具,例如文件、图片或其他二进制数据。计数器:哈希类型可以用于实现计数器功能,例如统计网站访问量、用户行为等。其他Redis支持的不仅仅是五种数据类型。除了五种基本数据类型(string、hash、list、set、zset)之外,Redis还支持其他四种分外的数据类型。因此,Redis统共支持九种数据类型。
Stream:用于实现高等行列步队,可以用于处理实时数据流。HyperLogLog:用于估计数据集的基数,可以在不存储完全数据集的情形下进行基数统计。Geospatial:用于存储地理空间数据,可以用于地理位置的搜索和间隔打算。Pub/Sub:用于实现发布/订阅模型,可以用于实时通信和通报。分外的这4类,目前没有用过,欢迎大家补充!
【申明:部分图片来源于网络,侵权,联系,删除】