Redis- 简单动态字符串

本贴最后更新于 2984 天前,其中的信息可能已经斗转星移

Redis 没有直接使用 C 语言传统的字符串,而自己构建了一种简单动态字符串(Simple Dynamic String)的抽象类型,简称为 SDS。并将 SDS 作为 Redis 的默认字符串表示。

例如:当我们在 redis-client 执行如下的命令时;

> redis 127.0.0.1:6379>set message 'Hello World' > > OK

那么 Redis 将会在数据库中创建一个新的键值对,其中:

  • 键值对的键是一个字符串对象,对象底层的实现是一个保存着字符串“msg”的 SDS。
  • 键值对的值也是一个字符串对象,对象底层的实现是一个保存着字符串“Hello World”的 SDS。

SDS 的定义

每个 sds.h/sdshdr 结构表示一个 SDS 值:

struct sdshdr{ int len; //记录buf中已使用字节的数量等于SDS所保存的字符串的长度 int free; //记录buf中未使用字节的长度 char []buf; //字节数据,保存字符串 }

获取字符串的长度

Redis 获取字符串长度可以通过 SDS 中的 len 属性来获得,时间复杂度为 O(1)。而 C 语言获取字符串需要去遍历 char 数据来叠加获得,时间复杂度为 O(n)。这就保证了在获取字符串长度时不会成为 Redis 的性能瓶颈。

杜绝缓存区溢出

除了获取字符串长度复杂度高之外,C 语言不记录自身字符串长度带来的另一个问题是容易造成缓存区溢出(Buffer Overflow)。SDS 属性 len 可以记录自身字符串的长度,因此当对 SDS 字符串进行拼接时,SDS API 会先去检测 buf 的空间,如果空间不足,SDS 先会扩容 buf 的空间,之后进行拼接。反之,直接去拼接。

减少修改字符串带来的内存重分配次数

  • 空间预分配

空间预分配用于优化 SDS 字符串增长操作,当 SDS 的 API 对 SDS 的字符串进行修改,并且要对 SDS 进行空间扩展的时候,程序不仅会为 SDS 分配修改所必须要的空间,还会为 SDS 分配额外未使用的空间。分配公式主要有 SDS 中的 len 属性的大小决定。当 len 属性值小于 1MB 时,buf 数组的实际长度为 len(修改后的 len 值)*2+1byte,这时 len 和 free 相等,一个字节用于保存空字符。当 len 属性值大于 1MB 时,buf 数组的实际长度为 len(修改后的 len 值)+1MB+1byte,这时 free 的值为 1MB。通过内存预分配策略,Redis 可以减少连续执行字符串增长操作所需要的内存重分配次数。

  • 惰性空间释放

惰性空间释放用于优化 SDS 字符串缩短操作:当 SDS 的 API 需要缩短 SDS 所保存的字符串时,程序并不立即去使用内存重分配来回收字符串缩短后多出来的字节,而是使用 free 属性将这些字节的数量记录起来并等待将来使用。

二进制安全

由于 SDS 是通过 len 属性来判断字符串是否结束的,而不是使用空字符串来判断字符串是否结束的,并且 SDS 的 API 都是二进制安全的,所有的 SDS API 都会以处理二进制的方式来处理 SDS 存放在 buf 数组中的数据,程序不会对数组中的数据进行任何的过滤,限制,假设,数据在写入和读出的时候是一致的。

兼容部分 C 字符串函数

虽然 SDS API 是二进制安全的,但它依然遵循 C 字符串以空字符结尾的惯例。

总结

C 语言字符串 SDS
获取字符串长度的时间复杂度为 O(N) 获取字符串长度的时间复杂度为 O(1)
API 是不安全的,可能会造成缓存区溢出 API 是安全的,不会造成缓存区溢出
修改字符串 N 次必须需要执行 N 次内存重分配 修改字符串 N 次最多需要执行 N 次内存重分配
只能保存文本数据 可以保存文本和二进制数据
可以使用所有的函数 可以使用部分函数

SDS API

函数 作用 时间复杂度
sdsnew 创建一个给定包含 C 字符串的 SDS O(N),N 为给定 C 字符串的长度
sdsempty 创建一个不包含任何内容的空 SDS O(1)
sdsfree 释放给定的 SDS O(N),N 为被释放的 SDS 的长度
sdslen 返回 SDS 已使用的字节数 可以直接去读取 SDS 的 len 属性,O(1)
sdsavail 返回 SDS 未使用的字节数 可以直接去读取 SDS 的 free 属性,O(1)
sdsdup 创建一个给定 SDS 的副本(copy) O(N),N 为给定 SDS 的长度
sdsclear 清空给定的 SDS 字符串内容 使用惰性空间释放策略,O(1)
sdscat 将给定的 C 字符串拼接到 SDS 字符串的末尾 O(N),N 为拼接 C 字符串的长度
sdscatsds 将给定的 SDS 字符串拼接到另一个 SDS 字符串的末尾 O(N),N 为拼接 SDS 字符串的长度
sdscpy 将给定的 C 字符串复制到 SDS 中,覆盖原来 SDS 中的字符串 O(N),N 为被复制 C 字符串的长度
sdsgrowzero 用空字符串将 SDS 扩展到指定的长度 O(N),N 被扩展的新增字节数
sdsrange 保留 SDS 给定区域的数据,不在区域的数据覆盖或者清除 O(N),N 被保留的字节数
sdstrim 接受一个 SDS 和 C 字符串的参数,从 SDS 中移除所有在 C 字符串中出现过的字符 O(N*N),N 为给定 C 字符串的长度
sdscmp 对比两个 SDS 是否相等 O(N),N 两个 SDS 中 len 较小的值
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    284 引用 • 248 回帖
  • 数据结构
    87 引用 • 115 回帖 • 4 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
SimpleBin
改变自己晴空万里,埋怨别人天昏地暗。 西安

推荐标签 标签

  • 黑曜石

    黑曜石是一款强大的知识库工具,支持本地 Markdown 文件编辑,支持双向链接和关系图。

    A second brain, for you, forever.

    24 引用 • 242 回帖
  • 30Seconds

    📙 前端知识精选集,包含 HTML、CSS、JavaScript、React、Node、安全等方面,每天仅需 30 秒。

    • 精选常见面试题,帮助您准备下一次面试
    • 精选常见交互,帮助您拥有简洁酷炫的站点
    • 精选有用的 React 片段,帮助你获取最佳实践
    • 精选常见代码集,帮助您提高打码效率
    • 整理前端界的最新资讯,邀您一同探索新世界
    488 引用 • 384 回帖 • 5 关注
  • Office

    Office 现已更名为 Microsoft 365. Microsoft 365 将高级 Office 应用(如 Word、Excel 和 PowerPoint)与 1 TB 的 OneDrive 云存储空间、高级安全性等结合在一起,可帮助你在任何设备上完成操作。

    5 引用 • 34 回帖
  • Swagger

    Swagger 是一款非常流行的 API 开发工具,它遵循 OpenAPI Specification(这是一种通用的、和编程语言无关的 API 描述规范)。Swagger 贯穿整个 API 生命周期,如 API 的设计、编写文档、测试和部署。

    26 引用 • 35 回帖 • 3 关注
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    336 引用 • 324 回帖
  • SMTP

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。

    4 引用 • 18 回帖 • 630 关注
  • BND

    BND(Baidu Netdisk Downloader)是一款图形界面的百度网盘不限速下载器,支持 Windows、Linux 和 Mac,详细介绍请看这里

    107 引用 • 1281 回帖 • 36 关注
  • Notion

    Notion - The all-in-one workspace for your notes, tasks, wikis, and databases.

    10 引用 • 77 回帖
  • 又拍云

    又拍云是国内领先的 CDN 服务提供商,国家工信部认证通过的“可信云”,乌云众测平台认证的“安全云”,为移动时代的创业者提供新一代的 CDN 加速服务。

    20 引用 • 37 回帖 • 579 关注
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    45 引用 • 114 回帖 • 172 关注
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 1 关注
  • OneNote
    1 引用 • 3 回帖 • 1 关注
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖 • 1 关注
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖 • 1 关注
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 438 关注
  • GAE

    Google App Engine(GAE)是 Google 管理的数据中心中用于 WEB 应用程序的开发和托管的平台。2008 年 4 月 发布第一个测试版本。目前支持 Python、Java 和 Go 开发部署。全球已有数十万的开发者在其上开发了众多的应用。

    14 引用 • 42 回帖 • 820 关注
  • 书籍

    宋真宗赵恒曾经说过:“书中自有黄金屋,书中自有颜如玉。”

    81 引用 • 409 回帖
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 560 关注
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 368 关注
  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 182 关注
  • Outlook
    1 引用 • 5 回帖 • 5 关注
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    315 引用 • 547 回帖 • 1 关注
  • 智能合约

    智能合约(Smart contract)是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于 1994 年由 Nick Szabo 首次提出。

    1 引用 • 11 回帖 • 3 关注
  • 阿里巴巴

    阿里巴巴网络技术有限公司(简称:阿里巴巴集团)是以曾担任英语教师的马云为首的 18 人,于 1999 年在中国杭州创立,他们相信互联网能够创造公平的竞争环境,让小企业通过创新与科技扩展业务,并在参与国内或全球市场竞争时处于更有利的位置。

    43 引用 • 221 回帖 • 59 关注
  • Follow
    4 引用 • 12 回帖 • 2 关注
  • 职场

    找到自己的位置,萌新烦恼少。

    127 引用 • 1708 回帖
  • Firefox

    Mozilla Firefox 中文俗称“火狐”(正式缩写为 Fx 或 fx,非正式缩写为 FF),是一个开源的网页浏览器,使用 Gecko 排版引擎,支持多种操作系统,如 Windows、OSX 及 Linux 等。

    7 引用 • 30 回帖 • 384 关注