这是我参与「第三届青训营 -后端场」笔记创作活动的第2篇笔记。Redis

84 阅读5分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第2篇笔记。 基本类型:

string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)

高级类型:

geospatial、hyperloglog、bitmap

String

简介:String是Redis最基础的数据结构类型,它是二进制安全的,可以存储图片或者序列化的对象,值最大存储为512M。

简单使用举例: set key value、get key

等应用场景:共享session、分布式锁,计数器、限流。

内部编码有3种,int(8字节长整型)/embstr(小于等于39字节字符串)/raw(大于39个字节字符串)

struct sdshdr{
    unsigned int len; // 标记buf的长度
    unsigned int free; //标记buf中未使用的元素个数
    char buf[]; // 存放元素的坑
}

空间预分配

空间预分配用于优化 SDS 的字符串增长操作:当 SDS 的 API 对一个 SDS 进行修改,并且需要对 SDS 进行空间扩展的时候,程序不仅会为 SDS 分配修改所必要的空间,还会为 SDS 分配额外的未使用空间。

  • 如果修改完 SDS 后,SDS 的长度(len)小于 1 MB,那么程序分配和 len 属性同样大小的未使用空间,这时(扩展后) SDS len 属性的值将与 free 的值相同 。比如修改后,SDS 的 len 改为了 13 字节,那么程序也会预分配 13 字节给 free 属性,SDS 的 buf 数组的实际长度将变成 13B+13B+1B('/0')=27 字节。
  • 如果修改完 SDS 后,SDS 的长度将大于 1 MB,那么程序会分配 1 MB 的未使用空间。比如修改后,SDS 的 len 改为 30 MB,那么程序会分配 1 MB 的未使用空间,SDS 的 buf 数组的实际长度将变成 30MB + 1MB + 1B。

通过这种空间预分配策略,Redis可以减少连续执行字符串涉及长度修改操作所需的内存重分配次数 。

惰性空间释放

惰性空间释放用于优化 SDS 的字符串缩短操作:当 SDS 的 API 需要缩短 SDS 保存的字符串时,程序并不立即使用内存重分配来回收缩短后多出来的字节,而是使用 free属性 将这些字节的数量记录起来,并等待将来使用。

二进制安全

C 字符串中的字符必须符合某种编码(比如 ASCII),并且除了字符串的结尾外,字符串里面不能包含空字符('/0'),否则最先被程序读入的空字符将被误认为是字符串结尾,这些限制使得 C 字符串只能保存文本数据,而不能保存像图片、音频、视频、压缩文件这样的二进制数据 。如上图,假如是 C 字符串的函数的话只会识别到 "Redis",而忽略之后的 "Cluster"。

虽然数据库一般用于保存文本数据,但使用数据库来保存二进制数据的场景也不少见,因此,为了确保 Redis 可以适用于各种不同的场景,SDS 的 API 是 二进制安全 的(binary-safe),所有 SDS API 都会以处理二进制的方式来处理 SDS 存放的 buf 数组里的数据,程序不会对其中的数据做任何限制、过滤或者假设, 数据在写入时是什么样的,它被读取时就是什么样的

总结

C字符串SDS
获取字符串长度的复杂度为O(N)获取字符串长度的复杂度为O(1)
API是不安全的,可能会造成缓冲区溢出API是安全的,不会造成缓冲区溢出
修改字符串长度N次必然需要执行N次内存重分配修改字符串长度N次最多需要执行N次内存重分配
只能保存文本数据可以保存文本或者二进制数据

Hash

简介:在Redis中,哈希类型是指v(值)本身又是一个键值对(k-v)结构

简单使用举例:hset key field value 、hget key field

内部编码:ziplist(压缩列表) 、hashtable(哈希表)

应用场景:缓存用户信息等。

List

简介:列表(list)类型是用来存储多个有序的字符串,一个列表最多可以存储2^32-1个元素。

简单实用举例:lpush key value [value ...] 、lrange key start end

内部编码:ziplist(压缩列表)、linkedlist(链表)

应用场景: 消息队列,文章列表

  • lpush+lpop=Stack(栈)
  • lpush+rpop=Queue(队列)
  • lpsh+ltrim=Capped Collection(有限集合)
  • lpush+brpop=Message Queue(消息队列)

Set

  • 简介:集合(set)类型也是用来保存多个的字符串元素,但是不允许重复元素
  • 简单使用举例:sadd key element [element ...]、smembers key
  • 内部编码:intset(整数集合)、hashtable(哈希表)
  • 注意点:smembers和lrange、hgetall都属于比较重的命令,如果元素过多存在阻塞Redis的可能性,可以使用sscan来完成。
  • 应用场景: 用户标签,生成随机数抽奖、社交需求。

Zset

  • 简介:已排序的字符串集合,同时元素不能重复
  • 简单格式举例:zadd key score member [score member ...],zrank key member
  • 底层内部编码:ziplist(压缩列表)、skiplist(跳跃表)
  • 应用场景:排行榜,社交需求(如用户点赞)。

高级数据类型

  • Geo:Redis3.2推出的,地理位置定位,用于存储地理位置信息,并对存储的信息进行操作。
  • HyperLogLog:用来做基数统计算法的数据结构,如统计网站的UV。
  • Bitmaps :用一个比特位来映射某个元素的状态,在Redis中,它的底层是基于字符串类型实现的,可以把bitmaps成作一个以比特位为单位的数组。\