Redis 源码分析字符串对象(z_string)

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis 源码分析字符串对象(z_string)

字符串对象



字符对象的三种编码可以是 int, raw 或者 embstr, 三种情况我分别来说明一下:


  1. 如果一个字符串对象保存的整数值,并且这个整数值可以用 long 类型来表示,那么这个字符串会将整数值保存在字符串对象结构的 ptr 属性值里面,并且字符串对象的编码设置为 int.


  1. 如果一个字符串保存的是一个字符值,并且这个字符串长度小于等于 32 字节,那么这个字符串讲使用 embstr 编码的形式来保存这个字符串值。


  1. embstr 编码是专门用来保存短字符串的一种优化编码方式这种编码和 raw 编码一样,都是使用 redisObject 中的 sdshdr 结构来表示字符串对象,但是 raw 会调用两次内存比分配函数来创建 redisObject 结构和 sdshdr 结构,而 embstr 编码则通过调用一次内存分配一款连续空间,空间依次包含 redisObject 和 sdshdr 两个结构


int 编码的字符串如下:


image.png


embstr 编码的字符如下:


image.png


raw 编码的字符如下:


image.png


下面是 redisObject 所有的类型:


char *strEncoding(int encoding) {
    switch(encoding) {
    case OBJ_ENCODING_RAW: return "raw";
    case OBJ_ENCODING_INT: return "int";
    case OBJ_ENCODING_HT: return "hashtable";
    case OBJ_ENCODING_QUICKLIST: return "quicklist";
    case OBJ_ENCODING_ZIPLIST: return "ziplist";
    case OBJ_ENCODING_LISTPACK: return "listpack";
    case OBJ_ENCODING_INTSET: return "intset";
    case OBJ_ENCODING_SKIPLIST: return "skiplist";
    case OBJ_ENCODING_EMBSTR: return "embstr";
    case OBJ_ENCODING_STREAM: return "stream";
    default: return "unknown";
    }
}


我们本处主要是一起来分析 OBJ_ENCODING_INT、OBJ_ENCODING_RAW、OBJ_ENCODING_EMBSTR 三种情况


int (OBJ_ENCODING_INT)


长度小于 20 确保在一个长整型的范围内,2^64次方恰好占用 20 位,且是数字字符串类型。


image.png


其实这里就是可以涵盖了所有 long 类型的长整型。


embstr (OBJ_ENCODING_EMBSTR)


长度小于等于 44 个字符(包括浮点数)44 个字节是只要为了适应 jemalloc 分配的 64k arena


/* Create a string object with EMBSTR encoding if it is smaller than
 * OBJ_ENCODING_EMBSTR_SIZE_LIMIT, otherwise the RAW encoding is
 * used.
 *
 * The current limit of 44 is chosen so that the biggest string object
 * we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */
#define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44
robj *createStringObject(const char *ptr, size_t len) {
    if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)
        return createEmbeddedStringObject(ptr,len);
    else
        return createRawStringObject(ptr,len);
}


这块其实可以就是理解为一个短的字符串, 且非 20 位内的整形。


raw (OBJ_ENCODING_RAW)


长度大于 44 字节的字符串(包括浮点数), 简单总结就是其他的字符串,或者字符串浮点数。下面会做详细的对比。


raw 和 embstr 对比



raw 和 embstr 对比如下:


类型 特点 优点 缺点
embstr 1. 只分分配一次内存空间,因此 robj 和 sds 是连续的;2. 只读;3. Embstr 字符串需要修改时,会转换为 raw, 之后一直是 raw 1. 创建和删除只需要一次;2.查找速度快 1. 重新分配涉及到 robj 和 sds 整个对象,因此 embstr 是只读的
raw 1. robj 和 sds 非连续;2. 可以修改


embstr 创建过程如下:


image.png


redisObject 对象创建:


image.png


使用 append 命令修改字符串会改变字符串底层的类型:


image.png


通过这个实验,证明了两点:


  1. 浮点数 redis 用 embstr 存储。


  1. embstr 如果有 append 操作那么会转换为 raw 存储。


底层代码(embstr 转换 raw):


image.png


Redis 字符串限定



Redis 字符串约定长度不能大于 512m, 通常开发过程中字符串很难达到这么长,除非是你想存 base64 之类的, 默认值已经很大。


// 字符串最大长度限制
static int checkStringLength(client *c, long long size) {
    if (!(c->flags & CLIENT_MASTER) && size > server.proto_max_bulk_len) {
        addReplyError(c,"string exceeds maximum allowed size (proto-max-bulk-len)");
        return C_ERR;
    }
    return C_OK;
}


这长度我们可以在 redis.config 中配置, 配置 key proto-max-bulk-len 默认值:512mb. 如下图所示:


image.png


字符串使用场景



  • 缓存功能:mysql 做数据持久化存储,redis 做少量热数据缓存;


  • 计数器:如点赞次数,视频播放次数;


  • 限流:见基于 redis 的分布式限流;


使用命令和其他实践可以翻阅我以前的文章,本文不在赘述:



常用操作



image.png


参考文档



  • 《Redis 设计与实现》黄健宏


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
11小时前
|
存储 缓存 NoSQL
深入浅出Redis(一):对象与数据结构
深入浅出Redis(一):对象与数据结构
|
11小时前
string(字符串)
在 Lua 中,字符串可以用双引号或单引号定义,如 `string1 = &quot;this is string1&quot;` 和 `string2 = &#39;this is string2&#39;`。多行字符串可由两个方括号包围,例如 `html` 变量所示,它包含了一个 HTML 片段。Lua 会尝试将数字字符串转换为数值进行算术运算,但混合字符串和数字可能导致错误,如 `&quot;error&quot; + 1`。
|
11小时前
|
NoSQL Java Unix
Redis基础操作 String List
Redis基础操作 String List
9 0
|
11小时前
|
存储 NoSQL 安全
Redis入门到通关之Redis数据结构-String篇
Redis入门到通关之Redis数据结构-String篇
35 1
|
11小时前
|
存储 NoSQL 安全
Redis入门到通关之数据结构解析-动态字符串SDS
Redis入门到通关之数据结构解析-动态字符串SDS
18 0
|
11小时前
|
存储 缓存 NoSQL
Redis入门到通关之String命令
Redis入门到通关之String命令
18 0
|
11小时前
|
缓存 安全 Java
【Java基础】String、StringBuffer和StringBuilder三种字符串对比
【Java基础】String、StringBuffer和StringBuilder三种字符串对比
9 0
|
11小时前
|
存储 消息中间件 缓存
Redis 命令全解析之 String类型
Redis 命令全解析之 String类型
15 1
|
11小时前
|
存储 编译器 Linux
标准库中的string类(中)+仅仅反转字母+字符串中的第一个唯一字符+字符串相加——“C++”“Leetcode每日一题”
标准库中的string类(中)+仅仅反转字母+字符串中的第一个唯一字符+字符串相加——“C++”“Leetcode每日一题”
|
11小时前
|
存储 NoSQL Redis
Redis源码、面试指南(5)多机数据库、复制、哨兵、集群(下)
Redis源码、面试指南(5)多机数据库、复制、哨兵、集群
7 1