String 数据结构

首先我来看下, Redis 中 String 的数据结构:

我们称之为 SDS (Simple Dynamic String) 简单动态字符串

struct sdshdr {
//记录buf数组中已经使用的字节数(等价于字符串的长度strlen)
int len; //记录buf数组中未使用的字节数(用于动态扩容)
int free; //字节数组,用于保存字符串
char buf[];
}

对比C语言字符串:

  • 优化了获取字符串长度的时间复杂度为: O(1)

    因为 SDS 维护了一个 len 字段,这个字段的设置和更新是由 SDS 的 API 在执行时自动完成的。

  • 杜绝缓冲区溢出

    在使用 c 语言函数 strcat(s1, " Cluster") (在 s1 字符串后面拼接另一个字符串) 时,如果忘记提前为 s1 分配足够的空间,那么 strcat 函数执行之后, 将会导致s1后面的空间内容被意外修改。

    而 Redis 在对 SDS 修改时,会提前检查长度时候足够,才执行相关操作, 如果长度不够,会先扩展 s 的空间, 再执行

  • 减少内存重分配

    在 SDS 维护了 free 字段,可以知道未使用的字节数,这样在动态扩充字符串时可以根据这个值判断要不要重新分配内存

  • 二进制安全

    C语言是依靠 \0 作为字符串的结束标志的,这意味着字符串中间不能再次包含 \0 字符, 而 SDS 记录了字符串的实际长度, 所以它可以做更多的事情, 比如保存图片

  • 兼容部分 C字符串函数

    虽然 SDS 是 二进制安全的,但他们都遵守在字符串末尾额外分配一个字节容纳 \0 当结尾,这就是为了让那些保存文本数据的 SDS 可以重用 <string.h> 库

RedisObject 数据结构

在redis中存储的每个对象都表示为一个redisObject,它记录了这个对象的数据类型,编码方式,指向实际内容的指针等

typedef struct redisObject {
// 类型 4bits (String,Hash,Set,List等)
unsigned type:4; // 编码方式 4bits (int, embstr, raw 等)
unsigned encoding:4; // LRU 时间(相对于 server.lruclock) 24bits
unsigned lru:22; // 引用计数 Redis里面的数据可以通过引用计数进行共享 32bits
int refcount; // 指向实际存储的对象 (比如:指向一个SDS字符串对象) 64bits
void *ptr;
} robj;

String的三种编码方式

  • int

    当保存的值为整数且值的大小不超过long的范围,使用整数存储

  • embstr

    当字符串长度不超过44个字节时,使用embstr编码

    (只实现一次分配内存空间,只允许读,若修改数据,就会转成raw编码)

  • raw

    大于44字节时,用raw编码

int编码不必多说,为了数值计算方便

为什么要分为 embstr 和 raw 呢?

首先来张图,直观感受下,这2种存储方式的内存布局:

  • embstr 是连续存储的,也就是说 RedisObject 对象头 和 SDS 字符串的实际内容 是连续在一起存储的,也就是 RedisObject 中的ptr 指向的内容,就紧跟着在后面 (只要分配1次内存)
  • raw 是不连续存储的, ptr 指向的内容,是单独分配的(要分配2次内存)

这么做的原因当然是为了性能考虑,Redis考虑到多数字符串,可能都不会很长, 这样使用 embstr 只需分配一次内存(也很小),而且还是连续的存储,性能很高,也有利于减少内存碎片

String编码演示

  • 使用 TYPE key 查看对象的数据类型
  • 使用 OBJECT ENCODING key 查看对象的编码方式

演示 int 编码:

127.0.0.1:6379> set age 100
OK
127.0.0.1:6379> type age
string
127.0.0.1:6379> object encoding age
"int"

演示 embstr 编码:

127.0.0.1:6379> SET name tom
OK
127.0.0.1:6379> TYPE name
string
127.0.0.1:6379> OBJECT ENCODING name
"embstr"

演示 raw 编码:

127.0.0.1:6379> set name sdsdnjjkasjdnnjasjdnasldklaksdkkansndmasdulasndnkadashdahsdhkpasduasdybasbdvcfaffafkgsaas
OK
127.0.0.1:6379> type name
string
127.0.0.1:6379> object encoding name
"raw"

String的常用命令

  • SET: 添加或修改一个已经存在的String类型的键值对
  • GET: 根据key获取String类型的value
  • INCR: 让一个整形存储的String类型的value自增1
  • INCRBY: 让一个整形存储的String类型的value自增指定的步长, 例如 incrby num 2, 让num的值自增2
  • INCRBYFLOAT: 让一个浮点类型的数值自增指定的步长
  • SETNX: 添加一个String类型的键值对,前提是这个key不存在,否则不执行(可用于实现分布式锁)
  • SETEX: 添加一个String类型的键值对,并且指定超时时间
  • 更多 String 命令,请查阅 官方文档

Redis 原理 - String的更多相关文章

  1. 一、Redis基本操作——String(原理篇)

    小喵的唠叨话:最近京东图书大减价,小喵手痒了就买了本<Redis设计与实现>[1]来看看.这里权当小喵看书的笔记啦.这一系列的模式,主要是先介绍Redis的实现原理(可能很大一部分会直接照 ...

  2. 二、Redis基本操作——String(实战篇)

    小喵万万没想到,上一篇博客,居然已经被阅读600次了!!!让小喵感觉压力颇大.万一有写错的地方,岂不是会误导很多筒子们.所以,恳请大家,如果看到小喵的博客有什么不对的地方,请尽快指正!谢谢! 小喵的唠 ...

  3. Redis详细讲解(Redis原理,Redis安装,Redis配置,Redis使用,Redis命令)

    一.Redis介绍 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年3月15日起,Redis的开发 ...

  4. Redis原理篇

    Redis原理篇 1.发布 订阅模式 1.1列表 的局限 ​ 前面我们说通过队列的 rpush 和 lpop 可以实现消息队列(队尾进队头出),但是消费者需要不停地调用 lpop 查看 List 中是 ...

  5. Redis原理详解

    Redis原理详解 数据类型 Redis最为常用的数据类型主要有以下五种: String Hash List Set Sorted set 在具体描述这几种数据类型之前,我们先通过一张图了解下Redi ...

  6. Redis之String

    一.Redis之String简介 1. String是redis最基本的数据类型,一个key对应一个value. 2. String是二进制安全的,可以包含任何数据,例如图片或序列化的对象. 3. S ...

  7. redis对string进行的相关操作

    redis对string类型操作的相关命令以及如何在python使用这些命令 redis对string类型操作的命令: 命令 语法 概述 返回值 Redis SET 命令  set key value ...

  8. Redis操作string

    Redis简介: ''' redis: 缓存,例如两个个程序A,B之间要进行数据共享,A可以把数据存在redis(内存里),其他程序都可以访问redis里的数据, 这样通过中间商redis就实现了两个 ...

  9. Redis学习-string数据类型

    Redis 是一个开源的使用 ANSI C 语言编写.支持网络.可基于内存亦可持久化的日志 型.Key-Value 数据库. redis提供五种数据类型string,hash,list,set及sor ...

  10. 使用Redis数据库(String类型)

    一 String类型 首先使用启动服务器进程 : redis-server.exe 1. Set 设置Key对应的值为String 类型的value. 例子:向 Redis数据库中插入一条数据类型为S ...

随机推荐

  1. Windows安全加固(三)

    五.网络安全配置 协议安全 1.SYN攻击保护 指定触发SYN洪水攻击保护所必须超过的TCP连接请求数阈值为5:指定处于SYN_RCVD状态的TCP连接数的阈值为500,指定处于至少已发送一次重传的S ...

  2. Solution Set -「AGC 007~009」C~F

    目录 「AGC 007C」Pushing Balls 「AGC 007D」Shik and Game 「AGC 007E」Shik and Travel ^ 「AGC 007F」Shik and Co ...

  3. VS2022推送代码 到github错误: CertGetCertificateChain trust error CERT_TRUST_IS_PARTIAL_CHAIN的解决办法

    VS2022推送代码 到github错误: CertGetCertificateChain trust error CERT_TRUST_IS_PARTIAL_CHAIN 解决办法: 进入到 选项&g ...

  4. c# WPF convert photo to Sketch effects

    using the online website https://imagetosketch.com/ <Window x:Class="WpfMosaic.PhotoSketchWi ...

  5. nginx平台初探-1

    初探nginx架构(100%) 众所周知,nginx性能高,而nginx的高性能与其架构是分不开的.那么nginx究竟是怎么样的呢?这一节我们先来初识一下nginx框架吧. nginx在启动后,在un ...

  6. HERS: Homomorphically Encrypted Representation Search-2020:学习

    阅读"HERS: Homomorphically Encrypted Representation Search-2020",记录笔记. 摘要 本文介绍了一种针对加密图像的搜索方法 ...

  7. 在nginx上搭建php服务

    不同的操作系统会有不一样 我这里用的是centos系统 首先下载 yum install php php-fpm php-mysqlnd php-gd php-mbstring 其次我们需要修改配置文 ...

  8. 微信小程序block的作用

    有了block标签过后,你就可以把if 或则 for 语句写在block标签里面; 这样就控制了这一块的逻辑. 个人建议是要是v-if和v-for的都可以写在block上: block并不是一个组件, ...

  9. Integer超过128要用对象比较,否则出问题

    一.测试代码 public void testEquals() { int int1 = 12; int int2 = 12; Integer integer1 = new Integer(12); ...

  10. 单机麒麟kylin安装

    https://archive.apache.org/dist/kylin/ 2.5.0版本 首先启动hadoop.hive.hbase 并记得设置环境变量 #JDK export JAVA_HOME ...