Redis源码-String:Redis String命令、Redis String存储原理、Redis String三种编码类型、Redis字符串SDS源码解析、Redis String应用场景

  • Redis数据类型
  • 1.String存储原理
  • 2.Redis-String数据类型:操作命令
    • 新增修改key
    • 依据给定key和下标的开始结束值输出值value
    • 获得key的value长度
    • 拼接key值
    • key不存在,才能成功,分布式锁
    • 为key设置过期时间
    • 新增修改多个key的值
    • 获取多个key的值
    • 对于数字类型(整型、浮点型)的增减、递增减操作
    • 查看Redis内部的数据结构类型
  • 3.存储原理(底层编码)
    • Redis String存储底层编码
      • Redis String三种底层编码类型:int、embstr、raw
      • 编码转换问题:int和embstr什么时候转化为raw?
      • 编码转换问题:会还原吗?
      • embstr和raw的区别
        • embstr优点
        • embstr的缺点
    • sds.h源码文件:Redis自己实现了它的字符串结构
      • SDS是什么:简单动态字符串
      • sds.h文件的sdshdr8的源码截取
      • Redis为什么要用SDS来实现字符串?
  • 4.应用场景
    • String怎么存储表格式的数据?
    • Hash 哈希
    • String与Hash的区别
  • Redis各数据结构命令、源码分析、应用场景

Redis数据类型

Redis数据类型不等同与数据结构,数据结构是Redis该数据类型存储结构的存储原理,也是该数据类型的底层编码。

1.String存储原理

2.Redis-String数据类型:操作命令

新增修改key

# set key value:新增修改key值
127.0.0.1:6379> set mykey 1234567
OK# get key:获得key值
127.0.0.1:6379> get mykey
"1234"

依据给定key和下标的开始结束值输出值value

# getrange key start end:依据给定key和下标的开始结束值输出值value
# 下标从0开始,如果下标end>String个数,会输出到末尾截至
127.0.0.1:6379> getrange mykey 0 3
"1234"
127.0.0.1:6379> getrange mykey 3 10
"4567"

获得key的value长度

# strlen key:获得key的value长度
127.0.0.1:6379> strlen mykey
(integer) 7

拼接key值

# append mykey abc:拼接key值,返回拼接后的长度
127.0.0.1:6379> append mykey abc
(integer) 10

key不存在,才能成功,分布式锁

# setnx key value:key不存在,才能成功,返回0或1
# 利用该特性:可以用来实现一些竞争性的操作
# 这个命令是redis实现分布式锁的关键
127.0.0.1:6379> setnx mykey 222
(integer) 0
127.0.0.1:6379> get mykey
"1234567abc"
127.0.0.1:6379> setnx mykey2 333
(integer) 1

为key设置过期时间

# expire key seconds:为key设置过期时间,单位秒,返回0或1
# 存在失败的可能性,不建议这样操作,建议在新建key的同时赋予过期时间
127.0.0.1:6379> expire existkey 3
(integer) 0
127.0.0.1:6379> expire mykey 3
(integer) 1
127.0.0.1:6379># set key value [EX seconds] [PX milliseconds] [NX|XX]
# EX秒,PX毫秒,以及更精确的时间,指定时间的类型需要为integer,成功返回ok
127.0.0.1:6379> set mykey 222 EX 60
OK

新增修改多个key的值

# mset key value [key value ...]:新增修改多个key的值,成功返回ok
127.0.0.1:6379> mset mykey1 111 mykey2 222 mykey3 333
OK

获取多个key的值

# mget key [key ...]:获取多个key的值
127.0.0.1:6379> mget mykey1 mykey0 mykey3
1) "111"
2) (nil)
3) "333"

对于数字类型(整型、浮点型)的增减、递增减操作

# 对于数字类型(整型、浮点型)的增减、递增减操作:返回的是操作后的值
127.0.0.1:6379> set mykey 22
OK
127.0.0.1:6379> incr mykey
(integer) 23
# incrby key increment:增加指定整型值
127.0.0.1:6379> incrby mykey 100
(integer) 123
127.0.0.1:6379> decr mykey
(integer) 122
127.0.0.1:6379> decrby mykey 100
(integer) 22
# incrbyfloat key increment:增加指定浮点型值
127.0.0.1:6379> incrbyfloat mykey 0.5
"22.5"

查看Redis内部的数据结构类型

当你插入Redis一个字符串数据时,会根据你插入的值,Redis再进行内部的数据转换。
可以先看本文目录:3.存储原理(底层编码)

可以用object encoding key名查看key的value再Redis的内部数据类型。

127.0.0.1:6379> set key1 11
OK
127.0.0.1:6379> set key2 dhasjkkshljashfklsahkjfjkashaskhdlsahjlvnajhjsdaldhasjkhdjashjkdhask
OK
127.0.0.1:6379> set key3 abc
OK
# 查看key在Redis的对外数据类型
127.0.0.1:6379> type key1
string
127.0.0.1:6379> type key2
string
127.0.0.1:6379> type key3
string
# 查看key在Redis的对内数据类型
127.0.0.1:6379> object encoding key1
"int"
127.0.0.1:6379> object encoding key2
"raw"
127.0.0.1:6379> object encoding key3
"embstr"

可以看到Redis对外类型都为String(type命令查看),但是对内的不一样。

3.存储原理(底层编码)

Redis源码:Redis源码怎么查看入门、Redis外部数据结构到Redis内部数据结构查看源码顺序、Redis源码查看顺序

Redis String存储底层编码

Redis String三种底层编码类型:int、embstr、raw

Redis字符串存储类型的内部编码有三种:

  1. int,存储8个字节的长整型(long,2^63-1)
  2. embstr,embstr格式的SDS,存储小于44个字节的字符串,之前存的一长串字母,一个字母就是一个字节
  3. raw,raw格式的SDS,存储大于44个字节的字符串
    不同编码方式1个英文字母占的字节是不同的,具体如下:

不同编码方式1个英文字母占的字节是不同的,具体如下
1,ASCII码:一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。
2,UTF-8编码:一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。中文标点占三个字节,英文标点占一个字节。
3,Unicode编码:一个英文等于两个字节,一个中文(含繁体)等于两个字节。中文标点占两个字节,英文标点占两个字节。

编码转换问题:int和embstr什么时候转化为raw?

  1. int数据不再是整数→raw
  2. int大小超过了long的范围(2^63-1)→embstr
  3. embstr长度超过了44个字节→raw

编码转换问题:会还原吗?

编码转换在Redis写入数据时完成,且转换过程不可逆,只能从小内存编码向大内存编码转换(不包括重新set),重新set虽然在值上是修改或插入,但在Redis看来是重新赋值,这里的编码转换指的修改比如说拼接字符串、自增这种,非set的改值操作。

embstr和raw的区别

embstr:只分配一次内存空间:RedisObject和SDS连续
raw:需要分配两次内存空间

embstr优点

它将 RedisObject 对象头和 SDS 对象连续存在一起,使用 malloc 方法一次分配,它的计算会更快。
embstr的最小占用空间为19(16+3),而64-19-1(结尾的\0)=44,所以empstr只能容纳44字节。

当字节数小于44时,分配的大小一直都是64个字节。

一旦超过44个字节,整体的大小超过64个字节,
在Redis中将认为是一个大的字符串,不再使用 emdstr 形式存储,存储结构将变为raw。

embstr的缺点

  1. 如果你的value的长度增加的话,那么RedisObject对象头和SDS对象需要重新分配内存空间,所以Redis设计的embstr是只读的
  2. 由于embstr是只读的,它的内容是不能修改的,因此一旦修改会使embstr编码直接变成raw编码,即使字节数小于44时
127.0.0.1:6379> set key a
OK
127.0.0.1:6379> object encoding key
"embstr"
127.0.0.1:6379> append key 2
(integer) 2
# 可以看到,append后长度为2,字节数小于44,修改会使embstr编码直接变成raw编码
127.0.0.1:6379> object encoding key
"raw"

sds.h源码文件:Redis自己实现了它的字符串结构

sds.h源码文件在解压后的src目录下

SDS是什么:简单动态字符串

SDS(Simple Dynamic String):简单动态字符串,Redis会根据String类型的value长度,去选择合适的sdshdr数结构来存储这个value,这样的设计可以节省内存空间。

# 换算:
2^10=1024byte=1kb
2^20=1MB
2^30=1GB
2^40=1TB
2^50=1PB
2^60=1EB

sdshdr5:2^5=32byte(不用)
sdshdr8:2^8=256byte
sdshdr16:2^16=65536byte=64kb
sdshdr32:2^32=4GB
sdshdr64:2^64=16EB

Redis的key是字符类型,即String,最大可以用得到是512M,那么它的value字符类型,也是String,最大也是512M。
sdshdr32,sdshdr64定义的这么大,但你未必能用得到全部,这也是Redis预留的一种思想,给你足够多的空间,未来可能就用的到这么大了。

sds.h文件的sdshdr8的源码截取

struct __attribute__ ((__packed__)) sdshdr8 {uint8_t len; /* used *//* 当前字符数组的长度,有这个值使得获取字符长度的复杂度变为O(1),不用向C语言的字符数组那样从头至尾遍历O(N) */uint8_t alloc; /* excluding the header and null terminator *//* 当前字符数组总共分配的内存大小 */unsigned char flags; /* 3 lsb of type, 5 unused bits *//* 当前字符数组的属性、用来标识到底是sdshdr8还是sdshdr16等 */char buf[];             /* 字符串真正的值,它是用字符数组来进行存储的 */
};

Redis为什么要用SDS来实现字符串?

C语言里面也是没有字符串的,它有的是字符数组,有以下特点:

  1. 内存空间预先分配
  2. 获取字符长度(即字符数组的长度)需要从头到尾先遍历一遍,时间复杂度O(n)
  3. C语言的字符数组内存分配是固定的,长度变更引起内存重新分配
  4. 用’\0’判断字符串结束(如果你存的内容恰好包含,也会认为是结束)

所以Redis基于字符数组实现了自己的字符串SDS:简单动态字符串

C字符数组 SDS
获取字符长度的复杂度O(N) 获取字符长度的复杂度O(1),因为SDS中uint8_t len存储当前字符数组的长度
API是不安全的,可能会造成称缓冲区溢出 API是安全的,不会造成称缓冲区溢出,简单动态字符串可以扩容,而且不需要预先分配,因此不会产生内存溢出
修改字符长度N次必然需要执行N次内存重新分配 修改字符长度N次最多需要执行N次内存重新分配,SDS里面有一个特殊的设计,叫做空间的预分配和惰性的空间释放,不管是获取内存还是释放内存都不是及时的,所以性能会提升
只能保存文本数据 可以保存文本数据或者二进制数据
可以使用所有<string.h>库中的函数 可以使用部分<string.h>库中的函数

4.应用场景

  1. 缓存: 查询、计算过的数据直接放入Redis里面,然后应用直接从Redis中拿数据,而不是再次去数据库查值,既可以提升应用的查询速度,又可以起到保护数据库的作用
  2. 分布式Session: 在spring和spring boot里面,其实是有一个包,叫spring session,引入之后,会直接将session写入到Redis中,为什么可以实现这个功能呢,因为它是一个基于分布式环境的服务,也就是大家都连接到它,就能够实现数据的共享(Session共享)
  3. 分布式锁 set NX EX: 如果存在就不成功,以此来实现竞争,同时提供了这个的过期时间,来保证会定时释放锁
  4. 分布式全局ID incr: 这个其实有很多方法:比如数据库、UUID、雪花算法,而Redis之所以也可以,是因为它的String类型可以存储整型,并且提供了incr、incrby这种增长的设计
  5. 计数器 incr: 网页访问数、微博点赞数这种实时性不是很高的,可以先存在Redis中,之后在同步给数据库
  6. 限流 incr: 对于某一个用户、IP在一段时间限制操作次数
  7. 位操作: 是因为Redis里面它的字符是以8位二进制来存储的

String怎么存储表格式的数据?

使用Redis存储一张表的数据,比如下表student:

id name age
12 aaa 25
13 bbb 36

你使用String数据结构也可以实现:
key特殊处理一下(key前缀+“自定义分隔符”+“表的唯一键约束”+“自定义分隔符”+属性名),然后获取值使用mget来批量获取属性

# 自定义分隔符_:key名(student_12_id:key前缀+"自定义分隔符"+"表的唯一键约束"+"自定义分隔符"+属性名)
127.0.0.1:6379> mset student_12_id 12 student_12_name aaa student_12_age 25
OK
127.0.0.1:6379> mget student_12_id student_12_name student_12_age
1) "12"
2) "aaa"
3) "25"

那么如果这样做很好,还要Hash干嘛?
String这样做,key已经占了很大的存储空间(真实场景你拼接的这个key很长),还有value,有点得不偿失,于是Redis提供了存储表格式的数据类型Hash。

String每个key是单独存储,利用这个特性,因此可以更方便的拆分,所以如果一个key的数据量很大,可以考虑用String来接

Hash 哈希

存储多个无序的键值对,最大存储数量2^32-1(40亿个左右)

Redis本身就是KV存储的,这个存储方式是Redis外层的Hash,那么Hash数据结构存储KV结构的数据,这个叫做Redis内层的Hash。

内层的Hash中的value是不能够再次嵌套其它的数据类型(比如list、set、hash等),它的value只能是String。

String与Hash的区别

Hash特点:

  1. 节省内存空间: 因为只存一个key
  2. 减少key冲突: 因为只存一个key
  3. 取值减少性能消耗: 一次性就可以取出所有属性,不需要用mget命令,或者get向Redis服务端多次交互进行取值

Hash不适合的场景:

  1. Field不能单独设置过期时间: String可以单独设置过期时间
  2. 需要考虑数据量分布的问题: 内容是不能拆分的,大数据量的key会使Redis多个节点的内存分布不均衡。比如一个key有10亿个Field,但是一个key只能存储在Redis的一个服务节点上,你想拆成两个5亿的,Hash做不到;而String每个key是单独存储,因此可以更方便的拆分,所以如果一个key的数据量很大,可以考虑用String来接

Redis各数据结构命令、源码分析、应用场景

Redis源码-String:Redis String命令、Redis String存储原理、Redis String三种编码类型、Redis字符串SDS源码解析、Redis String应用场景

Redis源码-Hash:Redis String与Hash的区别、Redis Hash存储原理、Redis Hash命令、 Redis Hash存储底层编码、Redis Hash应用场景

Redis源码-List:Redis List存储原理、Redis List命令、 Redis List存储底层编码quicklist、Redis List应用场景

Redis源码-Set:Redis Set存储原理、Redis Set集合操作命令、Redis Set两种存储底层编码intset+hashtable、Redis Set应用场景

Redis源码-ZSet:Redis ZSet存储原理、Redis ZSet命令、 Redis ZSet两种存储底层编码ziplist/dict+skiplist、Redis ZSet应用场景

Redis源码-String:Redis String命令、Redis String存储原理、Redis String三种编码类型、Redis字符串SDS源码解析、Redis String应用场景相关推荐

  1. 跟着狂神学Redis(NoSql+环境配置+五大数据类型+三种特殊类型+Hyperloglog+Bitmap+事务+Jedis+SpringBoot整合+Redis持久化+...)

    跟着狂神学Redis 狂神聊Redis 学习方式:不是为了面试和工作学习!仅仅是为了兴趣!兴趣才是最好的老师! 基本的理论先学习,然后将知识融汇贯通! 狂神的Redis课程安排: nosql 讲解 阿 ...

  2. verilog中状态机的三种编码方式的比较(二进制码、独热码、格雷码)

    最近做了一个小项目,是关于状态机中三种编码方式的比较,总结了一下三种编码方式的不同,可以会在以后IC笔试面试过程中用到,简单记录一下三种编码方式的优缺点. 三种编码方式如下图所示:其中独热码只有一位为 ...

  3. redis三种架构:主从Cluster哨兵+整合Springboot访问redis

    文章目录 概要:redis集群方案 主从架构 部署主从示例: Redis主从工作原理 Sentinel(哨兵)模式 哨兵的Jedis连接代码: springboot访问哨兵结点 Cluster模式 R ...

  4. 十四、Redis三种特殊类型之一Geospatial

    一.概述 redis除了提供了五大基本数据类型String.List.Set.Hash.Zset,还有3个比较特殊的数据类型,Geospatial.Hyperloglog.Bitmap,这三个数据类型 ...

  5. 读取Java文件到byte数组的三种方式及Java文件操作大全(包括文件加密,String加密)

    读取Java文件到byte数组的三种方式 package zs;import java.io.BufferedInputStream; import java.io.ByteArrayOutputSt ...

  6. 实现二维码-完整三种编码流程加代码解析(javascript)

    效果 输入内容:XXXwedewed生日//&sss乐❤XXXwedewed生日//&sss乐❤ 完整的演示效果为,输入内容后会将解码绘制的每一步都展示(有点长就不全截图了,可以直接移 ...

  7. c#字符型转化为asc_C#中使用强制类型实现字符串和ASCII码之间的转换

    C#貌似没有专门用于ASCII码转字符或字符转ASCII码的系统函数,所以小编这里就借用一下强制类型转换来实现ASCII码与字符之间的互转. 所谓的ASCII码,即American Standard ...

  8. 三种方式生成小程序二维码

    通过后台接口可以获取小程序任意页面的二维码,扫描该二维码可以直接进入小程序对应的页面,所有生成的二维码永久有效,可放心使用.目前微信支持两种二维码,小程序码(左),小程序二维码(右),如下所示: 为满 ...

  9. 十六、Redis三种特殊类型之三Bitmap

    一.BitMap是什么 通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身,value对应0或1,我们知道8个bit可以组成一个Byte,所以bitmap本身会极大的节省储存 ...

最新文章

  1. 谷歌发布 RLDS,在强化学习生成、共享和使用数据集
  2. Java程序员春招三面蚂蚁金服,1200页文档笔记
  3. Android Studio新建类头部注释和添加函数注释模板及快捷键
  4. springboot MVC视图解析流程源码分析
  5. python 列表拼接_【Python杂货铺】速学python基础
  6. boost::hana::maximum用法的测试程序
  7. 配置mysql为主主复制步骤
  8. tensorrt轻松部署高性能dnn推理_实战教程:TensorRT中递归神经网络的介绍(中文字幕)...
  9. redisb并发访问慢出现的问题
  10. JAVA总裁--Java数组基础知识
  11. YzmCMSV3.1 | 代码审计
  12. spring boot 尚桂谷学习笔记07 嵌入式容器 ---Web
  13. 【分享】浅析Quora的技术架构
  14. Excel的设置 .net
  15. java案例代码1-生成随机验证码
  16. 微信公共号给客户发送消息提醒/模板消息(如业务到期提醒 ,订单提醒,帐户变动提醒)
  17. 面向对象程序设计语言和面向过程程序设计
  18. Mac用户必备翻译软件!Bob 0.5.3 中文版 附谷歌翻译插件!
  19. 阿里云ECS-Centos7.9集群部署Redis服务遭木马攻击
  20. 用Windows自带工具给U盘4k对齐

热门文章

  1. gitlab cicd配置
  2. 机器人门禁控制盒怎么接线方法_门禁电锁如何接线
  3. wu-database-lazy-starter(懒人数据库操作-核心增量式更新)
  4. 软件测试——单元测试/集成测试/系统测试/验收测试
  5. 限制EditText为单行
  6. fastunit中使用MapList一个注意例子
  7. 开源项目之Android繁体中文输入法
  8. matlab 文件输出到text文件总结
  9. vmware虚拟机实现两台电脑远程桌面连接
  10. HTML中表格怎么制作