神奇,Redis存储原理竟然是这样!

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis是一个Key-Value模式的非关系型数据库,那么Key和Value的保存模式我们在这里说一说。其实kv给大家的第一影响是啥?数组?哈希?没错就是哈希,redis其实是用哈希表保存的键值对,键为str,值为数据类型,哈希表中的每一对元素是哈希桶

本文的部分内容参考自《小林Coding》,部分地方根据源代码进行剖析。
Redis源码地址:https://github.com/redis/redis.git

今天继续

Redis存储是如何实现的?

键值对的实现

Redis是一个Key-Value模式的非关系型数据库,那么Key和Value的保存模式我们在这里说一说。

其实kv给大家的第一影响是啥?数组?哈希?

没错就是哈希,redis其实是用哈希表保存的键值对,键为str,值为数据类型,哈希表中的每一对元素是哈希桶

哈希桶存放的是啥?如果学过C++的STL,这里你可以理解为pair<string,T>

下面来西索一下。

img

下面来简单聊聊图上面的东西,具体的聊我会在后文说,真实的存储其实和这个图还是有些区别

Redis的数据库管理

  • redisDb 结构,表示 Redis 数据库的结构,结构体里存放了指向了 dict 结构的指针;

  • dict 结构,结构体里存放了 2 个哈希表,正常情况下都是用「哈希表1」,「哈希表2」只有在 rehash 的时候才用;

  • dictht 结构,表示哈希表的结构,结构里存放了哈希表数组,数组中的每个元素都是指向一个哈希表节点结构(dictEntry)的指针;

    在最新版的dict中已经将dictht改为了数组,这样可能稍微难以理解,一会儿细说

  • dictEntry 结构,表示哈希表节点的结构,结构里存放了 void key 和 void value 指针, key 指向的是 String 对象,而 \value 则可以指向 String 对象,也可以指向集合类型的对象,比如 List 对象、Hash 对象、Set 对象和 Zset 对象

下面我们来说说源代码,我会在保留原注释的条件下进行解释

/* Redis database representation. There are multiple databases identified
 * by integers from 0 (the default database) up to the max configured
 * database. The database number is the 'id' field in the structure. */
//Redis数据库结构,通过ID来识别多个数据库
typedef struct redisDb {
   
    // 当前数据口的所有键值对空间
    dict *dict;                 /* The keyspace for this DB */
    // 存放已设置exptime的key的集合
    dict *expires;              /* Timeout of keys with a timeout set */

    // 客户端等待的阻塞中的key
    dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP)*/
    // 客户端等待的阻塞中的key,如果key被删除,那么应该取消阻塞,是blocking_keys的子集
    dict *blocking_keys_unblock_on_nokey;    /* Keys with clients waiting for data, 
                                              *and should be unblocked if key is deleted (XREADEDGROUP).
                                              *This is a subset of blocking_keys*/
    // 可以解除阻塞的键(客户端已经收到的key)
    dict *ready_keys;           /* Blocked keys that received a PUSH */
    // 还在被watch命令监视中的键
    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */
    // 数据库id
    int id;                     /* Database ID */
    // 数据库的平均TTL
    long long avg_ttl;          /* Average TTL, just for stats */
    unsigned long expires_cursor; /* Cursor of the active expire cycle. */
    list *defrag_later;         /* List of key names to attempt to defrag one by one, gradually. */
    clusterSlotToKeyMapping *slots_to_keys; /* Array of slots to keys. Only used in cluster mode (db 0). */
} redisDb;

//dictEntry的实现很简单,就是个链表
struct dictEntry {
   
    void *key;
    union {
   
        void *val;            //其他
        uint64_t u64;        //整数
        int64_t s64;        //整数
        double d;            //双精度数值
    } v;
    struct dictEntry *next;     /* Next entry in the same hash bucket.  指向下一个hash值相同的entry*/
    void *metadata[];           /* An arbitrary number of bytes (starting at a
                                 * pointer-aligned address) of size as returned
                                 * by dictType's dictEntryMetadataBytes(). */
};


struct dict {
   
    dictType *type;

    dictEntry **ht_table[2];    //第二个表用来进行rehash    
    /**
    *    dictEntry **ht_table[2]; <==>
    *     typedef struct dictht{
    *        dictEntry **table;
    *    }dictht;
    *    ditcht ht[2];
    **/

    unsigned long ht_used[2];    

    //用于保证rehash安全,如果值为1,那么不能执行rehash
    long rehashidx; /* rehashing not in progress if rehashidx == -1 */

    //redis6之后新加入,如果值>0则暂停rehash,保证rehash安全
    /* Keep small vars at end for optimal (minimal) struct padding */
    int16_t pauserehash; /* If >0 rehashing is paused (<0 indicates coding error) */

    //哈希的内存指数
    signed char ht_size_exp[2]; /* exponent of size. (size = 1<<exp) */

    //由dictType的dictEntryBytes定义的大小的任意字节数(从指针对齐的地址开始)。
    void *metadata[];           /* An arbitrary number of bytes (starting at a
                                 * pointer-aligned address) of size as defined
                                 * by dictType's dictEntryBytes. */
};

/* If safe is set to 1 this is a safe iterator, that means, you can call
 * dictAdd, dictFind, and other functions against the dictionary even while
 * iterating. Otherwise it is a non safe iterator, and only dictNext()
 * should be called while iterating. */
typedef struct dictIterator {
   
    dict *d;
    long index;
    int table, safe;
    dictEntry *entry, *nextEntry;
    /* unsafe iterator fingerprint for misuse detection. */
    unsigned long long fingerprint;
} dictIterator;

然后redisServer的内容有点多,我就截图了

image-20230720025349861

从这个图我们看出来,不仅数据可以用dict来存储,命令也是。

相关实践学习
基于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缓存存储(一)
100 1
|
2月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(二)
数据的存储--Redis缓存存储(二)
52 2
数据的存储--Redis缓存存储(二)
|
2月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
78 6
|
1天前
|
存储 消息中间件 监控
Redis Stream:实时数据流的处理与存储
通过上述分析和具体操作示例,您可以更好地理解和应用 Redis Stream,满足各种实时数据处理需求。
27 14
|
1月前
|
存储 NoSQL 算法
Redis分片集群中数据是怎么存储和读取的 ?
Redis集群采用哈希槽分区算法,共有16384个哈希槽,每个槽分配到不同的Redis节点上。数据操作时,通过CRC16算法对key计算并取模,确定其所属的槽和对应的节点,从而实现高效的数据存取。
49 13
|
1月前
|
存储 NoSQL Redis
【赵渝强老师】Redis的存储结构
Redis 默认配置包含 16 个数据库,通过 `databases` 参数设置。每个数据库编号从 0 开始,默认连接 0 号数据库,可通过 `SELECT &lt;dbid&gt;` 切换。Redis 的核心存储结构包括 `dict`、`expires` 等字段,用于处理键值和过期行为。添加键时需指定数据库信息。视频讲解和代码示例详见内容。
|
3月前
|
缓存 NoSQL Linux
redis的原理(三)
redis的原理(三)
redis的原理(三)
|
2月前
|
设计模式 NoSQL 网络协议
大数据-48 Redis 通信协议原理RESP 事件处理机制原理 文件事件 时间事件 Reactor多路复用
大数据-48 Redis 通信协议原理RESP 事件处理机制原理 文件事件 时间事件 Reactor多路复用
43 2
|
2月前
|
存储 缓存 NoSQL
大数据-46 Redis 持久化 RDB AOF 配置参数 混合模式 具体原理 触发方式 优点与缺点
大数据-46 Redis 持久化 RDB AOF 配置参数 混合模式 具体原理 触发方式 优点与缺点
70 1
|
2月前
|
NoSQL 关系型数据库 MySQL
Redis 事务特性、原理、具体命令操作全方位诠释 —— 零基础可学习
本文全面阐述了Redis事务的特性、原理、具体命令操作,指出Redis事务具有原子性但不保证一致性、持久性和隔离性,并解释了Redis事务的适用场景和WATCH命令的乐观锁机制。
366 0
Redis 事务特性、原理、具体命令操作全方位诠释 —— 零基础可学习