`

Redis 存储结构分析,及哈希相关

阅读更多

Redis 是支持多 key-value 数据库 ( ) , 并用 RedisDb 来表示一个 key-value 数据库 ( ). redisServer 中有一个 redisDb *db; 成员变量 , RedisServer 在初始化时 , 会根据配置文件的 db 数量来创建一个 redisDb 数组 . 客户端在连接后 , 通过 SELECT 指令来选择一个 reidsDb, 如果不指定 , 则缺省是 redisDb 数组的第 1 ( 即下标是 0)redisDb. 一个客户端在选择 redisDb , 其后续操作都是在此 redisDb 上进行的 .

 

dictType 中定义的为各种函数 : 哈希函数 ,key 比较函数 ,key/value 复制函数等 .

dict 是主要是由 struct dictht 的哈希表构成的 , 之所以定义成长度为 2 (dictht ht[2]) 哈希表数组 , 是因为 redis 采用增量的 rehash. 这种渐进的 rehash 需要一个额外的 struct dictht 结构来保存 .

dictht 中的 table 是一个数组 + 指针形式的 hash 表, size hash 数组 ( ) 的大小, used 表示 hash 表的元素个数,这两个值与 rehash resize 过程密切相关。 sizemask 等于 size-1 ,这是为了方便将 hash 值映射到数组中。

iterators 记录当前 dict 中的迭代器数,主要是为了避免在有迭代器时 rehash ,在有迭代器时 rehash 可能会造成值的丢失或重复 .

rehashidx 表示上次 rehash 时在 ht[0] 的下标位置 .

 

关于 rehash:

1)原因:
redis使用的为动态大小的哈希表,当哈希表的大小不能满足需求,元素的hash碰撞比较多时进行扩容. 由于在数据结构中定义使用两个哈希表,当第一个表ht中的元素大于桶的个数时,进行扩容(dictAdd->_dictKeyIndex->_dictExpandIfNeeded->dictExpand),每次扩容大小为((d->ht[0].size > d->ht[0].used) ? d->ht[0].size : d->ht[0].used)*2,初始值为DICT_HT_INITIAL_SIZE = 4.扩容后开始将第一个表ht中的元素进行增量rehash到第二个表中,当rehash完成时,将第二个表赋给第一个表,并将原表内存释放.

/* Check if we already rehashed the whole table... */
if (d->ht[0].used == 0) {
  zfree(d->ht[0].table);
  d->ht[0] = d->ht[1];
  _dictReset(&d->ht[1]);
  d->rehashidx = -1;
  return 0;
}

 

2)原则: 增量更新与分批更新同时进行,不阻塞请求. 将操作平摊到每次操作,以及充分利用server idle时的CPU资源,以减少突然的rehash行为造成服务器性能的瞬间下降.
3)模式:
lazy rehashing:在每次对dict进行操作的时候执行一个slot的rehash
_dictRehashStep中,也会调用dictRehash,而_dictRehashStep每次仅会rehash一个值从ht[0]到ht[1],但由于_dictRehashStep是被dictGetRandomKey、 dictFind、 dictGenericDelete、dictAdd调用的,因此在每次dict增删查改时都会被调用,这无疑就加快rehash了 过程。
active rehashing:每100ms里面使用1ms时间进行rehash。
serverCron中,当没有后台子线程时,会调用incrementallyRehash,最终调用dictRehashMilliseconds。 incrementallyRehash的时间较长,rehash的个数也比较多。这里每次执行 1 millisecond rehash 操作;如果未完成 rehash,会在下一个loop里面继续执行。
4)方法:
active rehashing: serverCron->incrementallyRehash->dictRehashMilliseconds->dictRehash(100)
lazy rehashing: dictAdd/dictGenericDelete/dictFind/dictGetRandomKey->_dictRehashStep-> dictRehash(1)

分享到:
评论

相关推荐

    Redis Python 客户端,Redis 键值存储的 Python 接口

    Redis 是一个高性能的键值存储系统,广泛应用于缓存、消息队列、实时分析等场景。在 Python 中,可以通过多个客户端库与 Redis 进行交互,其中最流行的是 `redis-py`。以下是 Redis Python 客户端及其主要功能的描述...

    redis开发的概要介绍与分析

    Redis是一个开源的、内存中的数据结构存储系统,它可以用作数据库、缓存和消息代理。Redis支持多种数据结构,包括字符串、哈希、列表、集合、有序集合等,并提供了丰富的API供开发者使用。 在Redis开发过程中,...

    Redis常用语法命令及使用示例详解

    Redis是一个开源的、内存中的数据结构存储系统,它可以用作数据库、缓存和消息中介。它支持多种数据类型,包括字符串(string)、哈希(hash)、列表(list)、集合(set)、有序集合(sorted set)等,并提供了丰富...

    Redis-64-5.0.10.7z

    Redis通常用于缓存、消息队列、实时数据分析、计数器、排行榜等场景,Redis是一个功能强大的键值对存储数据库,具有高速、高可用、可扩展等特点,适用于各种应用场景。 它的主要特点包括: 速度快:Redis使用ANSI ...

    redis安装配置详细教程.pdf

    Redis还具有多种应用场景,如在Web应用中存储会话信息、实现消息队列、排行榜和计数器、分布式锁以及实时分析等。例如,Redis的发布订阅功能可以用来实现消息队列,通过将消息发布到特定的频道,可以让订阅该频道的...

    Python 抓取数据存储到Redis中的操作

    和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set 有序集合)和hash(哈希类型),数据存储如下图分析 为了分别为ID存入多个键值对,此次仅对Hash数据...

    安装和配置指引,通俗易懂

    Redis支持多种数据结构,如字符串、哈希表、列表、集合、有序集合等,使其非常灵活和强大。 Redis的特点包括: - 高性能:Redis数据存储在内存中,读写速度非常快。 - 支持持久化:Redis可以将数据持久化到磁盘,...

    java 大数据 spark flink redis hive hbase kafka 面试题 数据结构 算法 设计模式.zip

    存储结构(物理结构):描述数据在计算机中如何具体存储。例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、...

    Practical-redis:这本书的代码-Practical Redis

    数据结构服务器-简单地说,Redis是一个数据库,但与传统数据库不同,因为它直接公开了核心数据结构-字符串,列表,集合,哈希,排序集合,地理空间索引,超级日志,位图等。 使用可以添加新的数据结构和功能 其他...

    Hash表的分析以及组成原理解析及代码实现.md

    Hash表采用了数组加链表的结构,即一个数组元组中不再是存储单个元素,而是存储一个链表,就好比包租婆收租的时候,一个握把上面挂了一连串的钥匙一样。Hash表的引出是为了减少查询数据库操作所带来的时间问题,将...

    nosql 入门教程

    3.1.4 Redis数据存储与访问 43 3.1.5 Redis数据查询 47 3.1.6 HBase数据存储与访问 50 3.1.7 HBase数据查询 52 3.1.8 Apache Cassandra数据存储与访问 54 3.1.9 Apache Cassandra数据查询 55 3.2 NoSQL数据...

    大数据与人工智能-fy.docx

    支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型) 答案解析:使用开源C语言编写 10. 以下哪个不属于Redis三大架构 [单选题] A.主从复制...

    最新Java面试题视频网盘,Java面试题84集、java面试专属及面试必问课程

    │ Java面试题78:redis存储对象的方式.mp4 │ Java面试题79:redis数据淘汰机制.mp4 │ Java面试题80:java访问redis级redis集群?.mp4 │ Java面试题81:微信公众号分类和微信开发原理.mp4 │ Java面试题82:怎么...

    开涛高可用高并发-亿级流量核心技术

    12.2.2 HttpClient连接池源码分析 240 12.2.3 HttpClient 4.2.3配置 241 12.2.4 问题示例 243 12.3 线程池 244 12.3.1 Java线程池 245 12.3.2 Tomcat线程池配置 248 13 异步并发实战 250 13.1 同步阻塞调用 251 13.2...

    java开源包8

    可以将列表数据缓存到redis中,其他kv结构数据继续缓存到memcached 6. 支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL...

    java开源包1

    可以将列表数据缓存到redis中,其他kv结构数据继续缓存到memcached 6. 支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL...

    java开源包11

    可以将列表数据缓存到redis中,其他kv结构数据继续缓存到memcached 6. 支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL...

    java开源包2

    可以将列表数据缓存到redis中,其他kv结构数据继续缓存到memcached 6. 支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL...

    java开源包3

    可以将列表数据缓存到redis中,其他kv结构数据继续缓存到memcached 6. 支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL...

Global site tag (gtag.js) - Google Analytics