Redis高可用系列——Set类型底层详解

news/2024/10/21 11:42:40/

文章目录

  • 概述
  • intset
  • intset 和 hashtable 的转换
  • 为什么加入了listpack
    • hashtable 的空间开销高
    • hashtable 的碰撞概率高
    • intset 、listpack和hashtable的转换

概述

在讲解set结构之前,需要先说明一下set结构编码的更替,如下

  • Redis7.2之前,set使用的是intsethashtable
  • Redis7.2之后,set使用的是intsetlistpackhashtable

intset

intset是一种紧凑的数组结构,它只保存int类型的数据,它将所有的元素按照从小到大的顺序存储在一块连续的内存中。intset会根据传入的数据大小,encoding分为int16_tint32_tint64_t


下图为命令所显示的编码结构

127.0.0.1:6379> sadd set 123
(integer) 1
127.0.0.1:6379> object encoding set
"intset"
127.0.0.1:6379> sadd set abcd
(integer) 1
127.0.0.1:6379> object encoding set
"hashtable"

intset 和 hashtable 的转换

Redis7.2之前,当一个集合满足以下两个条件时,Redis 会选择使用intset编码:

  • 集合对象保存的所有元素都是整数值
  • 集合对象保存的元素数量小于等于512个(默认)

intset最大元素数量可在redis.conf配置

set-max-intset-entries 512

为什么加入了listpack

redis7.2之前,sds类型的数据会直接放入到编码结构式为hashtableset中。其中,sds其实就是redis中的string类型。

而在redis7.2之后,sds类型的数据,首先会使用listpack结构当 set达到一定的阈值时,才会自动转换为hashtable

添加listpack结构是为了提高内存利用率和操作效率,因为 hashtable 的空间开销和碰撞概率都比较高。

hashtable 的空间开销高

hashtable 的空间开销高是因为它需要预先分配一个固定大小的数组来存储键值对,而这个数组的大小通常要大于实际存储的元素个数,以保证较低的装载因子。装载因子是指 hashtable 中已经存储的元素个数和数组大小的比值,它反映了 hashtable 的空间利用率

  • 如果装载因子过高,那么 hashtable 的性能会下降,因为碰撞的概率会增加
  • 如果装载因子过低,那么 hashtable 的空间利用率会下降,因为数组中会有很多空闲的位置

因此,hashtable 需要在装载因子和空间利用率之间做一个平衡,通常装载因子的推荐值是 0.75

hashtable 的碰撞概率高

hashtable碰撞概率高是因为它使用了一个散列函数来将任意长度的键映射到一个有限范围内的整数,作为数组的索引

散列函数的设计很重要,它应该尽可能地保证不同的键能够均匀地分布在数组中,避免出现某些位置过于拥挤,而其他位置过于稀疏的情况。然而,由于散列函数的输出范围是有限的,而键的取值范围是无限的,所以不可能完全避免两个不同的键被散列到同一个位置上,这就产生了碰撞。碰撞会影响 hashtable 的性能,因为它需要额外的处理方式来解决冲突,比如开放寻址法或者链地址法

举例说明,假设有一个大小为8的hashtable,使用取模运算作为散列函数,即h(k) = k mod 8。现在有四个键:5,13,21,29,它们都被散列到索引1
在这里插入图片描述
这就是一个碰撞的例子,因为四个键都映射到了同一个索引。这种情况可能是由于以下原因造成的:

  • 散列函数的选择不合适,没有充分利用hashtable的空间。
  • 键的分布不均匀,有些区间的键出现的频率更高。
  • hashtable的大小太小,不能容纳所有的键。

为了解决碰撞,redis采用了链地址法。就是在每个索引处维护一个链表,存储所有散列到该索引的键。但是,如果链表过长,查找效率会降低。因此,一般建议保持hashtable的负载因子(即键的数量除以hashtable的大小)在一定范围内,比如0.5到0.75之间。如果负载因子过高或过低,可以通过扩容或缩容来调整hashtable的大小

intset 、listpack和hashtable的转换

intset 、listpack和hashtable这三者的转换时根据要添加的数据、当前set的编码和阈值决定的。

  • 如果要添加的数据是整型,且当前set的编码为intset,如果超过阈值由intset直接转为hashtable

    阈值条件为:
    set-max-intset-entriesintset最大元素个数,默认512

  • 如果要添加的数据是字符串,分为三种情况

    • 当前set的编码为intset:如果没有超过阈值,转换为listpack;否则,直接转换为hashtable
    • 当前set的编码为listpack:如果超过阈值,就转换为hashtable
    • 当前set的编码为hashtable:直接插入,编码不会进行转换

    阈值条件为:
    set-max-listpack-entries:最大元素个数,默认128
    set_max_listpack_value:最大元素大小,默认64
    以上两个条件需要同时满足才能进行编码转换


http://www.ppmy.cn/news/66097.html

相关文章

理解和使用Java中的枚举

枚举是一种特殊的数据类型,用于定义一组具名的常量。Java中的枚举类型可以包含多个枚举常量,每个常量都具有唯一的名称和值。本文将详细介绍Java中的枚举,包括为什么要使用枚举、枚举的好处、如何定义和使用枚举等。 为什么要使用枚举&#…

【计算机视觉 | ViT-G】谷歌大脑提出 ViT-G:缩放视觉 Transformer,高达 90.45% 准确率

文章目录 一、简介二、如何做到的?三、扩展数据四、「head」 的解耦权重衰减五、通过移除 [class] token 节省内存六、实验结果6.1 将计算、模型和数据一起扩展6.2 ViT-G/14 结果 论文地址为: https://arxiv.org/pdf/2106.04560.pdf一、简介 视觉 Trans…

Linux安装Kafka

本文介绍Linux安装Kafka。 1.Kafka简介 Kafka也是开源与Apache开源基金会的项目,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统。 在百度百科是这样介绍的: Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala…

全面理解哈希,哈希的底层原理是如何实现的,哈希题型的做题思路与题目清单(不断更新)

什么是哈希 哈希(Hash)是一种算法,它接受一个输入(或“消息”),并返回一个固定大小的字符串。这个输出字符串的大小通常以字节为单位,输出的内容看起来是随机的且整个过程是单向的。 哈希的一…

知识变现海哥:掌握这四个步骤,轻松实现知识变现

你是否有过这种感受,看了很多书,网上报课花了很多钱,课程屯了很多,可是依然很难变现,问题出在哪里呢? 海哥写这本《知识变现道法术器》将为你揭开答案。 海哥,国内知名知识变现创业教练&#x…

Ansys Lumerical | 单行载流子光电探测器仿真方法

综述 在本例中,我们将研究混合硅基光电探测器的各项性能。单行载流子(uni-traveling carrier,UTC)光电探测器(PD)由InP/InGaAs制成,其通过渐变耦合的方式与硅波导相连。在本次仿真中&#xff0c…

Linux诞生与分支

a) 什么是操作系统操作系统是计算机系统中必不可少的基础系统软件,它的作用是管理和控制计算机系统中的硬件和软件资源,合理地组织计算机系统的工作流程,以便有效地利用这些资源为使用者提供一个功能强大、使用方便的操作环境。它在计算机系…