- 浏览: 141181 次
文章分类
最新评论
Redis 虽说由 C 语言实现,但用户直接操作的字符串绝大多数情况下均非 C 语言中以空字符结尾的字符串,而是一种封装了 C 字符串的称作简单动态字符串(simple dynamic string, SDS)的抽象结构,并将其作为 Redis 的默认字符串表示。
SDS 结构的定义如下:
之所以采用 SDS 结构而非直接使用 C 风格字符串,主要是为了满足 Redis 对字符串在安全性、效率以及功能方面的要求。这主要表现在以下几方面。
1、获取字符串长度的复杂度
因为访问 C 字符串的长度则需要 O(N)(N 为字符串的长度),而根据 SDS 结构的定义可知,要获取其保存的字符串的长度,只需访问 len 属性即可,时间复杂度为 O(1),这避免了在 Redis 中反复执行 STRLEN 命令对系统性能造成的影响。
2、杜绝缓冲区溢出
SDS 的内存分配策略能保证在每次修改 SDS 底层存储的字符串时,buf 数组有足够的空间容纳新的字符串,从而避免了缓冲区溢出的可能。
3、使用了空间预分配和惰性空间释放来优化内存分配
当剩余的未使用空间 free 不能容纳修改后增长的字节长度时,使用空间预分配能减少连续执行字符串增长操作所需的内存重分配次数。具体的预分配策略算法如下:
a)若修改后 SDS 的字符串长度 len 小于 1MB,则分配和 len 同样大小的未使用空间 free,此时 SDS 的属性 len 和 free 的值相同。
b)若修改后 SDS 的字符串长度 len 不小于 1MB,则额外分配 free 为 1MB 的未使用空间。
而使用惰性空间释放则是指:在需要缩短 SDS 保存的字符串时,程序并不立即释放缩短后多出来的空间,而是追加到 free 属性中,以备将来使用。
4、二进制安全
由于 C 字符串是以空字符来区分字符串是否结束,所以这使得其只能保存文本数据,而不能保存数据中可能含有空字符的二进制数据(如图片、音频、视频和压缩文件等)。为了确保 Redis 可以适用于多种场景,SDS 的 API 都是二进制安全的(binary-safe)。这也是将 buf 称为字节数组的原因,因为 Redis 不是用它来保存字符,而是用来保存一系列二进制数据。因此 SDS 是使用 len 属性而非空字符来判断字符串是否结束。
5、兼容部分 C 字符串函数
尽管 SDS 的 API 都是二进制安全的,但它们依然遵循 C 字符串以空字符串结尾的惯例,这主要是为了让那些保存文本数据的 SDS 可以重用一部分 C 中的字符串函数。
Redis 中的列表结构是基于双端链表的,因此它既支持栈操作,也支持队列操作。除列表键值外,Redis 中的发布与订阅、慢查询、监视器等功能也都用到了链表结构。每个链表节点都使用一个 listNode 结构来表示,此外,为了方便操作,Redis 用了一个 list 结构来封装了 listNode 结构组成的链表。这两种结构的定义如下:
为实现多态,以便链表可以用于保存各种不同类型的值,listNode 结构中使用了“void *”空指针来保存节点值,并通过 list 结构中的 dup、free 和 match 三个属性来为节点值设置类型特定函数。
参考:
1、《Redis 设计与实现》第二章——简单动态字符串。
2、《Redis 设计与实现》第三章——链表。
SDS 结构的定义如下:
struct sdshdr{ int len; // 记录 buf 数组中已使用的字节数,等于 SDS 所保存的字符串的长度 int free; // 记录 buf 数组中未使用的字节数 char buf[]; // 保存真正的字节数据,长度为:len + free + 1(额外的一字节用于保存末尾的空字符) };
之所以采用 SDS 结构而非直接使用 C 风格字符串,主要是为了满足 Redis 对字符串在安全性、效率以及功能方面的要求。这主要表现在以下几方面。
1、获取字符串长度的复杂度
因为访问 C 字符串的长度则需要 O(N)(N 为字符串的长度),而根据 SDS 结构的定义可知,要获取其保存的字符串的长度,只需访问 len 属性即可,时间复杂度为 O(1),这避免了在 Redis 中反复执行 STRLEN 命令对系统性能造成的影响。
2、杜绝缓冲区溢出
SDS 的内存分配策略能保证在每次修改 SDS 底层存储的字符串时,buf 数组有足够的空间容纳新的字符串,从而避免了缓冲区溢出的可能。
3、使用了空间预分配和惰性空间释放来优化内存分配
当剩余的未使用空间 free 不能容纳修改后增长的字节长度时,使用空间预分配能减少连续执行字符串增长操作所需的内存重分配次数。具体的预分配策略算法如下:
a)若修改后 SDS 的字符串长度 len 小于 1MB,则分配和 len 同样大小的未使用空间 free,此时 SDS 的属性 len 和 free 的值相同。
b)若修改后 SDS 的字符串长度 len 不小于 1MB,则额外分配 free 为 1MB 的未使用空间。
而使用惰性空间释放则是指:在需要缩短 SDS 保存的字符串时,程序并不立即释放缩短后多出来的空间,而是追加到 free 属性中,以备将来使用。
4、二进制安全
由于 C 字符串是以空字符来区分字符串是否结束,所以这使得其只能保存文本数据,而不能保存数据中可能含有空字符的二进制数据(如图片、音频、视频和压缩文件等)。为了确保 Redis 可以适用于多种场景,SDS 的 API 都是二进制安全的(binary-safe)。这也是将 buf 称为字节数组的原因,因为 Redis 不是用它来保存字符,而是用来保存一系列二进制数据。因此 SDS 是使用 len 属性而非空字符来判断字符串是否结束。
5、兼容部分 C 字符串函数
尽管 SDS 的 API 都是二进制安全的,但它们依然遵循 C 字符串以空字符串结尾的惯例,这主要是为了让那些保存文本数据的 SDS 可以重用一部分 C 中的字符串函数。
Redis 中的列表结构是基于双端链表的,因此它既支持栈操作,也支持队列操作。除列表键值外,Redis 中的发布与订阅、慢查询、监视器等功能也都用到了链表结构。每个链表节点都使用一个 listNode 结构来表示,此外,为了方便操作,Redis 用了一个 list 结构来封装了 listNode 结构组成的链表。这两种结构的定义如下:
typedef struct listNode{ struct listNode *prev; // 前置节点 struct listNode *next; // 后置节点 void *value; // 节点值 }listNode; typedef struct list{ listNode *head; // 表头节点 listNode *tail; // 表尾节点 unsigned long len; // 列表所包含的节点数量 void *(*dup)(void *ptr); // 节点值复制函数 void (*free)(void *ptr); // 节点值释放函数 int (*match)(void *ptr, void *key); // 节点值对比函数 }list;
为实现多态,以便链表可以用于保存各种不同类型的值,listNode 结构中使用了“void *”空指针来保存节点值,并通过 list 结构中的 dup、free 和 match 三个属性来为节点值设置类型特定函数。
参考:
1、《Redis 设计与实现》第二章——简单动态字符串。
2、《Redis 设计与实现》第三章——链表。
发表评论
-
Lua 脚本
2019-10-07 19:49 665Redis 2.6 版本开始引入对 Lua 脚 ... -
Redis事务的实现
2019-09-22 18:56 466Redis 事务是 ... -
Redis集群之复制、故障转移及消息实现
2019-09-14 21:04 497在Redis集群 ... -
Redis集群实现原理
2019-09-14 12:19 662Redis 集群是 Redis 提供的分布式数 ... -
sentinel 系统介绍
2019-08-04 18:35 500Sentinel(哨兵)是 Redis 的高可 ... -
数据库复制
2019-07-13 22:02 364在连接到一 ... -
redis 客户端实现
2019-06-02 15:06 370Redis 服务器是典型的一对多服务器程序,通 ... -
AOF 持久化
2019-05-12 13:36 412除了前面提到的 RDB 持久化功能外,Redi ... -
RDB 文件结构
2019-04-27 12:10 576在RDB 持久化一节中,我们对 RDB 持久化 ... -
RDB 持久化
2019-04-14 17:20 419RDB 持久化功能可以将 Redis 在某个时 ... -
Redis 数据库通知功能的实现
2019-04-07 11:56 1280Reids 数据库通知功能可以让客户端通过订阅 ... -
数据库实现
2019-03-24 13:58 437Redis 服务器将其所有的数据库都保存在 r ... -
Redis 五种对象
2019-01-20 11:13 361阅读本节前需要阅读 Redis 对象系统概览一 ... -
Redis 对象系统概览
2019-01-06 13:10 777前面介绍了 Redis 中用到的所有主要数据结 ... -
整数集合与压缩列表
2018-12-09 21:19 592在 Redis 中,当一 ... -
跳跃表在 Redis 中的应用
2018-08-23 16:30 2023前提申明,因篇幅 ... -
字典实现
2018-08-20 15:49 564字典在 Redis 中的应用相当广泛,如 Redis ...
相关推荐
### 使用SDS代码结构实现Redis字符串的编写 #### SDS简介 Redis是一款高性能的键值存储系统,因其出色的性能和灵活性而被广泛应用于多种场景。为了达到高性能的目标,Redis在很多方面都进行了精心设计,其中就包括...
Redis作为一个键值对数据库,键和值可以是多种类型的对象,如字符串、集合或列表。对于存储字符串的字符串对象,它们内部就包含了一个`sds`值。例如,通过`SET`和`GET`命令创建的键值对,其键和值都是字符串对象,...
Redis字符串的另一个重要特性是它可以作为计数器使用,通过INCR、INCRBY和DECR、DECRBY等命令进行原子性的递增或递减操作,这在分布式环境中非常有用,例如统计网站访问量或者实现限流策略。 需要注意的是,Redis的...
SDS 是 Redis 为了提高字符串操作的效率和安全性而自定义的一种数据结构,它在 Redis 的各种操作中扮演着重要角色,包括作为键值对中的键和值,以及作为缓冲区(buffer)。 SDS 结构包含三个字段: 1. `len`:表示...
它支持多种数据结构,包括字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)。在Java开发中,为了方便与Redis进行交互,通常会封装一个工具类,本文将详细介绍如何封装一个基于...
Redis字符串原理的深入理解 Redis作为一种高性能的Key-Value存储系统,其数据结构的设计和实现对于性能至关重要。本文主要探讨Redis中的字符串(String)数据结构,包括它的特性、内部实现以及编码格式,帮助读者...
Redis支持多种数据结构,如字符串、哈希、列表、集合和有序集合。以下是一些基本操作的例子: 1. **字符串操作**: 设置键值对: ```csharp var db = redis.GetDatabase(); db.StringSet("key", "value"); ```...
工具类封装了基本的 Redis 操作,如字符串、哈希表、列表、集合的处理,还包括了分布式锁的实现。这种封装不仅提高了代码的可读性和可维护性,还减少了重复代码的编写。 1、字符串操作 get(key)、set(key, value)、...
1. 数据类型:Redis支持五种基本数据类型,包括字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)。这些数据类型提供了丰富的操作,满足各种应用场景。 2. 主从复制:Redis支持主从复制,...
简单来说就是用java实现远程操作redis,ip地址要找到自己linux上连网后的ip地址,在每个case文件中修改后就可以实现了,对应的test文件是实现操作文件,你可以自己写一个主程序把他们包括起来。哦,对了这里面包括了...
而Redis则是一种高性能的键值对存储数据库,支持多种数据结构如字符串、哈希、列表、集合和有序集合,非常适合用来存储Session数据。 接下来,我们来具体实施Tomcat和Redis的集成步骤: 1. **安装Redis**:在开始...
Redis支持五种基本数据类型:字符串(Strings)、哈希(Hashes)、列表(Lists)、集合(Sets)和有序集合(Sorted Sets)。这些数据类型的灵活性使得Redis能应对多种应用场景,如存储用户信息、实现消息队列等。 2. **Redis...
首先,要进行Redis数据的导入和导出,我们需要了解Redis的数据结构,包括字符串(Strings)、哈希(Hashes)、列表(Lists)、集合(Sets)和有序集合(Sorted Sets)。这些数据类型在Java中都有对应的客户端库支持,如Jedis和...
SpringBoot中利用Redis实现消息队列,代码亲测可用, 可以传输字符串,或java对象都可以
字典结构在大多数脚本语言中都非常常见,其中键值对不仅限于简单的字符串,还可以是更复杂的数据类型如列表、集合等。通过TCP协议,应用程序可以轻松地对Redis中的数据进行读写操作。 **(二)内存存储与持久化** ...
它支持多种数据类型的操作,如字符串、哈希、集合、有序集合等,同时包含发布订阅功能。通过这个库,我们可以在.NET应用中方便地实现Redis的发布订阅功能。 3. Key过期通知(Expiration Notifications): Redis...
它支持丰富的数据结构,如字符串、哈希、列表、集合、有序集合,同时提供了丰富的API,使得与各种应用集成变得简单。在本示例中,我们将使用Redis作为Session的存储介质。 实现步骤如下: 1. **安装和配置Redis**...
与传统的键值存储系统Memcached相比,Redis支持更多的数据类型和丰富的操作,包括字符串(Strings)、列表(Lists)、集合(Sets)和有序集合(ZSets)等。 - **数据类型及其操作**:Redis支持的数据类型非常丰富,包括基本...
2. **JSON字符串存储**:最简单的方式是将Java对象转换为JSON字符串,然后存储为Redis中的String类型。Fastjson库在这里被用到,其`toJSONString`方法可以将Java对象转化为JSON格式的字符串。获取时,直接返回JSON...