阿里P8大神讲解的跳跃表确定不了解下?

【Redis】拼多多面试官问我zset底层是如何实现的,我反手就把跳表的数据结构画了出来 拿下zset集合的底层实现 阅读详情

前言

hello,大家好,周五见了。前面几周我们一起看了Redis底层数据结构,如动态字符串SDS,双向链表Adlist,字典Dict,如果有对Redis常见的类型或底层数据结构不明白的请看上面传送门。

今天我们来看下ZSET的底层架构,如果不知道ZSET是什么的,可以看上面传送门第一篇。简单来说,ZSET是Redis提供的根据数据和分数来判断其排名的数据结构。最常见的就是微信运动的排名,每个用户对应自己的步数,每天晚上可以给出用户的排名。

有小伙伴可能会想,如果是实现排名的话,各种排序方法都可以实现的,没必要引入Redis的ZSET结构啊?

当然,如果是采用排序方法的话,是可以实现相同功能的,但是代码里面需要硬编码,会添加工作量,还会提供代码的Bug哦,哈哈哈。而且Redis的底层是C实现的,直接操作内存,速度也会比Java方法实现提升。

综上,使用Redis的ZSET结构,好处多多。那话不多说,开始吧。在正式开始之前,我们需要引入下跳跃表的概念,其是ZSET结构的底层实现。以下可能有点枯燥,我尽量说得简单点哈。

什么是跳跃表?

对于数据量大的链表结构,插入和删除比较快,但是查询速度却很慢。那是因为无法直接获取某个节点,需要从头节点开始,借助某个节点的next指针来获取下一节点。即使数据是有序排放的,想要查询某个数据,只能从头到尾遍历变量,查询效率会很低,时间复杂度为O(n)。

如果我们需要快速查询链表有啥办法呢?有同学说用数组存放,但是如果不改数据结构呢?

我们可以先想想在有序数组结构中有二分法,每次将范围都缩小一半,这样查询速度提升了很多,那么在链表中能不能也使用这种思想。

这就到了今天讲的主角——跳跃表。(一点也生硬地引出概念)

步骤一 新建有序单项链表

先看下图有序单向链表,存放了1,2,3,4,5,6,7这7个元素。

 

步骤二 抽取二级索引节点

我们可以在链表中抽取部分节点,下图抽取了1,3,5,7四个节点,也就是每两个节点提取了一个节点到上级,抽取出来的叫做索引。

注意不是每次都能抽取到这么完美,这其实就跟抛硬币一样,每个硬币的正反两面的概率是一样的,都是1/2。当数据量小的时候,正反的概率可能差别较大。但是随着数据量的加大,正反的概率越来越接近于1/2。类比过来是一个意思,每个节点的机会都是一样的,要么停留原级,要么提取到上级,概率都是1/2。但是随着节点数量的增加,抽取的节点越来越接近与1/2。

 

步骤三 抽取三级索引节点

我们可以在链表中抽取部分节点,下图抽取了1,5两个节点,也就是每两个节点提取了一个节点到上级,抽取出来的叫做索引。

 

步骤四 类二分法查询

我们假设要查找值为6的节点,先从三级索引开始,找到值为1的节点,发现比5小,根据值为1节点的next指针,找到值为5的节点,5后面没有其他的三级索引啦。

于是顺着往下找,到了二级索引,根据值为5的节点的next指针找到值为7的节点,发现比6小,说明要找到的节点6在此范围内。

再接着到了一级索引位置,根据值为5的节点next指针指向值为6的节点,发现是想要查询的数据,所以查询过程结束。

根据上面的查询过程(下图的蓝色连线),我们发现其采用的核心思想是二分法,不断缩小查询范围,如果在上层索引找到区间,则顺延深入到下一层找到真正的数据。

 

总结

从上面的整个过程中可以看出,数据量小的时候,这种拿空间换时间,消耗内存方法的并不是最优解。所以Redis的zset结构在数据量小的时候采用压缩表,数据量大的时候采用跳跃表。

像这种链表加多级索引的结构,就是跳跃表。这名字起的形象,过程是跳跃着来查询的。

Redis中跳跃表图解

下图简单来说是对跳跃表的改进和再封装,首先引入了表头的概念,这与双向链表,字典结构一样,都是对数据的封装,因为他们都是采用的指针,而指针必然导致在计算长度,获取最后节点的数据问题上会产生查询太慢的性能问题,所以封装表头是为了在这些问题上提升速度,浪费的只是添加,删除等操作的时间,与此对比,是可以忽略的。

其次是引入管理所有节点的层数数组,我们可以看到有32层,即32个数组,这和后面的数据节点结构是一样的。引入它是为了便于直接根据此数组的层数定位到每个元素。

再其次是数据节点的每个level都有层级和span(也就是下图箭头指针上的数字,其是为了方便统计两个节点相距多少长度)。

最后就是数据节点的后退指针backward,引入目的是Level数组只有前指针,即只能指向下一个节点地址,而后退指针是为了能往回找节点。

 

上图主要分为3大块:(这边大致看下就行,下面将对各模块进行代码详细解释)

表头

主要包括四个属性,分别是头指针header,尾指针tail,节点长度length,所有节点的最大level。

header:指向跳跃表的表头节点,通过这个指针地址可以直接找到表头,时间复杂度为O(1)。

tail:指向跳跃表的表尾节点,通过这个指针可以直接找到表尾,时间复杂度为O(1)。

length:记录跳跃表的长度,即不包含表头节点,整个跳跃表中有多少个元素。

level:记录当前跳跃表内,所有节点层数最大的level(排除表头节点)。

管理所有节点层数level的数组

其对象值为空,level数组为32层,目的是为了管理真正的数据节点。关于具体的level有哪些属性放在数据节点来说。

数据节点

主要包括四个属性对象值obj,分数score,后退指针backward和level数组。每个数据的Level数组有多少层,是随机产生的,这跟上面说过的跳跃表是一样的。

成员对象obj:真正的实际数据,每个节点的数据都是唯一的,但是节点的分数可能相同。两个相同分数的节点是按照成员对象在字典中的大小进行排序的,成员对象较小的节点会排在前面,成员对象较大的节点会排在后面。

分数score:各个节点中的数字是节点所保存的分数,在跳跃表中,节点按各自所保存的分数从小到大排列。

后退指针backward:用于从表尾向表头遍历,每个节点只有一个后退指针,即每次只能后退一步。

层级level:节点中用1,2,3等字样标记节点的各个层,L1代表第一层,L2代表第二层,L3代表第三层,并以此类推。

跳跃表的定义

表头结构zskiplist

 

typedef struct zskiplist {
    //表头的头指针header和尾指针tail
    struct zskiplistNode *header, *tail;
    //一共有多少个节点length
    unsigned long length;
    // 所有节点最大的层级level
   int level;
} zskiplist;

具体数据节点zskiplistNode

 

//跳表的具体节点 
typedef struct zskiplistNode {
    sds ele; //具体的数据,对应张三
    double score;//分数,对应70
    struct zskiplistNode *backward;//后退指针backward
     //层级数组    struct zskiplistLevel {
        struct zskiplistNode *forward;//前进指针forward
        unsigned int span;//跨度span
    } level[];
} zskiplistNode; 

 

 

跳跃表的实现(源码分析)

redis关于跳跃表的API都定义在t_zset.c文件中。

千万不要看到源码分析就跑开了,一定要看哦。

创建跳跃表

创建空的跳跃表,其实就是创建表头和管理所有的节点的level数组。首先,定义一些变量,尝试分配内存空间。其次是初始化表头的level和length,分别赋值1和0。接着创建管理所有节点的Level的数组,是调用zslCreateNode函数,输入参数为数组大小宏常量ZSKIPLIST_MAXLEVEL(32),分数为0,对象值为NULL。(此为跳跃表得以实现重点)。再接着就是为此数组每个元素的前指针forword和跨度span初始化。最后初始化尾指针并返回值。

可以参照下面的图解和源码:

 

//创建一个空表头的跳跃表
zskiplist *zslCreate(void) {
    int j;
    zskiplist *zsl;
    //尝试分配内存空间
    zsl = zmalloc(sizeof(*zsl));
    //初始化level和length
    zsl->level = 1;
    zsl->length = 0;
    //调用下面的方法zslCreateNode,传入的参数有数组长度ZSKIPLIST_MAXLEVEL 32
    //分数0,对象值NuLL
    //这一步就是创建管理所有节点的数组
    //并且设置表头的头头指针为此对象的地址
    zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL);
    //为这32个数组赋值前指针forward和跨度span
    for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
        zsl->header->level[j].forward = NULL;
        zsl->header->level[j].span = 0;
    }
    //设置尾指针
    zsl->header->backward = NULL;
    zsl->tail = NULL;
    //返回对象
    return zsl;
}
zskiplistNode *zslCreateNode(int level, double score, sds ele) {
    zskiplistNode *zn =
        zmalloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel));
    zn->score = score;
    zn->ele = ele;
    return zn;
}

 

插入节点

比如有下图6个元素,需要插入值为赵六,分数为101的元素,我们大致想一想,大致的步骤包括找到要插入的位置,新建一个数据节点,然后调整与之相关的头尾指针的level数组。那就看看redis咋做的,和我们想的一样不一样呢?

噔噔噔噔,答案揭晓。当然了大框架是相同的。

正文开始了:(先来图片)

 

1.遍历管理所有节点的level数组,从最大的level开始,即3,挨个对比值,如果有分数比他大的值或者分数相同,但是数据的值比他大,记录到数组里面,同时记录跨度。

这样说太抽象了。拿上图举个例子,从表头的level即3开始,首先到张三的L3,发现分数70,比目标分数101小跳过,根据其前指针找到赵六的L3,发现分数102,比目标分数101大,将赵六L3记录在待更新数组update中,同时记录跨度span为4。接着到下一层,张三的L2层,发现分数70比目标分数101小跳过,根据前指针找到王五的L2,发现分数90,比目标分数101小跳过,根据前指针找到赵六的L2,发现分数102比目标分数101大,将赵六的L2记录到待更新数组update中,同时记录跨度span为2。最后到下一层,张三的L1层,逻辑和刚才一样的,也是记录赵六的L1层和跨度span为1。

2.为新节点随机生成层级数level(通过位运算),如果生成的level大于目前level最大值3,则将将大于部分挨个遍历,并将跨度等信息记录到上面update表中。

比如,新节点生成的level为5,目前level最大值为3,说明这个节点只会有一个,并且跨越了之前的所有节点,那么我们将从第四层和第五层都遍历下,记录到待更新数组update中。

3.准备工作都做好了,找到了该节点将插入到哪一位置,处于哪一层,每层对应的跨度是多少,下面就要新增数据节点了。把上两步的信息都添加到新节点上,并且调整位置前后指针即可。

4.最后就是一些收尾工作,比如修改表头的层级level,节点大小length和尾指针tail等属性。

综上,整个流程就已经结束了。可能看着有点复杂,可以对照下面代码来。

//插入节点,输入参数为
//zsl:表头
//score:插入元素的分数score
//ele:插入元素的具体数据ele
zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele) {
    //使用update数组记录每层待插入元素的前一个元素
    zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
    //记录前置节点与第一个节点之间的跨度,即元素在列表中的排名-1
    unsigned int rank[ZSKIPLIST_MAXLEVEL];
    int i, level;

    serverAssert(!isnan(score));
    x = zsl->header;
    //从最大的level开始遍历,从顶到底,找到每一层待插入的位置
    for (i = zsl->level-1; i >= 0; i--) {
        /* store rank that is crossed to reach the insert position */
        rank[i] = i == (zsl->level-1) ? 0 : rank[i+1];
    //直接找到第一个分数比该元素大的位置
    //或者分数与该元素相同但是对象的ASSICC码比该元素大的位置
        while (x->level[i].forward &&
                (x->level[i].forward->score < score ||
                    (x->level[i].forward->score == score &&
                    sdscmp(x->level[i].forward->ele,ele) < 0)))
        {
            //将已走过元素的跨越元素进行计数,得到元素在列表中排名,或者是已搜寻的路径长度
            rank[i] += x->level[i].span;
            x = x->level[i].forward;
        }
    //记录待插入位置
        update[i] = x;
    }
     //随机产生一个层数,在1到32之间,层数越高,生成的概率越低
    level = zslRandomLevel();
    //如果产生的层数大于现有的最高层数,则超出层数都需要初始化
    if (level > zsl->level) {
        //开始循环
        for (i = zsl->level; i < level; i++) {
            rank[i] = 0;
            //该元素作为这些层的第一个节点,前节点就是header
            update[i] = zsl->header;
            //初始化后这些层每层有两个元素,走一步就是跨越所有元素
            update[i]->level[i].span = zsl->length;
        }
        zsl->level = level;
    }
    //创建节点
    x = zslCreateNode(level,score,ele);
    for (i = 0; i < level; i++) {
        //将新节点插入到各层链表中
        x->level[i].forward = update[i]->level[i].forward;
        update[i]->level[i].forward = x;

        // rank[0]是第0层的前置节点P1(也就是底层插入节点前面那个节点)与第一个节点的跨度
        // rank[i]是第i层的前置节点P2(这一层里在插入节点前面那个节点)与第一个节点的跨度
        // 插入节点X与后置节点Y的跨度f(X,Y)可由以下公式计算
        // 关键在于f(P1,0)-f(P2,0)+1等于新节点与P2的跨度,这是因为跨度呈扇形形向下延伸到最底层
        // 记录节点各层跨越元素情况span, 由层与层之间的跨越元素总和rank相减而得
        x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]);
               // 插入位置前一个节点的span在原基础上加1即可(新节点在rank[0]的后一个位置)

 update[i]->level[i].span = (rank[0] - rank[i]) + 1;
    }

    /* increment span for untouched levels */
    for (i = level; i < zsl->level; i++) {
        update[i]->level[i].span++;
    }
    // 第0层是双向链表, 便于redis常支持逆序类查找
    x->backward = (update[0] == zsl->header) ? NULL : update[0];
    if (x->level[0].forward)
        x->level[0].forward->backward = x;
    else
        zsl->tail = x;
    zsl->length++;
    return x;
}

 

int zslRandomLevel(void) {
    int level = 1;
    while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
        level += 1;
    return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}

获取节点排名

担心大家忘了这张图,再粘贴一遍。如下图,这部分逻辑比较简单,就不写了,具体参考代码分析。

 

//得到节点的排名
//输入参数为表头结构zsl,分数score,真正的数据ele
unsigned long zslGetRank(zskiplist *zsl, double score, sds ele) {
    zskiplistNode *x;
    unsigned long rank = 0;
    int i;
    //先获取表头的头指针,即找到管理所有节点的level数组
    x = zsl->header;
     //从表头的level,即最大值开始循环遍历
    for (i = zsl->level-1; i >= 0; i--) {
        //如果找到分数小于目标分数的,排名加上其跨度
        //或者分数相同,但是具体数据小于目标数据的,排名也加上跨度
        while (x->level[i].forward &&
            (x->level[i].forward->score < score ||
                (x->level[i].forward->score == score &&
                sdscmp(x->level[i].forward->ele,ele) <= 0))) {
            rank += x->level[i].span;
            x = x->level[i].forward;
        }

        //确保在第i层找到分值相同,且对象相同时才会返回排位值
        if (x->ele && sdscmp(x->ele,ele) == 0) {
            return rank;
        }
    }
    return 0;
}

 

结语

该篇主要讲了Redis的ZSET数据类型的底层实现跳跃表,先从跳跃表是什么,引出跳跃表的概念和数据结构,剖析了其主要组成部分,进而通过多幅过程图解释了Redis是如何设计跳跃表的,最后结合源码对跳跃表进行描述,如创建过程,添加节点过程,获取某个节点排名过程,中间穿插例子和过程图。

深入学习 Redis - 深挖经典数据类型之 zset Zset 是一个有序且唯一的集合,在 zset 中的 member 同时引入了一个属性 score(分数),支持浮点类型,也就是说每一个 member 都安排一个分数,并且默认按照分数进行升序排序. 阅读详情

相关推荐

在 Eclipse 里快速用上 SAP Joule:ABAP 开发者的 AI 助手上手指南

本文介绍了SAP Joule for developers如何集成在ABAP开发工具中,为开发者提供AI辅助能力。主要内容包括: Joule作为ADT的增强层,直接嵌入开发流程,支持在项目资源管理器、代码编辑器等场景下通过上下文菜单调用AI功能。 核心使用方式:打开Joule视图后,可在开发对象、代码片段等上下文中使用自然语言交互,请求解释、生成测试或获取示例代码。 重点功能: Explain:解释现有代码逻辑,降低理解成本 ABAP Unit测试生成:快速创建与上下文相关的测试用例 支持在传输管理器等完整

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 398

Redis 数据类型 - zset (有序集合)

Redis 数据类型 - zset (有序集合) 有序集合每个元素都是一个字符串对象,每个元素都有一个分值为 double 类型的浮点数,底层数据结构是 ziplist 和 skiplist(跳跃表)+ dict 字典。 *dict:保存一个从成员到分数的映射,通过该字典可以用O(1)的复杂度查找给定成员的分值。 *zsl: 按照分值从小到大保存了所有集合元素,每个跳跃表节点都保存了一个元素。可以通过它对 zset 进行范围型操作,例如 ZRANK、ZRANGE。 同时使用字典和跳跃表并不会产生重复成员和

LarrYFinal的博客 1992

R数据分析:潜在剖面分析LPA的做法与解释

Latent Profile Analysis (LPA) tries to identify clusters of individuals (i.e., latent profiles) based on responses to a series of continuous variables (i.e., indicators). LPA assumes that there are unobserved latent profiles that generate patterns of resp.

Codewar的博客 1万+

[Redis][Zset]详细讲解

[Redis][Zset]详细讲解

SnowK博客 7195

2、硬件工程师笔试面试汇总(2025版本)

本文摘要:文章系统梳理了硬件工程师笔试面试中的电子元器件知识要点,涵盖电阻、电容、电感、二极管、三极管、MOS管等器件的工作原理、选型要点和应用场景。详细解析了UART、I2C、SPI等通信协议的特点及实现方式,并探讨了电源管理、信号处理、PCB设计等核心问题。针对常见电路如放大电路、滤波电路、逻辑电路等提供了深入分析,同时介绍了示波器使用、单片机系统设计等实用技能。文章还包含器件封装、电平转换、时序分析等工程实践内容,并附有相关真题解析和仿真实验指导,为硬件工程师提供全面的技术参考。

XU157303764的博客 9012

注册GitHub时出现Unable to verify your captcha response.Please visit https://docs.github.com/解决方案(持续更新)

本文主要介绍了注册GitHub时出现Unable to verify your captcha response. Please visit https://docs.github.com/articles/troubleshooting-connectivity-problems/#troubleshooting-the-captcha for troubleshooting information.解决方案,希望能对学习使用GitHub的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 8万+

Redis数据结构:Zset类型全面解析

Redis,作为一种高性能的键值对数据库,因其丰富的数据类型和高效的性能而受到了广泛的关注和使用。在 Redis 的五种主要数据类型中,Zset(有序集合)类型可能是最复杂,但也是最强大的一种。Zset 不仅可以存储键值对,还可以为每个元素分配一个分数,然后根据这个分数进行排序。这使得 Zset 非常适合用于实现排行榜、时间线等功能。

栗筝i的博客 1万+

基于 Arduino 的鱼缸水质检测控制系统设计

本系统通过多传感器实时采集鱼缸水质参数(pH 值、温度、溶解氧、浊度),经 Arduino 主控芯片处理后,驱动执行模块自动调节水质,并通过显示模块实时展示数据。系统具备阈值报警、自动换水、温度调节、增氧等功能,适用于家庭或小型水族箱的水质智能管理。本设计提供了低成本、易扩展的鱼缸水质管理方案,适用于家庭水族箱或小型水产养殖场景,可根据实际需求调整传感器类型和控制逻辑。注:本设计如有疑问需要解惑可直接私信本人,看我个人简介。

weixin_42300449的博客 1087

入职阿里不到一个月(新零售方向)对于社招java达到什么样的水平才能社招面进阿里?

作者:你丫才码农 刚刚入职阿里不到一个月(新零售方向),所以还是比较清楚之前都准备了啥,部门也在招聘,所以问了下那些招聘的同事主要看什么点。对于社招,我之前做的准备有以下几个方面: 1.基本功:阿里主要是java方向的,那对jdk要比较熟练的理解和使用,重点内容有:集合,多线程,io,异常,反射,注解,序列化,反序列化等知识。其次就是网络和数据结构,网络至少要知道三次握手,四次分手,https,get,post等。数据结构有时候会问下红黑树,平衡二叉树吧。如果了解redis的,还可以聊下跳跃表,前缀树吧

jinggege795的博客 261

第4篇:使用 NModbus 库快速搭建 Modbus TCP 通信(从零开始用 C# 开发 Modbus 上位机)

本文介绍了如何使用 NModbus 库快速搭建 Modbus TCP 上位机通信程序。通过安装 NModbus4 NuGet 包,开发者可以轻松实现 Modbus TCP 连接,无需手动处理底层协议细节。文章详细演示了核心功能实现: 创建 TCP 客户端连接设备 读取保持寄存器(功能码0x03) 写入单个寄存器(功能码0x06) 关闭连接释放资源 提供完整C#示例代码,包含初始化连接、数据读写等关键操作,帮助开发者快速构建Modbus TCP通信应用。相比手动实现,NModbus库大幅简化了开发流程,特别适

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1047

汽车ECU诊断刷写和OTA升级中的验签和校验

汽车ECU诊断刷写和OTA升级中的验签和校验

天赐好车的博客 619

菜鸟教程linux教程,kafka面试题整理

一般像这样的大企业都有好几轮面试,所以自己一定要花点时间去收集整理一下公司的背景,公司的企业文化,俗话说「知己知彼百战不殆」,不要盲目的去面试,还有很多人关心怎么去跟HR谈薪资。这边给大家一个建议,如果你的理想薪资是30K,你完全可以跟HR谈33~35K,而不是一下子就把自己的底牌暴露了出来,不过肯定不能说的这么直接,比如原来你的公司是25K,你可以跟HR讲原来的薪资是多少,你们这边能给到我的是多少?你说我这边希望可以有一个20%涨薪。

a1901149的博客 1091

Clawdbot安装教程:从零开始到接入飞书

这几天,Clawdbot把整个科技圈都刷屏了。就是这个胖逼小龙虾🦞。不过现在改名叫Moltbot了。原因很简单:被Anthropic告了。Anthropic觉得Clawdbot这名字太像Claude Code的延伸产品,要求改名。真的,Anthropic你这家伙…更离谱的是,因为Clawdbot太火,Mac Mini都被抢断货了。无数人为了用它,疯狂买Mac Mini。我刚打开美团外卖,发现居然没货了???

Maynor的博客 2179

【Redis】深入探索 Redis 的数据类型 —— 有序集合 ZSet

ZSet(有序集合)是 Redis 数据库中的一种数据类型,它是一种无序的集合,每个元素都与一个浮点数分数相关联,使得集合中的元素可以根据分数进行排序。ZSet 也常被称为 Sorted Set。特点和用途:元素唯一性:ZSet 中的元素是唯一的,不允许重复元素存在。有序性:与普通集合不同,ZSet 中的元素是有序排列的,根据元素的分数从小到大排序。分数与元素关联:每个元素都与一个分数相关联,分数用于确定元素的位置。高效的成员查找:Redis 提供了高效的成员查找操作,可以根据成员名字快速查找分数。

qq_61635026的博客 6047

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

redis学习-17- Redis zset有序集合操作

redis学习-17- Redis zset有序集合操作

时光 1366

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Redis使用规范

1.拒绝bigkey value不应超过1MB。其中string类型的值应控制在10KB以内,hash,list,set,zset元素个数不应超过5000个且单个元素应非常小。 2.控制key的生命周期 key应设置过期时间。最好可以设置不同的过期时间,防止集中过期引起的缓存雪崩。 缓存雪崩:大量key在同一时间段失效,大量请求直接到达存储层。 (补充: 缓存穿透:访问一个不存在...

干货满满~ 1878

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Redis的Zset集合命令介绍及使用

Redis的Zset常用命令总结:1.zadd key value(v1 k1 v2 k2 v3 k3) :向Zset集合中添加数据。 2. zrange :查看value值。zrange key start end withscores :查看value值及键值。ZRANGEBYSCORE set1 70 80 withscores :获取某个范围内的数据。ZRANGEBYSCORE set1 ...

笨笨熊咦 2万+

redis有序集合zset详解

zset 概述 Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。 不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分是可以重复的 。 因为元素是有序的, 所以你也可以很快的根据评分(score)或者次序来获取一个范围的元素。 访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。 此外,有序集合中的元素是按顺序获取的(因此它们

it浅阳的博客 9233

Redis数据类型之ZSet类型

Redis有序集合跟集合一样也是String类型元素的集合,且不允许重复的成员不同的是每个元素都会关联一个double类型的分数,Redis正是通过这个分数来为集合中的元素进行从小到大的排序有序集合的成员是唯一的,但是分数(score)是可以重复的集合是通过哈希表实现的,集合中最大的成员数为2的32次方-1,可以存储40多亿个成员,Zset集合是有序不可重复的。

qq_39093474的博客 325

Redis中的ZSet

ZSet(有序集合)是 Redis 数据库提供的一种数据结构,它是一种有序的字符串集合,每个成员都关联着一个浮点数类型的分值(score),用于进行成员之间的排序。ZSet 的特点是能够保持成员的插入顺序和根据分值范围或成员获取数据,同时还支持快速的插入、删除和更新操作。总之,ZSet 是 Redis 提供的一种有序集合数据结构,通过成员和分值的关联,实现了排序、范围查询和快速的插入、删除和更新操作。成员排序:ZSet 内部按照成员的分值进行排序,并且成员之间的排序是唯一的。排名是基于分值从小到大排序的。

cpy1356140308的博客 645

【Redis】zset 类型

zset 类型

2203_76003626的博客 3299

redis zset结构详解

type:类型4bit得具体类型,String,list,set,hash,zset等;为啥用4bit?因为4bit可以有16中类型,目前redis还暂未支持这莫多类型。encoding:底层存储结构,4bit;比如hash结构,压缩表结构;LRU_BITS:24位得LRU时间ptr:指针 8byte 64位 指向具体得数据;特殊说明:只有string类型得embstr中ptr指针为空,其他得均有值refCount:引用次数,4byte 32位。

syath1314的博客 279

redis中的zset

zset,即有序集合,是Redis中的一种数据结构。它类似于set,但是每个元素都会关联一个分数,这个分数用于对元素进行排序。下面将对zset的详细使用方法进行解析。

weixin_45596982的博客 4911

Redis02:常用的五大数据类型和配置文件介绍

常用的五大数据类型 redis常见数据类型操作命令http://www.redis.cn/commands.html Redis键(key) keys *查看当前库所有key (匹配:keys *1) exists key判断某个key是否存在 type key 查看你的key是什么类型 del key 删除指定的key数据 unlink key 根据value选择非阻塞删除 仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作。就好比它先告诉你这个数据删除了,但其实它还没删

weixin_51418572的博客 392

Redis-Zset篇

目录基础命令存储编码ziplistskiplist源码分析存储结构解析level生成规则查找图解编码转换规则基础篇结束语 基础命令 存储编码 ziplist skiplist 源码分析 存储结构解析 level生成规则 查找图解 编码转换规则 基础篇结束语 ...

guohuGH的博客 5912
上一篇: 对内 DDD 对外 API 之—对外 API 的设计理念
下一篇: 手把手教你如何通过Java给图片添加文字和图片水印
java_lujj
博客等级 码龄4年 18粉丝 152原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值