Java中高级核心知识全面解析——Redis(简介、基本数据结构、跳跃表【简介、实现】

本文深入探讨了Redis中的核心数据结构,包括字符串、列表、字典、集合和有序列表,强调了它们的底层实现和操作。此外,详细介绍了跳跃表的概念、为何使用跳跃表以及其在Redis有序列表中的实现,阐述了跳跃表如何提供高效查找、插入和删除操作。文章还提及Redis的安装、性能测试和基本操作,如设置和获取键值对、过期时间设置以及字典的渐进式rehash策略。
摘要由CSDN通过智能技术生成
  • 多实用工具 - Redis 是一个多实用工具,可用于多种用例,如:缓存,消息队列(Redis 本地支持发布/订阅),应用程序中的任何短期数据,例如,web应用程序中的会话,网页命中计数等。

2)Redis 的安装

这一步比较简单,你可以在网上搜到许多满意的教程,这里就不再赘述。

给一个菜鸟教程的安装教程用作参考:https://www.runoob.com/redis/redis-install.html

3) 测试本地 Redis 性能

当你安装完成之后,你可以先执行 redis-server 让 Redis 启动起来,然后运行命令 redis- benchmark -n 100000 -q 来检测本地同时执行 10 万个请求时的性能:
QQ:2046136117免费获取资料
当然不同电脑之间由于各方面的原因会存在性能差距,这个测试您可以权当是一种「乐趣」就好。

2.Redis五种基本数据结构

Redis有 5 种基础数据结构,它们分别是:string(字符串)list(列表)hash(字典)set(集合)zset(有序集合)。这 5 种是 Redis 相关知识中最基础、最重要的部分,下面我们结合源码以及一些实践来给大家分别讲解一下。

注意:

每种数据结构都有自己底层的内部编码实现,而且是多种实现,这样Redis会在合适的场景选择合适的内部编码。
可以看到每种数据结构都有两种以上的内部编码实现,例如string数据结构就包含了raw、int和embstr三种内部编码。
同时,有些内部编码可以作为多种外部数据结构的内部实现,例如ziplist就是hash、list和zset共有的内部编码。

1)字符串 string

Redis 中的字符串是一种 动态字符串,这意味着使用者可以修改,它的底层实现有点类似于 Java 中的ArrayList,有一个字符数组,从源码的 sds.h/sdshdr 文件 中可以看到 Redis 底层对于字符串的定义SDS,即 Simple Dynamic String 结构:

/* Note: sdshdr5 is never used, we just access the flags byte directly.

  • However is here to document the layout of type 5 SDS strings. /
    struct attribute ((packed)) sdshdr5 {
    unsigned char flags; /
    3 lsb of type, and 5 msb of string length /
    char buf[];
    };
    struct attribute ((packed)) sdshdr8 {
    uint8_t len; /
    used /
    uint8_t alloc; /
    excluding the header and null terminator /
    unsigned char flags; /
    3 lsb of type, 5 unused bits /
    char buf[];
    };
    struct attribute ((packed)) sdshdr16 {
    uint16_t len; /
    used /
    uint16_t alloc; /
    excluding the header and null terminator /
    unsigned char flags; /
    3 lsb of type, 5 unused bits /
    char buf[];
    };
    struct attribute ((packed)) sdshdr32 {
    uint32_t len; /
    used /
    uint32_t alloc; /
    excluding the header and null terminator /
    unsigned char flags; /
    3 lsb of type, 5 unused bits /
    char buf[];
    };
    struct attribute ((packed)) sdshdr64 {
    uint64_t len; /
    used /
    uint64_t alloc; /
    excluding the header and null terminator /
    unsigned char flags; /
    3 lsb of type, 5 unused bits */
    char buf[];
    };

你会发现同样一组结构 Redis 使用泛型定义了好多次,为什么不直接使用 int 类型呢

因为当字符串比较短的时候,len 和 alloc 可以使用 byte 和 short 来表示,Redis 为了对内存做极致的优化,不同长度的字符串使用不同的结构体来表示

①、SDS 与 C 字符串的区别

为什么不考虑直接使用 C 语言的字符串呢?因为 C 语言这种简单的字符串表示方式 不符合 Redis 对字符串在安全性、效率以及功能方面的要求。我们知道,C 语言使用了一个长度为 N+1 的字符数组来表示长度为 N 的字符串,并且字符数组最后一个元素总是 '\0' 。(下图就展示了 C 语言中值为 “Redis” 的一 个字符数组)
QQ:2046136117免费获取资料
这样简单的数据结构可能会造成以下一些问题:

  • 获取字符串长度为 O(N) 级别的操作 → 因为 C 不保存数组的长度,每次都需要遍历一遍整个数组;
  • 不能很好的杜绝 缓冲区溢出/内存泄漏 的问题 → 跟上述问题原因一样,如果执行拼接 or 缩短字符串的操作,如果操作不当就很容易造成上述问题;
  • C 字符串 只能保存文本数据 → 因为 C 语言中的字符串必须符合某种编码(比如 ASCII),例如中间出现的 ‘\0’ 可能会被判定为提前结束的字符串而识别不了;

我们以追加字符串的操作举例,Redis 源码如下:

/* Append the specified binary-safe string pointed by ‘t’ of ‘len’ bytes to the

  • end of the specified sds string ‘s’.
  • After the call, the passed sds string is no longer valid and all the
  • references must be substituted with the new pointer returned by the call. */
    sds sdscatlen(sds s, const void *t, size_t len) {
    // 获取原字符串的长度
    size_t curlen = sdslen(s);

// 按需调整空间,如果容量不够容纳追加的内容,就会重新分配字节数组并复制原字符串的内容到新数组中
s = sdsMakeRoomFor(s,len);
if (s == NULL) return NULL; // 内存不足
memcpy(s+curlen, t, len); // 追加目标字符串到字节数组中
sdssetlen(s, curlen+len); // 设置追加后的长度
s[curlen+len] = ‘\0’; //

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值