【Redis碎片知识】5种基本数据类型编码

字符串对象 string

  • int(long)

    如果一个字符串对象保存的是整数值,并且这个整数值可以用 long 类型表示,那么字符串对象的编码就会设置为 int。

  • embstr(简单动态字符串,SDS)

    如果字符串对象保存的是一个字符串值,并且这个字符串的长度 小于 39 (基于Redis 3.0,我在CentOS 8 上直接yum安装的Redis是5.0.6,发现这个阈值是45),那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串值。编码将被设置为 embstr。

  • raw(简单动态字符串,SDS)

    如果字符串对象保存的是一个字符串值,并且这个字符串的长度 大于等于 39 ,那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串值。编码将被设置为 raw。

Redis 没有直接使用C语言传统的字符串表示,而是自己构建了一种名为简单字符串(simple dynamic string,SDS)的抽象类型。

embstr 编码是专门用于保存短字符串的一种优化编码方式,相较于 raw 带来的好处有:

  • embstr 编码将创建字符串对象所需要的内存分配次数从 raw 编码的两次降低为一次。
  • 释放 embstr 编码的字符串对象只需要调用一次内存释放函数,而释放 raw 编码的字符串对象需要调用两次内存释放函数。
  • 因为 embstr 编码的字符串对象的所有数据都保存在一块连续的内存里,所以这种编码的字符串对象比起 raw 编码的字符串对象能够更加好的利用缓存带来的优势。

使用场景

1、缓存功能

Redis 作为缓存层,MySQL作为存储层,绝大多部分请求数据都是从Redis中获取。由于 Redis 具有支撑高并发的特性,所以缓存通常能起到加速读写和降低后端压力的作用。

2、计数

许多应用都会使用 Redis 作为计数的基础工具,它可以实现快速计数、查询缓存的功能,同时数据可以异步落地到其他数据源。具体的有点赞数,视频播放量等。

3、共享Session

一个分布式Web服务将用户Session消息(如登入信息)保存在各自服务器中,这样会照成一个问题,出于负载均衡的考虑,分布式服务会将用户的访问均衡到不同服务器上,用户刷新一次可能会发现需要重新登入,这是用户无法忍受的。为了解决这个问题,可以使用Redis将用户的Session集中管理。

4、限速

比如手机验证码登入,为了短信接口不被频繁访问,会限制用户在获取验证码几分钟之内不能再获取验证码。还有一些网站限制一个IP地址不能在一秒内访问超过n次。

列表对象 list

  • ziplist(压缩列表)

    当列表的元素个数小于 list-max-ziplist-entries 配置(默认 512 个),同时列表每个元素的值都小于 list-max-ziplist-value 配置时(默认 64 字节),Redis会选用ziplist来作为列表的内部实现来减少内存的使用。

  • linkedList(双端链表)

    当列表类型无法满足 ziplist 的条件时,Redis会使用 linkedlist 作为列表的内部实现。

在Redis 3.2之后,list 内部编码就都用 quicklist 了,这种编码是上面两个的结合,书上用的是Redis 3.0,所以以后有时间再看吧。

使用场景

1、消息队列

Redis的lpush+brpop命令组合即可实现阻塞队列,生产者客户端使用lrpush从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞式的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性。

2、文章列表

每个用户有属于自己的文章列表,现需要分页展示文章列表。此时可以考虑使用列表,因为列表不但是有序的,同时支持按照索引范围获取元素。

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

哈希对象 hash

  • ziplist(压缩列表)

    当哈希类型元素个数小于 hash-max-ziplist-entries 配置(默认 512 个),同时所有值都小于 hash-max-ziplist-value 的配置(默认 64 字节)时,Redis 会使用 ziplist 作为哈希的内部实现,ziplist使用更加紧凑的结构实现多个元素的连续存储,所以在节省内存方面比 hashtable 更加优秀。

  • hashtable(字典)

    当哈希类型无法满足 ziplist 的条件时,Redis 会使用 hashtable 作为哈希的内部实现,因为此时ziplist的读写效率会下降,而 hashtable的读写时间复杂度为O(1)

使用场景

可以存储用户的信息,例如key为 user:1 value为id:1 name:tom。

集合对象 set

  • intset(整数集合)

    当集合中的元素都是整数且元素个数小于 set-max-intset-entries 配置(默认 512 个),Redis 会选用 intset 来作为集合的内部实现,从而减少内存的使用。

  • hashtable(字典)

    当集合类型无法满足 intset 的条件时,Redis 会使用 hashtable 作为集合的内部实现。

使用场景

集合类型比较典型的使用场景是标签(tag)。例如一个用户可能对娱乐、体育比较感兴趣,另一个用户可能对历史、新闻比较感兴趣,这些兴趣点就是标签。有了这些数据就可以得到喜欢同一个标签的人,以及用户的共同喜好的标签,这些数据对于用户体验以及增强用户黏度比较重要。例如一个电子商务的网站会对不同标签的用户做不同类型的推荐,比如对数码产品比较感兴趣的人,在各个页面或者通过邮件的形式给他们推荐最新的数码产品,通常会为网站带来更多的利益。

有序集合对象 zset

  • ziplist(压缩列表)

    当有序集合的元素个数小于 zset-max-ziplist-entries 配置(默认 128 个),同时每个元素的值都小于 zset-max-ziplist-value 配置(默认 64 字节)时,Redis会用 ziplist 来作为有序集合的内部实现,ziplist 可以有效减少内存的使用。

  • skiplist(跳跃表)

    当 ziplist 条件不满足时,有序集合会使用 skiplist 作为内部实现,因为此时 ziplist 的读写效率会下降。

使用场景

有序集合比较典型的使用场景就是排行榜系统。例如视频网站需要对用户上传的视频做排行榜,榜单的维度可能是多个方面的:按照时间、按照播放数量、按照获得的赞数。


  • 基于 Redis 3.0
  • 《Redis 设计与实现》
  • 《Redis 开发与运维》

有时间再把《Redis 设计与实现》中介绍的底层数据结构再看下。