Redis的String探索之路

String是redis最基本的类型,键值对(Key : Value 形式),Redis 的 String 可以包含任何数据,最大能存储 512 MB。(一个键最大能存储 512MB

Redis 的字符串是动态字符串,是可以修改的字符串哦  ^_^,采用预分配冗余空间的方式来减少内存的频繁分配。党字符串长度小于 1M 时,扩容都是加倍当前的空间,当超过 1M 在扩容时只会多扩 1M的空间大小。

注意:

  • 字符串在长度小于 1M 之前,扩容空间采用加倍策略,也就是保留 100% 的冗余空间。
  • 当长度超过 1M 之后,为了避免加倍后的冗余空间过大而导致浪费,每次扩容只会多分配 1M 大小的冗余空间。

Redis的String探索之路_第1张图片

 String 内部分配结构

String 内部为当前字符串实际分配的空间 capacity 一般要高于实际字符串长度 len。

set key value [EX seconds|PX milliseconds] [NX|XX] [KEEPTTL]
  • EX seconds: 设置键的过期时间为多少秒。
  • set key value Ex seconds  <=> setex key seconds value
set name xiaomo ex 2  = setex name 2 xiaomo

Redis的String探索之路_第2张图片 

  • PX milliseconds: 设置键的过期时间为 多少毫秒。
  • set key value ex  milliseconds  <=>   psetex key millseconds value
  • NX :在键不存在时, 才对键进行设置操作。
  • set key vlaue ex <=>  setnx key value
  • XX :在键已经存在时, 才对键进行设置操作。

返回值:set命令在设置操作成功完成时才返回 OK 。

               如果设置参数 nx ,当值不存在时返回 OK,存在返回 nil 。

 

Redis 的字符串叫「SDS」— Simple Dynamic String,它的结构是一个带长度信息的字节数组。

struct SDS {
   T capacity;      // 数组容量
   T len;           // 数组长度
   byte flags;      // 特殊标识位,不理睬它
   byte[] content;  // 数组内容
}

 

Redis 的字符串有两种存储方式,embstr 和 raw。

在长度特别短时,使用 emb 形式存储 (embeded),当长度超过 44 字节时,使用 raw 形式存储。

在Redis 对象头结构体,所有的 Redis 对象都有下面的这个结构头:

struct RedisObject {
    int4 type;      // 4bits
    int4 encoding;  // 4bits
    int24 lru;      // 24bits
    int32 refcount; // 4bytes
    void *ptr;      // 8bytes,64-bit system
} robj;

 4b + 4b + 24b + 4B + 8B = 16B

每个对象都有个引用计数,当引用计数为零时,对象就会被销毁,内存被回收。一个 RedisObject 对象头需要占据 16 字节的存储空间。

SDS 内部结构如下:

struct SDS {
    int8 capacity;  // 1byte
    int8 len;       // 1byte
    int8 flags;     // 1byte
    byte[] content; // 内联数组,长度为 capacity(默认开辟的空间)
}

在 SDS 结构体的大小,在字符串比较小时,SDS 对象头的大小是content+3,至少是 3。意味着分配一个字符串的最小空间占用为 19 字节 (内容为空)。

Redis的String探索之路_第3张图片

SDS 结构体中的 content 中的字符串是以字节\0结尾的字符串,之所以多出这样一个字节,是为了便于直接使用 glibc 的字符串处理函数,以及为了便于字符串的调试打印输出。

  • 当内存分配器分配了 64 空间时,那这个字符串的长度(内容)最大可以是多少呢?

64 - 19 - 1 = 44(字节)

127.0.0.1:6379> set content aaaabbbbccccddddeeeeffffgggghhhhiiiijjjjkkkk
OK
127.0.0.1:6379> debug object content
Value at:0x7f4f4f0c3a40 refcount:1 encoding:embstr serializedlength:45 lru:15180126 lru_seconds_idle:13
127.0.0.1:6379> append content l
(integer) 45
127.0.0.1:6379> debug object content
Value at:0x7f4f4f0adc20 refcount:1 encoding:raw serializedlength:46 lru:15180178 lru_seconds_idle:19

 

(1)可以用来计数

如果 value 值是一个整数,还可以对它进行自增(自减)操作。

1.商品数量变化

2.博客论坛帖子点赞数目

3.文章帖子收藏用户数

4.文章帖子转发数

5.用户留言数目

  ····

基本跟数量变化的都可以使用上呀 ~

但是要注意的一点是:自增是有范围的,它的范围是 signed long long 的最大和最小值,超过了这个值,Redis 会报错。

long long (__int64) 
范围:-922 3372 0368 5477 5808 ~ 922 3372 0368 5477 5807 (922*10^16)
127.0.0.1:6379> set age 9223372036854775807
OK
127.0.0.1:6379> get age
"9223372036854775807"
127.0.0.1:6379> incr age
(error) ERR increment or decrement would overflow
127.0.0.1:6379> set age -9223372036854775808
OK
127.0.0.1:6379> get age
"-9223372036854775808"
127.0.0.1:6379> incrby age -1
(error) ERR increment or decrement would overflow

 

(2)可以用来限流

比如在某些火爆新品上架的时候,商家上架的货都是有一定的数量的。同时,会设置在一段时间内销售商品。这个时候需要用 Redis 来做一些限流操作,限制一个操作可以被执行的速率,让每个商品的最大请求访问限制在一定范围内(设置键的生存时间)。

 

 3)二进制 — 位图使用(bitmap)

1. 统计 :任意用户在任意时间窗口登录天数(setbit、bitcount)

2.送礼品:在活跃期间段的用户,送礼品盒等。

3.进行数据分析:将数据导入内存,进行统计报表分析。

 

你可能感兴趣的:(Redis的String探索之路)