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

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
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
相关文章
|
14天前
|
Java
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
本文深入探讨了Java中方法参数的传递机制,包括值传递和引用传递的区别,以及String类对象的不可变性。通过详细讲解和示例代码,帮助读者理解参数传递的内部原理,并掌握在实际编程中正确处理参数传递的方法。关键词:Java, 方法参数传递, 值传递, 引用传递, String不可变性。
32 1
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
|
6天前
|
存储 消息中间件 NoSQL
Redis 数据结构与对象
【10月更文挑战第15天】在实际应用中,需要根据具体的业务需求和数据特点来选择合适的数据结构,并合理地设计数据模型,以充分发挥 Redis 的优势。
39 8
|
10天前
|
NoSQL Redis
Redis 字符串(String)
10月更文挑战第16天
26 4
|
21天前
|
canal 安全 索引
(StringBuffer和StringBuilder)以及回文串,字符串经典习题
(StringBuffer和StringBuilder)以及回文串,字符串经典习题
32 5
|
22天前
|
存储 分布式计算 NoSQL
大数据-40 Redis 类型集合 string list set sorted hash 指令列表 执行结果 附截图
大数据-40 Redis 类型集合 string list set sorted hash 指令列表 执行结果 附截图
23 3
|
25天前
|
JSON 缓存 NoSQL
Redis 在线查看序列化对象技术详解
Redis 在线查看序列化对象技术详解
28 2
|
1月前
|
存储 JavaScript 前端开发
JavaScript 字符串(String) 对象
JavaScript 字符串(String) 对象
38 3
|
2月前
|
存储 缓存 NoSQL
3)深度解密 Redis 的字符串
3)深度解密 Redis 的字符串
27 1
|
2月前
|
存储 JSON NoSQL
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】
这篇文章是关于Redis基本数据结构的学习笔记,包括了String、Hash、Set、List和SortedSet的介绍和常用命令。文章解释了每种数据结构的特点和使用场景,并通过命令示例演示了如何在Redis中操作这些数据结构。此外,还提供了一些练习示例,帮助读者更好地理解和应用这些数据结构。
redis基本数据结构(String,Hash,Set,List,SortedSet)【学习笔记】
|
2月前
|
Java 索引
java基础(13)String类
本文介绍了Java中String类的多种操作方法,包括字符串拼接、获取长度、去除空格、替换、截取、分割、比较和查找字符等。
35 0
java基础(13)String类