前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis认知-String类型编码看二进制安全

Redis认知-String类型编码看二进制安全

原创
作者头像
Janesong0806
发布2024-07-07 17:29:38
1130
发布2024-07-07 17:29:38
举报
文章被收录于专栏:Redis

Redis 是一个K-V NOSQL,使用键值对存储数据,其中的值(对象)包括 5 种类型,即字符串、哈希、列表、集合、有序集合。

这 5 种类型是 Redis 对外提供的,实际上,在 Redis 内部,每种类型可能有 2 种或更多的内部编码实现。

本文着重介绍字符串编码。

二进制安全

Redis进程与外界交互时,客户端从socket里获取的是字节流。Redis-Server服务端存储二进制字节,即二进制安全。

二进制安全,换句话说只要未来的双方客户端有统一的编码、解码,数据就不会被破坏。

在计算机里ASCII码是字符集标准,其他是扩展字符集。它有个规律0xxxxxxx,第一个字节肯定是0,后面可以从全0到全1逐个变化,代表不同的东西。而GBK、UTF-8是一个编码,不是字符集。

示例:

终端控制台设置采用GBK编码

终端控制台设置采用GBK编码-效果展示
终端控制台设置采用GBK编码-效果展示

终端控制台设置采用UTF-8编码

终端控制台设置采用UTF-8编码-效果展示
终端控制台设置采用UTF-8编码-效果展示

补充:命令【strlen $key】会返回$key的长度

在GBK情况下,redis-server是不知道客户端外围什么编码。redis-client发送写请求时先变成字节数组,redis-server底层按字节预存。

从这点上看,redis-server服务端与客户端侧的编码无直接关系。这就是二进制安全。

字符串编码-Int和Raw

Redis中的String编码是指Redis中存储字符串时所使用的数据结构。Redis中的字符串最大长度为512MB。

String类型直接存储了字符串值,但 Redis 内部为了优化存储效率和访问速度,会根据存储的内容自动选择不同的编码方式。Redis 中 String 类型的编码主要有两种:int(或称为 embstr,嵌入式字符串)和 raw(或称为 sdshdr,动态字符串)。

  • int 编码(或 embstr)

适用条件:当存储的字符串是整数且长度小于 Redis 源码中定义的一个阈值(通常是 32 位或 64 位整数的大小限制,但具体会受 Redis 配置和版本的影响)时,Redis 会使用 int 编码来存储这个字符串。

存储结构:在这种编码下,Redis 直接使用整数的原始二进制形式来存储数据,不需要额外的内存来存储字符串的长度或其他元数据。这使得访问速度非常快,且内存占用非常低。

  • raw 编码(或 sdshdr)

适用条件:当存储的字符串不是整数,或者字符串的长度超过了 int 编码的阈值时,Redis 会使用 raw 编码。

存储结构:raw 编码使用 Redis 自定义的动态字符串(SDS, Simple Dynamic String)来存储数据。SDS 不仅存储了字符串的内容,还存储了字符串的长度、空闲空间等信息。这种设计使得 Redis 在进行字符串操作时(如追加、修改等)更加高效,并且能够自动管理内存,减少内存碎片的产生。

编码转换

Redis 在存储 String 类型的数据时,会根据数据的实际情况自动选择合适的编码方式。在数据更新过程中,如果数据的内容或大小发生了变化,Redis 也会自动调整编码方式,以确保存储效率和访问速度的最优化。

示例:

127.0.0.1:6379> set key 9

OK

127.0.0.1:6379> object encoding key // 查看key的编码

"int"

127.0.0.1:6379> append key 1 // 追加字符”1”

(integer) 2

127.0.0.1:6379> get key

"91"

127.0.0.1:6379> strlen key

(integer) 2

127.0.0.1:6379> object encoding key // 再次查看key的编码

"raw"

127.0.0.1:6379>

上述,写入key存储是用int编码,但经过append操作后,变更为raw。

有关字符串数值计算

先来看个例子:

janesong@192 ~ % redis-cli

127.0.0.1:6379> set key 9

OK

127.0.0.1:6379> append key 1

(integer) 2

127.0.0.1:6379> object encoding key

"raw"

127.0.0.1:6379> incr key // value+1作为新value存入key

(integer) 92

127.0.0.1:6379> get key

"92"

127.0.0.1:6379> object encoding key

"int"

127.0.0.1:6379>

从上述例子可以看出,编码格式为raw也可以参与计算,只要是数字型的。

redis-server其实是要把这个key的value字节在内存里面拿出来,先转换为数值,然后它会更新key上的encoding编码。这是为了方便调一次encoding,因为key可能开始是raw,也能是字符串。

当转换数字没有报错没有报异常,而且参与计算也成功了,encoding就更新为int类型,下次做incr、decr等就可以直接参与计算了。如果发现不是int类型,就可以避归报错的问题。这样做就是为了提速,直接触发计算,无排错过程

从这点上说,Redis自身的编码么有影响数据存储。

数值计算溢出

既然Redis的字符串是字节方式,那么在参与计算时,是否没有”计算溢出”一说。答案显然不是。

举个例子:

127.0.0.1:6379> set key 9999999999999999999

OK

127.0.0.1:6379> incr key

(error) ERR value is not an integer or out of range // 服务端溢出无法计算

127.0.0.1:6379> get key

"9999999999999999999"

127.0.0.1:6379>

补充:本处只是考虑redis-server在对数字类字符串溢出问题,实际上对于客户端也会有语言偏差方面的溢出考虑处理。比如:redis-server返回一个比较大的value[数字字符型],而jedis在用变量去接并转int,需要考虑溢出。

所以,我们在使用Redis时,对于计算数值溢出,不仅仅要考虑redis-server,还要考虑redis-client的处理。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 二进制安全
  • 字符串编码-Int和Raw
    • 编码转换
      • 有关字符串数值计算
        • 数值计算溢出
    相关产品与服务
    对象存储
    对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档