文章目录

  • Redis是如何支持基于Key的快速访问的
  • 全局哈希表
    • 哈希表结构
    • 哈希冲突
  • 一张图
  • 相关源码

Redis是如何支持基于Key的快速访问的

一谈到Redis,马上能想到的就是:“快”,那么,Redis之所以快,一方面是因为Redis的所有操作都在内存中完成,内存操作本身就很快,另一方面就要归功于它的数据结构了,高效的数据结构是Redis快的基石。

全局哈希表

为了实现基于Key的快速访问,Redis采用了哈希表作为最底层的数据存储结构,如果你了解Java中的HashMap,那么理解Redis的哈希表则应该非常容易,实际上也就是数组+链表的结构,这样一来,我们就可以在O(1)的时间复杂度下快速的查找出所需的Key,并且无论是多少Key都不受影响。

我们先来看看哈希表的具体结构设计,每一个dictEntry元素,都保存了*key和*value的指针,*value指针保存在联合体v中,既然保存的是指针,所以也就能保存任何类型的数据结构(String,Hash,List,Set)

typedef struct dictEntry {void *key;union {void *val;uint64_t u64;int64_t s64;double d;} v;struct dictEntry *next;
} dictEntry;

哈希表结构

typedef struct dictht {dictEntry **table;unsigned long size;unsigned long sizemask;unsigned long used;
} dictht;

哈希冲突

当然,提到哈希表,肯定少不了哈希冲突的问题,Redis中采用的方式和Java中的HashMap一样,都是链式哈希的方式,所以一旦冲突变多,就会导致链表过长,最终退化为O(n)的时间复杂度,这对Redis来说肯定是不能接受的。

所以,解决的方式也和Java中的HashMap一样,直接进行一次rehash操作就好了,简单来说就是扩大Entry数组的大小,从而来减少哈希冲突,当然为了不对线上访问造成影响,Redis还采用渐进式rehash的方式,实际上Redis每次在进行rehash操作时,会新准备一个比原哈希表大一倍的新哈希表,然后在每一次处理请求的时候,顺便处理一次数据迁移,比如从原哈希表的第一个索引位置开始,把这个位置上的Entry全部挪到新的哈希表中,这样通过分摊处理,就避免了一次性全量处理所带来的阻塞问题。

一张图

相关源码

就用Hash数据类型中的HGET方法举例

void hgetCommand(client *c) {robj *o;if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp])) == NULL ||checkType(c,o,OBJ_HASH)) return;addHashFieldToReply(c, o, c->argv[2]->ptr);
}
static void addHashFieldToReply(client *c, robj *o, sds field) {int ret;if (o == NULL) {addReplyNull(c);return;}// 如果底层数据结构是压缩列表的处理逻辑if (o->encoding == OBJ_ENCODING_ZIPLIST) {unsigned char *vstr = NULL;unsigned int vlen = UINT_MAX;long long vll = LLONG_MAX;ret = hashTypeGetFromZiplist(o, field, &vstr, &vlen, &vll);if (ret < 0) {addReplyNull(c);} else {if (vstr) {addReplyBulkCBuffer(c, vstr, vlen);} else {addReplyBulkLongLong(c, vll);}}// 如果底层是Hash表的处理逻辑} else if (o->encoding == OBJ_ENCODING_HT) {sds value = hashTypeGetFromHashTable(o, field);if (value == NULL)addReplyNull(c);elseaddReplyBulkCBuffer(c, value, sdslen(value));} else {serverPanic("Unknown hash encoding");}
}

看Hash表的逻辑,基本上就是标准的Hash表查找方式

sds hashTypeGetFromHashTable(robj *o, sds field) {dictEntry *de;serverAssert(o->encoding == OBJ_ENCODING_HT);de = dictFind(o->ptr, field);if (de == NULL) return NULL;return dictGetVal(de);
}
dictEntry *dictFind(dict *d, const void *key)
{dictEntry *he;uint64_t h, idx, table;if (dictSize(d) == 0) return NULL; /* dict is empty */if (dictIsRehashing(d)) _dictRehashStep(d);h = dictHashKey(d, key);for (table = 0; table <= 1; table++) {idx = h & d->ht[table].sizemask;he = d->ht[table].table[idx];while(he) {if (key==he->key || dictCompareKeys(d, key, he->key))return he;he = he->next;}if (!dictIsRehashing(d)) return NULL;}return NULL;
}
#define dictGetVal(he) ((he)->v.val)

【Redis实战】认识Redis中的全局哈希表相关推荐

  1. Redis实战之Redis + Jedis

    用Memcached,对于缓存对象大小有要求,单个对象不得大于1MB,且不支持复杂的数据类型,譬如SET 等.基于这些限制,有必要考虑Redis! 相关链接: Redis实战 Redis实战之Redi ...

  2. Redis实战 - 09 Redis BitMaps 实现用户签到,统计签到次数,统计签到情况等功能

    文章目录 1. 需求分析 2. 设计思路 3. 用户签到和统计连续签到的次数 1. 签到控制层 SignController 2. 签到业务逻辑层 SignService 3. 测试 4. 按月统计用 ...

  3. redis(二)redis实战 使用redis进行文章的排序

    2019独角兽企业重金招聘Python工程师标准>>> http://www.beckbi.cn/?p=172 redis实战使用redis进行文章的排序 转载于:https://m ...

  4. 程序员面试中常见的哈希表,到底是什么?

    作者 | 倪升武 责编 | 胡巍巍 我所写的这些数据结构,都是比较经典的,也是面试中经常会出现的,这篇文章我就不闲扯了,全是干货,如果你能读完,希望对你有所帮助~ 哈希表也称为散列表,是根据关键字值( ...

  5. Redis实战 - 15 Redis事务机制和乐观锁实现

    文章目录 1. Redis事务简介 2. Redis事务的操作命令 3. Redis的事务回滚 4. Redis监控事务 1. Redis事务简介 在 Redis 中,也存在多个客户端同时向 Redi ...

  6. Redis底层详解(一) 哈希表和字典

    一.哈希表概述 首先简单介绍几个概念:哈希表(散列表).映射.冲突.链地址.哈希函数. 哈希表(Hash table)的初衷是为了将数据映射到数组中的某个位置,这样就能够通过数组下标访问该数据,提高数 ...

  7. mysql是表级锁还是行级锁_带你了解MySQL数据库中的全局锁、表级锁、行级锁

    在 MySQL 数据库中,有很多各种各样的锁,这些锁大致可以分为三类:全局锁.表级锁.行级锁.这篇文章小编就带你简单了解一下这三种锁. 1. 全局锁 全局锁是粒度比较大的锁,基本上也使用不上,就像我们 ...

  8. c++的STL中的map(哈希表)与unordered_map

    map: unordered_map: map: map内部实现了一个红黑树,该结构具有自动排序的功能,因此map内部的所有元素都是有序的 unordered_map:unordered_map内部实 ...

  9. 在Javascript中实现伪哈希表

    了解数据结构的人应该都听说过哈希表这种数据结构,它是一种典型的利用键值对存储并检索数据的一种非线性结构,又称散列表或杂凑法.在一般的线性表结构中,数据的相对位置是随机的,即数据和用于检索的关键字之间不 ...

最新文章

  1. oracle rodm包,由重启引起的Oracle RAC节点宕机分析及追根溯源
  2. 工作中涉及运维知识点的汇总
  3. 网站SEO优化之如何发布外链
  4. Linux curl命令参数详解--转载
  5. 处理 read_csv 报错 OSError:Initializing from file failed
  6. python之路----验证客户端合法性
  7. Java中Map, List, Set和Queue的区别和使用场景
  8. 企业信息化建设过程中,交通物流行业如何凭借数据成功转型?
  9. Linux开启路由转发功能
  10. Nodejs线上日志部署
  11. keras添加正则化全连接_第16章 Keras使用Dropout正则化防止过拟合
  12. nexttick使用场景_使用Jest实现Vue自动化测试
  13. Java对象引用之“强引用、软引用、弱引用、虚引用”
  14. MT4用EA测试历史数据时日志出现:stopped because of stop out
  15. 未开票收入怎么申报?后期补票又怎么申报?
  16. Cannot mix different versions of joi schemas解决方案
  17. 玉米社:百度SEM竞价推广策略有哪些?
  18. 2020阿里招聘岗位要求
  19. 空间管理系统有哪些管理模块?
  20. Objective-C修改运动步数

热门文章

  1. shell脚本(linux)
  2. 电源快速脉冲群EFT和静电测试ESD不通过怎么办?
  3. c语言 Linux CURL发送Http get请求 带参数
  4. 《大侦探福尔摩斯2:诡影游戏》蓝光高清720P 1080P下载[2011最新动作]
  5. 计算机网络专用术语基本概念
  6. Android开发中的WMS详细解析
  7. 你在客户那到底算老几
  8. 【BLDC理论篇】直流无刷电机控制方法
  9. 图像金字塔、特征金字塔(FPN)
  10. 变量、存储过程与函数