Redis-数据结构与对象

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Redis 版,经济版 1GB 1个月
简介: <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
相关文章
|
2天前
|
存储 NoSQL Redis
Redis系列学习文章分享---第十六篇(Redis原理1篇--Redis数据结构-动态字符串,insert,Dict,ZipList,QuickList,SkipList,RedisObject)
Redis系列学习文章分享---第十六篇(Redis原理1篇--Redis数据结构-动态字符串,insert,Dict,ZipList,QuickList,SkipList,RedisObject)
10 1
|
2天前
|
存储 NoSQL 安全
Redis系列学习文章分享---第十五篇(Redis最佳实践--设计优雅的key+合适的数据结构+持久化如何配置+慢查询问题解决)
Redis系列学习文章分享---第十五篇(Redis最佳实践--设计优雅的key+合适的数据结构+持久化如何配置+慢查询问题解决)
7 1
|
2天前
|
存储 消息中间件 缓存
Redis系列学习文章分享---第十七篇(Redis原理篇--数据结构,网络模型)
Redis系列学习文章分享---第十七篇(Redis原理篇--数据结构,网络模型)
7 0
|
3天前
|
存储 缓存 NoSQL
Redis为什么速度快:数据结构、存储及IO网络原理总结
Redis为什么速度快:数据结构、存储及IO网络原理总结
|
3天前
|
存储 NoSQL API
Redis数据结构与底层实现揭秘
Redis数据结构与底层实现揭秘
|
存储 NoSQL 算法
Redis之小对象压缩
Redis之小对象压缩
850 1
|
13天前
|
存储 运维 NoSQL
Redis Cluster集群模式部署
Redis Cluster集群模式部署
39 4
|
15天前
|
监控 NoSQL 算法
手把手教你如何搭建redis集群(二)
手把手教你如何搭建redis集群(二)
28 1
|
15天前
|
存储 NoSQL 容灾
手把手教你如何搭建redis集群(一)
手把手教你如何搭建redis集群(一)
34 1
|
1月前
|
负载均衡 监控 NoSQL
Redis的几种主要集群方案
【5月更文挑战第15天】Redis集群方案包括主从复制(基础,读写分离,手动故障恢复)、哨兵模式(自动高可用,自动故障转移)和Redis Cluster(官方分布式解决方案,自动分片、容错和扩展)。此外,还有Codis、Redisson和Twemproxy等工具用于代理分片和负载均衡。选择方案需考虑应用场景、数据量和并发需求,权衡可用性、性能和扩展性。
224 2