【Redis】Redis的五种数据结构

压缩列表中的节点数量大于 server.hash_max_ziplist_entries (默认值为 512 )

列表



REDIS_LIST (列表)是 LPUSH 、 LRANGE 等命令的操作对象, 它使用 REDIS_ENCODING_ZIPLIST 和 REDIS_ENCODING_LINKEDLIST 这两种方式编码:

[外链图片转存失败(img-gytpHpeq-1567048898172)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-9d1b937227cf948b8a9bfb3137570475e5407d2c.svg)]

创建新列表时 Redis 默认使用 REDIS_ENCODING_ZIPLIST 编码, 当以下任意一个条件被满足时, 列表会被转换成 REDIS_ENCODING_LINKEDLIST 编码:

  • 试图往列表新添加一个字符串值,且这个字符串的长度超过 server.list_max_ziplist_value (默认值为 64 )。

  • ziplist 包含的节点超过 server.list_max_ziplist_entries (默认值为 512 )。

列表的阻塞原语BLPOP 、 BRPOP 和 BRPOPLPUSH

阻塞原语并不是一定会造成客户端阻塞:

  • 只有当这些命令被用于空列表时, 它们才会阻塞客户端。

  • 如果被处理的列表不为空的话, 它们就执行无阻塞版本的 LPOP 、 RPOP 或 RPOPLPUSH 命令。

[外链图片转存失败(img-Nfnb66pX-1567048898175)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-657d8e78e1f1357fdff05173a259334670b87f85.svg)]

阻塞

当一个阻塞原语的处理目标为空键时, 执行该阻塞原语的客户端就会被阻塞。

阻塞一个客户端需要执行以下步骤:

  1. 将客户端的状态设为“正在阻塞”,并记录阻塞这个客户端的各个键,以及阻塞的最长时限(timeout)等数据。

  2. 将客户端的信息记录到 server.db[i]->blocking_keys 中(其中 i 为客户端所使用的数据库号码)。

  3. 继续维持客户端和服务器之间的网络连接,但不再向客户端传送任何信息,造成客户端阻塞。

[外链图片转存失败(img-7Srz5418-1567048898186)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-72233dd6a912518ff6874fdad4e20356091a6063.svg)]

当客户端被阻塞之后,脱离阻塞状态有以下三种方法:

  • 被动脱离:有其他客户端为造成阻塞的键推入了新元素。

  • 主动脱离:到达执行阻塞原语时设定的最大阻塞时间。

  • 强制脱离:客户端强制终止和服务器的连接,或者服务器停机。

脱离阻塞状态

通过将新元素推入造成客户端阻塞的某个键中, 可以让相应的客户端从阻塞状态中脱离出来 (取消阻塞的客户端数量取决于推入元素的数量)。

LPUSH 、 RPUSH 和 LINSERT 这三个添加新元素到列表的命令, 在底层都由一个 pushGenericCommand 的函数实现, 这个函数的运作流程如下图:

[外链图片转存失败(img-TbnHSUQy-1567048898188)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-be4975476661a3e683475377d30b659d70bee64c.svg)]

当向一个空键推入新元素时, pushGenericCommand 函数执行以下两件事:

  • 检查这个键是否存在于前面提到的 server.db[i]->blocking_keys 字典里, 如果是的话,

那么说明有至少一个客户端因为这个 key 而被阻塞,程序会为这个键创建一个 redis.h/readyList 结构, 并将它添加到

server.ready_keys 链表中。

  • 将给定的值添加到列表键中。

列表

集合



REDIS_SET (集合)是 SADD 、 SRANDMEMBER 等命令的操作对象, 它使用 REDIS_ENCODING_INTSET 和 REDIS_ENCODING_HT 两种方式编码:

[外链图片转存失败(img-5ykAMOkm-1567048898193)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-2f54a5b62b3507f0e6d579358e426c78b0dfbd5c.svg)]

第一个添加到集合的元素, 决定了创建集合时所使用的编码:

  • 如果第一个元素可以表示为 long long 类型值(也即是,它是一个整数), 那么集合的初始编码为

REDIS_ENCODING_INTSET 。

  • 否则,集合的初始编码为 REDIS_ENCODING_HT 。

集合编码的切换

如果一个集合使用 REDIS_ENCODING_INTSET 编码, 那么当以下任何一个条件被满足时, 这个集合会被转换成 REDIS_ENCODING_HT 编码:

  • intset 保存的整数值个数超过 server.set_max_intset_entries (默认值为 512 )。

  • 试图往集合里添加一个新元素,并且这个元素不能被表示为 long long 类型(也即是,它不是一个整数)。

集合类型为什么选择intset结构作为其中之一的底层实现方式?

intset底层实现方式是数组,这个数组以有序、无重复的方式保存集合元素,并且根据新添加的整数元素类型来进行自动升级,例如从int16_t升级到int32_t; 它具有灵活性+节省内存的优点;

在集合类型只有整数元素并且元素不是很大的时候选择intset是比较好的一个选择;

字典编码的集合

当使用 REDIS_ENCODING_HT 编码时, 集合将元素保存到字典的键里面, 而字典的值则统一设为 NULL 。

作为例子, 以下图片展示了一个以 REDIS_ENCODING_HT 编码表示的集合, 集合的成员为 elem1 、 elem2 和 elem3 :

[外链图片转存失败(img-gVLWNUdF-1567048898198)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-3b62c50ed475dc6c91adbb8079f0e0104f644931.svg)]

有序集



REDIS_ZSET (有序集)是 ZADD 、 ZCOUNT 等命令的操作对象, 它使用 REDIS_ENCODING_ZIPLIST 和 REDIS_ENCODING_SKIPLIST 两种方式编码:

[外链图片转存失败(img-Ua7tWSuy-1567048898206)(https://redisbook.readthedocs.io/en/latest/_images/graphviz-4d10098056ec25ed0e239f64bbcac524bce31bc8.svg)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值