Redis-String篇

基础命令

  • set:设置值
  • get:读取值
  • setex:设置key-value值并设置过期时间
myRedis:0>set guohu guohu 
"OK"

myRedis:0>get guohu
"guohu"

myRedis:0>set guohu2 guohu2 ex 100
"OK"

myRedis:0>set test value  px 100000
"OK"
执行set命令后面可以跟着过期时间参数
例如:set key value ex 100 (原子性的命令,ex:秒,px:毫秒)
注意:setnx 命令的参数,第二个是time:setnex key time value
  • append:在原有的基础上追加值,并返回value长度
myRedis:0>append guohu test
"9"

myRedis:0>get guohu 
"guohutest"
  • incr:对整型数据进行自增1操作(内置1)
  • incrby:对整型数据进行自定义递增
  • decr:对整型数据递减1操作(内置1)
  • decrby:对整型数据进行自定义递减操作
myRedis:0>incr guohu
"ERR value is not an integer or out of range"

myRedis:0>incr limit
"1"

myRedis:0>incr limit
"2"

myRedis:0>incrby limit 3
"5"

myRedis:0>decr limit
"4"
非整形incr会失败
incr也可以进行浮点数叠加:incrbyfloat
  • setnx:设置值,只有在key不存在的时候才成功(返回1)
myRedis:0>setnx test test
"1"

myRedis:0>setnx test test2
"0"
  • mset:批量设置key-value
  • mget:批量获取key-value
myRedis:0>mset key1 value1 key2 value2 key3 value3
"OK"

myRedis:0>mget key1 key2 key2
 1)  "value1"
 2)  "value2"
 3)  "value2"
  • setrange:从指定位置开始替换
  • getrange:截取字符串,从下标为n开始截取到n或n+1
myRedis:0>set rangeKey "hello golang"
"OK"

myRedis:0>get rangeKey
"hello golang"

myRedis:0>SETRANGE rangeKeymyRedis:0> 6 "java"
"12"

myRedis:0>get rangeKey
"hello javang"
  • strlen:获取string长度
myRedis:0>strlen key4
"6"
  • del:删除数据
myRedis:0>del rangeKey
"1"

适用场景

  • 缓存
  • 分布式锁
  • incr 全局id,计数器
  • incr 网站限流
  • 数据库
  • 位操作

存储原理图

在这里插入图片描述

dictEntry, redisObject SDS的定义在前一篇文中种已经解释
参考:Redis总纲

string的三种编码

  • int:存储8字节的长整型数据(2^63 - 1)
  • embstr:44字节以内的字符串,只读属性修改后会升级为raw
  • raw:存储大于44字节以上的字符串

44字节的由来

前面一篇文章已经介绍过,redisObject的源码以及数据结构
在使用中,redis为提高内存使用率,redisObject和SDS分配连续的一块内存空间,限制为64字节
redisObject占了16字节,sds本身占了3个字节的空间,底层是字符数组末尾是\0占据了一个字节,整个空间存储还剩 44字节

所以在内存连续的前提下,最多能存储44个字节的字符串,将这种内存连续的存储结构定义为embstr,超出这个范围后,需要重新在申请一块内存区域,在内存不连续的情况下,redis使用了数据类型的升级,转换了存储方式,把redisObject和sds分开存储,方便动态扩容,定义这种格式的数据类型为raw,从内存连续的embstr升级为内存不连续的raw,目的是为了达到内存最大化的利用

备注:redis3.2版本之前,sds占了8个字节,所以3.2版本临界条件是39字节

44字节 = 64- 4(32bit) - 4 - 8 - 1 - 1 - 1 - 1
在这里插入图片描述

embstr和raw的区别

  • 内存分配次数: embstr分配一次(内存是连续的),raw分配两次(redisObject和sds空间)
  • 空间回收:embstr回收一次,raw需要释放两次空间
  • embstr需要增加长度时,需要重新分配内存升级为raw,embstr属性时只读(当对embstr做修改时,在redis里面embstr是只读属性,不管有没有达到44字节的临界条件,都会对embstr进行编码升级,转换成raw以后,再进行修改)

图解分析

  1. 如果存储字符串小于44字节,实际数据与redisObject内存分配是连续的
    在这里插入图片描述
  2. 如果字符串大于44,实际的数据和RedisObject在内存中地址不相邻
    在这里插入图片描述

string扩容

sds结构解析,参考前一篇文章:Redis总纲

在使用string类型时,追加字符串,当字符串超过剩余空间大小时会涉及到底层存储的扩容机制,当然实际使用场景并不是很多,下面简单介绍下扩容的原理

扩容方式:

  1. 追加字符串小于1M,按照新追加内容的2倍进行扩容
  2. 追加字符串大于等于1M,则按照实际大小外加1M进行扩容

注意: 追加过程中要考虑到新得到的内存大小会不会超出现有数据类型的空间限制,如果超出了则重新分配内存选择数据类型

图解如下:
在这里插入图片描述

源码如下:

#define SDS_MAX_PREALLOC (1024*1024)

sds sdsMakeRoomFor(sds s, size_t addlen) {
    void *sh, *newsh;
    size_t avail = sdsavail(s);
    size_t len, newlen;
    char type, oldtype = s[-1] & SDS_TYPE_MASK;
    int hdrlen;

    /* Return ASAP if there is enough space left. */
    if (avail >= addlen) return s;

    len = sdslen(s);
    sh = (char*)s-sdsHdrSize(oldtype);
    newlen = (len+addlen);
    if (newlen < SDS_MAX_PREALLOC)
        newlen *= 2;
    else
        newlen += SDS_MAX_PREALLOC;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值