Redis-数据结构与对象

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: <div class="markdown_views"><p>Redis中的数据结构分为: 字符串,链表,哈希,集合Set和有序集合</p><h2 id="sds">SDS</h2><h3 id="what">what</h3><p>Simple Dynamic String <br>用来代替C的原生字符串</p><h3 id="where-用在哪儿

Redis中的数据结构分为: 字符串,链表,哈希,集合Set和有序集合

SDS

what

Simple Dynamic String
用来代替C的原生字符串

where 用在哪儿

key,值中的字符串类型,以及AOF等缓冲区中

why 为啥要用

因为比C原生的字符串要好:
1. O(1)获取长度
2. 杜绝缓冲区溢出
3. 减少修改字符串时带来的内存重新分配次数
4. 二进制安全
5. 兼容部分C字符串函数

how 怎么做到的

基本结构:

public class SDS {
        // 占用长度 1满足了
    private int len;
    // 空闲,用来预留空间,减少重新分配次数
    private int free;
    // 数据 4满足了
    private byte[] buf;

    public SDS(int length){
        buf = new byte[length + 1];
        len = 0;
        free = length;
    }

    public SDS(String s){
        buf = new byte[s.length() + 1];
        System.arraycopy(s.toCharArray(), 0, buf, 0, s.length());
        // 5满足了
        buf[s.length()] = '\u0000';
        free = 0;
        len = s.length();
    }
}

该结构一眼看去,有一个len属性,于是上面why中的第1条满足了。
第二眼看去,居然真正的长度比实际的要多1,存放了’\u0000’。 卡卡,这个跟c原生的结构就一样了,因此5满足了
第三眼看去,用的是bute 而不是char, 这就说明了数据是按字节存储的,如果是char的话,就是带有规则的,而byte是纯粹的字节,提供了对二进制数据的支持,满足了4

修改SDS

看实现:

/**
     * 添加到末尾,如果空间不够,会重新分配
     * @param sds
     */
      public void sdscat(SDS sds){
        if(sds.len > this.free){
            byte[] temp = new byte[(this.len + sds.len) * 2 + 1];
            free = 0;
            System.arraycopy(this.buf, 0, temp, 0, this.len);
            System.arraycopy(sds.buf, this.len, temp, 0, sds.len);
            temp[this.len + sds.len] = '\u0000';
            this.len = (this.len + sds.len) * 2 + 1;
            this.buf = temp;
        }
    }

首先这里在添加到末尾的时候,如果是c语言则会造成脏数据,内存溢出这种情况,对于Java来说直接就是内存溢出异常了,不管怎么说都不行,因此实现的方式是先判断够不够,不够就扩展。
这样2满足了。

再看, 实际创建的长度,是需要的二倍+1, 1就是空字符了,二倍呢就是留着以后用的了,这个叫做预分配,是为了减少重新分配次数的一种办法。Java中ArrayList也是可以这样搞的。
除了预分配,还有懒回收,就是删除的空间先不回收,留着用。如下:

    public void sdstrim(byte a){
        // 不重新分配,只是增加free的值,删除char a后所有后面的前移,具体算法的复杂度在O(N^2)
    }

链表

提供节点重排, 灵活插入,顺序遍历的特性
主要用在列表键,发布订阅等功能中
不具体展开说了,很像Java的LinkedList.具有如下特性:
- 双头
- 无环
- 带表头和表尾指针,而不用遍历,使复杂度为O(1)
- 带长度计数器,不用遍历

哈希

hash键的实现之一

结构

联系到Java就是HashMap
Redis中一个字典对应多个HashTable, 一个HashTable对应多个Hash节点。
Java中,字典对应HashMap, 一个HashMap有多个Entry, Entry是一个单项链表,所以一个Entry会对应多个Entry节点。

算法

计算hash值,然后求索引,找到其所在的HashTable。
因为HashTable中的节点是链式的,所以把该值放到链的最前面。 如果是查询值,则会先根据所以找到对应的HashTable,然后遍历HashTable的节点找到具体的值。

其他

跳跃表

用于实现有序集合

整数集合

集合键的一种实现
该数据结构包含了存储数据的数组以及数据类型(int8, int16),
如果把长度不同的混存,就会引起升级的现象

压缩列表

用于列表键和哈希键
当值为小整数,或者短字符串,并且数量不多的时候会采用该数据结构。
是为了节约内存而设计的

对象

上面仅仅是介绍了一些底层的数据结构,但是Redis并没有直接使用这些数据结构,而是封装为了对象。用对象来封装键值。
一个对象的结构:

public class RedisObject{
    // 类型
    Enum type;
    // 编码
    Enum encoding;
    // 底层的数据结构
    *impl
}

type的取值:{字符串,列表,哈希,集合,有序集合}
encoding, 这个编码集的意思跟mysql中的整理有点像,不是字符集编码,是具体采用了什么底层数据结构{字典,双端列表,整数集合…}

对象与数据结构

  • 字符串 全int时用long, >39是SDS, <39时另外的算法
  • 列表 ziplist或者linkedlist
  • 哈希 ziplist(同样把键值对铺开紧密相连) hashtable
  • 集合 intset hashtable
  • 有序集合 ziplist(用紧挨的连个值一个表示成员,一个表示分值) skiplist

回收与共享

对象中有refcount作为引用计数器,每多一个引用+1.为0时被释放,可以看做最简单的GC。
另外想要对象共享时也可使用此方法,指向同一个对象,只是增加计数器。但是只有由int型的小字符串才能共享,这是因为共享对象太复杂,那么验证共享对象是否是目标对象的操作就会很耗CPU。

空转时长

对象有多久没被访问了。
主要是redis的GC算法来使用的,会优先释放lru较大的数据。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
21天前
|
存储 算法 Java
散列表的数据结构以及对象在JVM堆中的存储过程
本文介绍了散列表的基本概念及其在JVM中的应用,详细讲解了散列表的结构、对象存储过程、Hashtable的扩容机制及与HashMap的区别。通过实例和图解,帮助读者理解散列表的工作原理和优化策略。
30 1
散列表的数据结构以及对象在JVM堆中的存储过程
|
28天前
|
存储 消息中间件 NoSQL
Redis数据结构:List类型全面解析
Redis数据结构——List类型全面解析:存储多个有序的字符串,列表中每个字符串成为元素 Eelement,最多可以存储 2^32-1 个元素。可对列表两端插入(push)和弹出(pop)、获取指定范围的元素列表等,常见命令。 底层数据结构:3.2版本之前,底层采用**压缩链表ZipList**和**双向链表LinkedList**;3.2版本之后,底层数据结构为**快速链表QuickList** 列表是一种比较灵活的数据结构,可以充当栈、队列、阻塞队列,在实际开发中有很多应用场景。
|
2月前
|
存储 消息中间件 NoSQL
Redis 数据结构与对象
【10月更文挑战第15天】在实际应用中,需要根据具体的业务需求和数据特点来选择合适的数据结构,并合理地设计数据模型,以充分发挥 Redis 的优势。
55 8
|
2月前
|
存储 NoSQL Java
介绍下Redis 的基础数据结构
本文介绍了Redis的基础数据结构,包括动态字符串(SDS)、链表和字典。SDS是Redis自实现的动态字符串,避免了C语言字符串的不足;链表实现了双向链表,提供了高效的操作;字典则类似于Java的HashMap,采用数组加链表的方式存储数据,并支持渐进式rehash,确保高并发下的性能。
介绍下Redis 的基础数据结构
|
28天前
|
存储 NoSQL 关系型数据库
Redis的ZSet底层数据结构,ZSet类型全面解析
Redis的ZSet底层数据结构,ZSet类型全面解析;应用场景、底层结构、常用命令;压缩列表ZipList、跳表SkipList;B+树与跳表对比,MySQL为什么使用B+树;ZSet为什么用跳表,而不是B+树、红黑树、二叉树
|
28天前
|
存储 NoSQL Redis
Redis常见面试题:ZSet底层数据结构,SDS、压缩列表ZipList、跳表SkipList
String类型底层数据结构,List类型全面解析,ZSet底层数据结构;简单动态字符串SDS、压缩列表ZipList、哈希表、跳表SkipList、整数数组IntSet
|
存储 NoSQL 算法
「Redis」数据结构与对象
Redis数据结构与对象介绍
|
NoSQL 算法 Java
Redis进阶 - 数据结构:对象机制详解,一文深入底层分析
我们在前文已经阐述了Redis 5种基础数据类型详解,分别是字符串(string)、列表(list)、哈希(hash)、集合(set)、有序集合(zset),以及5.0版本中Redis Stream结构详解;那么这些基础类型的底层是如何实现的呢?Redis的每种对象其实都由对象结构(redisObject) 与 对应编码的数据结构组合而成, 本文主要介绍对象结构(redisObject) 部分。
Redis进阶 - 数据结构:对象机制详解,一文深入底层分析
下一篇
无影云桌面