Redis Hashes 数据类型简述
Redis Hashes 是我们日常使用中比较高频的 Redis 数据类型,内部使用 Redis 字典结构存储,底层基于哈希表结构实现。
下面从哈希表节点,哈下表结构,Redis 字典,Redis 字典元素操作,Redis rehash 几点来简要概述。
一、Redis 哈希表节点
Redis 内部定义哈希表节点 dictEntry,用于存储具体的数据,其主要包括键 key,值 v,及外向指针。
1、dictEntry 具体定义
typedef struct dictEntry {
void *key;
union{
void *val;
uint64_t u64;
int64_t s64;
} v;
struct dictEntry *next; //下一个节点指针
} dictEntry;
key:键值对 key
v:键值对 value,可以是指向指针,或者具体的类型。
next:为指向下一个节点的指针,用于处理键哈希冲突问题。相同哈希值键的键值对会以链表的形式存在同一位置。
2、示例哈希表节点数据
如下,哈希表容量 size 为 4,掩码 sizemask 为 3 ,内部存储了两个键值对(k1、v1)、(k2、v2),已使用容量 used 为 2:

二、Redis 哈希表结构
Redis 内部定义哈希表结构 dictht,用于存储实际的(k、v)键值对,其主要包括哈希表数组,容量、已使用容量及掩码。
1、dictht 具体定义
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht
table:哈希表数组,为指向 dictEntry 类型数组的指针,存储具体的键值对元素。
size:哈希表容量,规划申请的容量
sizemask:哈希表大小掩码,用于索引计算,计算方式为 size - 1
used:已使用容量,实际存储的(k、v)键值对数
2、示例哈希表数据
如下,哈希表容量 size 为 4,掩码 sizemask 为 3 ,内部存储了一个键值对(k1、v1),已使用容量 used 为 1:

三、Redis 字典实现
Redis 字典基于上述的哈希表实现,其主要包括内部特定类型函数、私有数据、哈希表数组及 rehash 进度标识等数据。
1、dict:
typedef struct dict{
dictType *type;
void *privdata;
dictht ht[2];
int rehashidx;
} dict
type:类型为dictType,保存了用于操作特定类型键的函数,和 privdata 共同服务于构建 Redis 多态字典。
privdate:和type协同使用,为需要传递给特定类型函数的可选参数。
ht:哈希表数组,类型为dictht,ht[0] 为实际存储数据使用,ht[1] 为 rehash 时使用。
ehashidx:rehash 进度标志,-1 代表当前不在 rehash 进程中。
2、Redis 字典示例数据
如下,包含两个元素的 Redis 字典:

四、Redis 字典添加元素
向字 Redis 典中添加元素主要涉及以下几步操作:
1、计算键值对键的哈希值
hash = dict->type->hashFunction(key)
上面第三节我们提到过 Redis 字典的属性 type,应用其内部的哈希函数得到键哈希值。
2、计算需要放入的位置索引
index = hash & dict->ht[0].sizemask
使用上一步计算得到的哈希值与哈希表的 sizemask 属性进行【与操作】得到需要放入的位置索引值
3、键冲突解决
没有完美的哈希函数,哈希冲突无法避免,实际应用中,多个键往往会被索引到同一个位置时,这种现象,我们称之为键冲突。
Redis 采用链地址法解决键冲突:也即将冲突的键值对组成一个链表放到同一个哈希位置上。
上面第二节我们介绍过 dictEntry 的结构,其中包含一个指向另一个节点的指针 next。
这里需要说明的一点是:冲突节点插入时,是插入到链表的头部,这样只需要执行操作一次操作即可,也即时间复杂度为 O(1)。
如下图:(k2,v2)与(k1,v1)发生冲突,直接将(k2,v2)插入到链表头部:

五、Redis rehash
Redis rehash 是指 Redis 字典重新规划哈希表空间占用的过程。Redis 字典往往伴随着元素的增删改等操作,随着元素的增多或减少,需要适时地进行 Redis 字典容量的重新规划。
1、负载因子
哈希表使用负载因子(load_factor)来标识当前哈希表的使用状态,计算公式为:已保存节点数量(dict.ht[0].used)/ 哈希表容量(dict.ht[0].size)。它需要保持在一个合理的范围,以保障资源的最优利用。通常需要适时的对哈希表进行扩展或者收缩来对负载因子进行维护。
这里涉及到一个问题,就是什么时候需要进行伸缩维护?
a)扩展时机:
触发 rehash 实际收到 当前 Redis 服务器状态影响,即有无后台 bgsave 及 bgrewriteaop 操作:
无操作,则触发 load_factor 标准为 >= 1
当前有操作,则触发 load_factor 标准为 >= 5
Redis 服务器通过 fork 子进程形式执行 bgsave 及 bgrewriteaop 操作,此期间整个服务的资源耗费较大,为了避免可能发生的 rehash 带来额外的资源压力,服务器往往会调高触发执行 rehash 操作的负载因子界限,以降低触发 rehash 的频率。
b)收缩时机:
load_factor < 0.1
2、Redis rehash 基本过程
Redis rehash 过程主要包括空间分配、rehash 执行、重定向三个过程
a) 空间分配:
空间分配是指 为 dict.ht[1] 分配空间
所需要的空间大小计算如下:
扩展:最小n满足2n >= dict.ht[0].used * 2
收缩:最小n满足2n >= dict.ht[0].used
如下图:ht[0].used = 3,假定无bg相关任务,则h[1]大小需要计算:2n >= 3 * 2 = 6
n = 3,ht[1].size = 23 = 8

b) rehash 执行
此过程会逐一对 dict.ht[0] 中的元素,依据dict.ht[1] 特性(sizemask)重新计算索引值,并放置到 dict.ht[1] 中。
如下图:h[0] 中的元素以被完全 rehash 到 h[1] 中存储:

c) 重定向
当所有元素迁移完毕后,Redis 会释放调 dict.ht[0] 的空间占用,并将 dict.ht[1] 设置为 dict.ht[0],并重新在 dict.ht[1] 上创建空的哈希表,以用于下次 rehash 使用。
如下图:重新指向完毕,并创建了新的 ht[1]:

六、Redis rehash 并非一蹴而就
针对实际存储中不同容量的字典数据,Redis 采用不同的措施进行 rehash 执行:对于数据量较小的字典可以直接一次性的执行rehash;而对于数据量较大的字典数据,直接一次性的执行 rehash 会导致服务资源的集中占用,影响正常的服务响应。因此需要进行分而治之,采用渐进式执行过程。
渐进式 rehash 会用到上面第三节我们介绍的 dict 字典结构中的 rehashidx 属性,用以标识当前 rehash 进度。
关于渐进式 rehash 过程中 rehashidx 操作如下:
首先将rehashidx置0,标示rehash开始
每次rehash一个元素,rehashidx值增加1
当最终所有元素rehash完成,将rehashidx置-1。
渐进式 rehash 进程中对正常的服务请求的处理如下:
1、删除、查找、更新:
会涉及到两个哈希表(ht[0]、ht[1])操作,如查找元素,首先尝试在ht[0]上查找,找不到,则继续在h[1]上查找。
2、添加
添加元素只会在h[1]上操作,h[0] 上元素此过程保持只减不增。
Redis Hashes 数据类型简述的更多相关文章
- redis:hash 数据类型
简介 Redis Hashes是字符串字段和字符串值之间的映射,所以它们是完美的表示对象(eg:一个有名,姓,年龄等属性的用户)的数据类型.新建一个hash对象时开始是用zipmap(又称为small ...
- Redis的数据类型及其常用命令
快速入门Redis 首先安装redis: windows下安装redis Linux下安装redis 1. 什么是redis Redis属于nosql(非关系型数据库) 关系型数据库是基于关系表的数据 ...
- redis的数据类型与应用场景(二)
1. 如何学习 redis有好多数据类型,有这么多数据类型,我们不可能每个都记得完完全全.但是我们必须知道它有哪些数据类型,每个数据类型是怎样的,有什么作用.redis的每一个数据类型都有一大堆命令, ...
- redis学习——数据类型
一.内容简介 Redis不仅仅是简单的key-value 存储器,同时也是一种data structures server.传统的key-value是指支持使用一个key字符串来索引value字符串的 ...
- Redis之数据类型
一.概念: Redis:一个开源.支持网络.基于内存.键值对存储数据库. 特点:它可以支持多种数据类型. 二.数据类型 1)Redis String 具体说明: 一般的普通的k到v一个映射是Strin ...
- Redis常用数据类型介绍、使用场景及其操作命令
Redis常用数据类型介绍.使用场景及其操作命令 本文章同时也在cpper.info发布. Redis目前支持5种数据类型,分别是: 1.String(字符串) 2.List(列表) 3.Hash(字 ...
- Redis笔记(三)Redis的数据类型
前面说过,Redis的一大特性是支持丰富的数据类型, 这为更多的应用场景提供了可能. Redis有五种数据类型,包括string,list,set,sorted set和hash,注意,Redis的数 ...
- Redis常用数据类型
Redis常用数据类型 转载自:http://blog.sina.com.cn/s/blog_7f37ddde0101021q.html Redis最为常用的数据类型主要有以下五种: ●Str ...
- Redis基本数据类型
-------------------Redis基本数据类型------------------- 1.String 字符串 1.概念 1.String 是redis最基本的类 ...
随机推荐
- 血的教训!千万别在生产使用这些 redis 指令
哎,最近小黑哥又双叒叕犯事了. 事情是这样的,前一段时间小黑哥公司生产交易偶发报错,一番排查下来最终原因是因为 Redis 命令执行超时. 可是令人不解的是,生产交易仅仅使用 Redis set 这个 ...
- Redis必须会的知识点
Nosql:非关系型数据库 分表分库 + 水平拆分 + mysql集群: 在Memcached的高速缓存,Mysql主从复制.读写分离的基础上,由于MyISAM使用表锁,高并发Mysql应用开始使用I ...
- 【Nginx】冰河又一本超硬核Nginx PDF教程免费开源!!
写在前面 在 [冰河技术] 微信公众号中的[Nginx]专题,更新了不少文章,有些读者反馈说,在公众号中刷 历史文章不太方便,有时会忘记自己看到哪一篇了,当打开一篇文章时,似乎之前已经看过了, 但就是 ...
- Hadoop演进与Hadoop生态
1.了解对比Hadoop不同版本的特性,可以用图表的形式呈现. (1)0.20.0~0.20.2: Hadoop的0.20分支非常稳定,虽然看起来有些落后,但是经过生产环境考验,是 Hadoop历史上 ...
- Win10使用VMWare15安装Ubuntu-18.04.2-desktop-amd64
本文在Win10系统中使用VMWare Workstation Pro 15.1.0虚拟机安装Ubuntu-18.04.2-desktop-amd64.iso系统,同时安装VMWare Tools(实 ...
- UOS服务器常见问题
UOS服务器安装完成之后,xshell工具无法远程, 描述 我安装完系统后,用xshell工具无法远程,必须在系统上才能进去我是通过centos7的kvm虚拟工具上刷的统信的系统,安装方式: 最小化安 ...
- Python爬取股票信息,并实现可视化数据
前言 截止2019年年底我国股票投资者数量为15975.24万户, 如此多的股民热衷于炒股,首先抛开炒股技术不说, 那么多股票数据是不是非常难找, 找到之后是不是看着密密麻麻的数据是不是头都大了? 今 ...
- Spring属性注入(set方式、构造函数方式、p名称空间、spel、复杂类型)
1.set注入方式 (1)注入的为值类型(八大数据类型)的数据 配置文件: <?xml version="1.0" encoding="UTF-8"?&g ...
- Hadoop框架:集群模式下分布式环境搭建
本文源码:GitHub·点这里 || GitEE·点这里 一.基础环境配置 1.三台服务 准备三台Centos7服务,基础环境从伪分布式环境克隆过来. 133 hop01,134 hop02,136 ...
- MMC & SD 发展历史
一.概述 MMC 卡和 SD 卡都是基于 Nand Flash 技术的移动存储卡. MMC(MultiMediaCard) 卡于 1997 年由西门子和 Sandisk 推出,SD (Secure D ...