Redis 设计与实现,看 SDS(Simple Dynamic String) 感悟

今天在看 Redis 设计与实现这本书的时候,发现了里面系统定义的数据结构 SDS,中文名为 简单动态字符串。对其设计的思想挺有收获的。

SDS 的定义,位于 sds.h/sdshdr 中:结构如下:

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

SDS 与 C 字符串的区别:

  1. C 语言使用长度为 N+1 的 字符数组来表示长度为 N 的字符串, 并且字符串最后一个元素总为 \0
  2. C 字符串并不记录自身的长度信息,所以 取长度的操作为 O(N),SDS 的取长度操作为  O(1)
  3. C 语言容易 缓冲区 溢出,由于其不记录自身长度所带来的。

接下来是关键:  **空间预分配 和 惰性空间释放 **这两种优化策略。

空间预分配

主要用于优化 SDS 的字符串增长操作:当 SDS 的API 对一个 SDS 进行修改,并且需要对 SDS 进行空间扩展时,程序不仅会为 SDS 分配修改所需要必须要的空间,还会为 SDS 分配额外未使用的空间。

额外分配的算法如下:

if len < 1MB
free = len;
else
free = 1MB

假设进行修改之后, SDS 的长度 小于 1MB,假设修改之后  SDS 的 len 为 13, 那么  free 也为 13。 SDS 的 buf 长度将为 13 + 13 + 1 。 其中 1 字节 为 "\0";

惰性空间释放

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

假设有个如下的 SDS 结构:

进行 sdstrim(s, "XY");// 移除 SDS 字符串中所有的 'X' 和 'Y'

SDS 就变成了如下这样,

可以看到,SDS 并没有释放多出来的 5 字节空间,而是将这五个字节空间作为未使用空间保留在 SDS 里面。如果将来要对 SDS 进行增长的话,这些未使用的空间就可以排上用场了。

假设我们现在用进行  sdscat(s, "KO");
那么结构就变成了如下:

这样就避免了缩短字符串时所带来的的内存重分配操作。今天在坐公交时看到的这个数据结构的实现,这个设计思想应该是带给我收获最多的。

预分配,预处理,延时的思想。
在 C# 中,我记得有个 LazyInitialization,延时加载这玩意,如有一个对象和类是 属于延时加载的,那么只有在真正用到时才会去加载它。
也让我想到了 RFC2616 HTTP/1.1 协议中的一个 HTTP 连接池的这个标准的一个实现,在 HttpWebRequest 中 一个 Host 默认的存在的连接池是 2 个,但是可以通过 ServicePointManager.DefaultConnectionLimit 获取到默认的连接限制数

The maximum number of concurrent connections allowed by a ServicePoint object. The default connection limit is 10 for ASP.NET hosted applications and 2 for all others. When an app is running as an ASP.NET host, it is not possible to alter the value of this property through the config file if the autoConfig property is set to true. However, you can change the value programmatically when the autoConfig property is true. Set your preferred value once, when the AppDomain loads.

这种思想可以运用在哪里呢?我思考了一下:
不知道准确不准确, 想到了一个 缓存的。以博客园首页的前 20 篇文章为例,预分配:设置每篇文章在 Redis 中的缓存时间为10 分钟, 600秒。假设在 600 秒内,有用户点击了 第一篇文章,那么更新其 缓存失效时间为 1200 秒(基于第一个用户点击,那么可能就会有第二个用户点击之瞎说理论),假设 1200 秒内没有用户点击该文章,那么降低其 缓存时间为 600, 依次类推。

不太靠谱的伪代码:

set blog_item_1 expired_time 600;
blog_display_time = current_time; if have one user click blog_item_1
var blog_click_time = current_Time;
expired_time = expired_time * 2; if current_time > blog_click_time.addSecond(600) && have one user click blog_item_1
expired_time = expired_time * 2; if current_time < blog_display_time.addSecond(1200)
expired_time = exipred_time / 2;

Redis 设计与实现,看 SDS(Simple Dynamic String) 感悟的更多相关文章

  1. Redis 设计与实现笔记 - SDS

    Redis 中的字符串没有使用 C语言中的字符指针(char *),而是使用了自定义的结构 sds. 文件: sds.h sds.c 结构: struct sdshdr { int len; // 填 ...

  2. redis源码分析(一)-sds实现

    redis支持多种数据类型,sds(simple dynamic string)是最基本的一种,redis中的字符串类型大多使用sds保存,它支持动态的扩展与压缩,并提供许多工具函数.这篇文章将分析s ...

  3. Redis设计与实现(一~五整合版)【搬运】

    Redis设计与实现(一~五整合版) by @飘过的小牛 一 前言 项目中用到了redis,但用到的都是最最基本的功能,比如简单的slave机制,数据结构只使用了字符串.但是一直听说redis是一个很 ...

  4. Redis源码分析(sds)

    源码版本:redis-4.0.1 源码位置:https://github.com/antirez/sds 一.SDS简介 sds (Simple Dynamic String),Simple的意思是简 ...

  5. Redis是什么?看这一篇就够了

    本文由葡萄城技术团队编撰并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 引言 在Web应用发展的初期,那时关系型数据库受到了较为广泛的关注和应用,原 ...

  6. 探索Redis设计与实现3:Redis内部数据结构详解——sds

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  7. Redis设计与实现 -- 动态字符串对象(SDS)

    1. 动态字符串( simple dynamic string, SDS) 在 Redis 中,当需要可以被重复修改的字符串时,会使用 SDS 类型 ,而不是 C 语言中默认的 C 字符串类型 .举个 ...

  8. 【Redis】简单动态字符串SDS

    C语言字符串 char *str = "redis"; // 可以不显式的添加\0,由编译器添加 char *str = "redis\0"; // 也可以添加 ...

  9. Redis设计与实现-内部数据结构篇

    题记:这本书是2015年11月份开始读的,大约花了一个多月的时间通读了一遍,最近由于需要对redis做一些深入的了解,因此又花了两个多月仔细精读了一遍,由于本书设计的内容较多,且每部分的内容都比较细致 ...

随机推荐

  1. jemalloc内存占用问题

    最近,有部分越南的服务器内存不断上涨,怀疑是内存泄漏,因为框架提供的内存报告里,C内存和Lua占用内存都不大,和ps里看的差好多.总内存在12G左右,C和Lua的加起来约4G,两者相差了8G 经过一番 ...

  2. wpf 两个自定义控件

    wpf 两个自定义控件 一个是IP控件,一个滑动条.先看下效果图 IPControl 1.实际工作中有时需要设置IP信息,就想着做一个ip控件.效果没有window自带的好,需要通过tab切换.但也能 ...

  3. Razor 页面解说

    自己开始从头深造- 本是想将时间缩短,但发现自己还是很难呀.希望你理解吧,这里的知识 是 页面的基本信息.也页面的跳转关系和 Tag的帮助标签. Section   PartView.  @page ...

  4. Java生鲜电商平台-促销系统的架构设计与源码解析

    Java生鲜电商平台-促销系统的架构设计与源码解析 说明:本文重点讲解现在流行的促销方案以及源码解析,让大家对促销,纳新有一个深入的了解与学习过程. 促销系统是电商系统另外一个比较大,也是比较复杂的系 ...

  5. JS基础语法---函数---介绍、定义、函数参数、返回值

    函数: 把一坨重复的代码封装,在需要的时候直接调用即可 函数的作用: 代码的重用 函数需要先定义,然后才能使用 函数名字:要遵循驼峰命名法 函数一旦重名,后面的会把前面的函数覆盖 Ctrl +鼠标左键 ...

  6. js文件中模块化导入swiper.js文件方法

    es6导入: 在js文件顶端 import Swiper from "../../assets/javascripts/swiper.min"; import '../../ass ...

  7. 为Dynamics CRM注释的图片附件做个预览功能

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复163或者20151017可方便获取本文,同时可以在第一时间得到我发布的最新的博文信息,follow me! Dynamics CRM中注释可 ...

  8. linux内核 mtd分区

    首先 内核配置需要打开MTD选项 Memory Technology Devices (MTD) ---> 如果是NOR Flash,需要选择Common Flash Interface (CF ...

  9. Linux—使用man命令:man:command not found

    # 用echo $PATH查看该环境变量.这种问题一般是环境变量PATH不对的问题. [root@localhost ~]# echo $PATH # 用whereis命令查看,该指令的位置. [ro ...

  10. softmax求导、cross-entropy求导及label smoothing

    softmax求导 softmax层的输出为 其中,表示第L层第j个神经元的输入,表示第L层第j个神经元的输出,e表示自然常数. 现在求对的导数, 如果j=i,   1 如果ji, 2 cross-e ...