当前位置:首页 > 数码 > 深化了解缓存的神奇世界-浅析Redis数据结构 (缓存深度)

深化了解缓存的神奇世界-浅析Redis数据结构 (缓存深度)

admin6个月前 (05-10)数码27

Labs导读

(RemoteDictionaryServer)远程字典服务,是一款经过Key-Value存储的NoSql数据库,数据缓存在内存中,支持网络、可耐久化日志,提供多种言语的API,罕用的场景有高速缓存、散布式数据共享、散布式锁、限流和信息队列等。通常名目研发中,联合springframework封装的RedisTemplateAPI经常使用。

Part01、环境搭建

●操作系统:7

●集成环境:CLion

●编译环境:GCC9

深化了解缓存的神奇世界

●代码版本:redis-6.2.6

1.1环境装置

操作系统和集成环境的可自行装置。由于Centos7自动gcc版本较低,因此须要更新GCC版本,经过如下命令可成功编译环境的更新:

#装置centos-release-scl%yum-yinstallcentos-release-scl#装置devtoolsetGGC9%yum-yinstalldevtoolset-9-gccdevtoolset-9-gcc-c++devtoolset-9-binutils#激活对应的devtoolset%echosource/opt/rh/devtoolset-9/enable>>/etc/profile#检查版本%gcc-v

1.2编译和运转

从官网网站下载源码,解压,编译和运转。

%wget启动Redis%cdsrc%./redis-server#验证%cdsrc%./redis-cli

图片

经常使用Clion建设C工程,并导入源代码,确保GCC9是对应的编译环境,以调试形式启动redis-server模块,经常使用redis-cli客户端衔接服务端,设置断点,键入相应的命令启动调试。

图片

Part02、数据库的组织结构

首先从微观层面了解数据库的结构及组织相关。redisDB,dict,dictht,dictEntry,

redisObject等相关数据库结构定义在server.h,dict.h,sds.h和zipList.h等头文件中。

//server.htypedefstructredisDb{dict*dict;/*ThekeyspaceforthisDB*/dict*expires;/*Timeoutofkeyswithatimeoutset*/dict*blocking_keys;/*Keyswithclientswtingfor/>图片

经过上图,可以了解到如下内容:

(1)RedisDB可有多个,经过redis.conf中的databases参数启动性能,自动是16个;

(2)每个RedisDB有两个"dictht"哈希表组成,区分是ht[0]和ht[1],这样做的目标是为了rehash,重要处置扩容和缩容的疑问,经过ht[0]和ht[1]相互搬迁数据成功rehash上班,而且每次命令只搬迁一个索引上方的数据,缩小系统操作期间,防止因数据量过大而影响性能;其实如今dict.c的dictRehash函数中。

(3)HASH表中存储的每个元素是dictEntry结构组成的链表。经过链式,处置两个key的哈希值正好落在同一个哈希桶中的哈希抵触疑问。

intdictRehash(dict*d,intn){intempty_visits=n*10;/*Maxnumberofemptybucketstovisit.*/if(!dictIsRehashing(d))return0;while(n--&&d->ht[0].used!=0){dictEntry*de,*nextde;/*Notethatrehashidxcan'toverflowaswearesuretherearemore*elementsbecauseht[0].used!=0*/assert(d->ht[0].size>(unsignedlong)d->rehashidx);while(d->ht[0].table[d->rehashidx]==NULL){d->rehashidx++;if(--empty_visits==0)return1;}/*在HASH桶中找到非空的索引后,开局链表的数据移动上班*/de=d->ht[0].table[d->rehashidx];/*MoveallthekeysinthisbucketfromtheoldtothenewhashHT*/while(de){uint64_th;nextde=de->next;/*在新的hash表中找到对应键值的索引*/h=dictHashKey(d,de->key)&d->ht[1].sizemask;/*把要参与的数据放在新的hash表对应索引链表的开局*/de->next=d->ht[1].table[h];d->ht[1].table[h]=de;/*更新计数器*/d->ht[0].used--;d->ht[1].used++;/*链表中的下一个Node*/de=nextde;}/*因数据已成功移动,因此清空老的hash表对应的桶*/d->ht[0].table[d->rehashidx]=NULL;/*指向下一个桶*/d->rehashidx++;}/*假设曾经rehashed了一切的表,监禁HT[0]的表空间,将HT[1]设置为以后的表,重置HT[1]*/if(d->ht[0].used==0){zfree(d->ht[0].table);d->ht[0]=d->ht[1];_dictReset(&d->ht[1]);d->rehashidx=-1;return0;}/*Moretorehash...*/return1;}

(4)dictEntry中的"key"由sds(便捷灵活字符串)结构组成。redis依据数据的长度,定义了不同类型的sds结构。例如:sdshdr8,sdshdr16,sdshdr32,sdshdr64;这样的结构定义,既节俭了空间,也处置了二进制安保(例如C言语的‘’)缓和冲区溢出(经过alloc-len可计算残余空间)等疑问。

//SDS.Hstruct__attribute__((__packed__))sdshdr8{uint8_tlen;/*used*/uint8_talloc;/*excludingtheheaderandnullterminator*/unsignedcharflags;/*3lsboftype,5unusedbits*/charbuf[];};struct__attribute__((__packed__))sdshdr16{uint16_tlen;/*used*/uint16_talloc;/*excludingtheheaderandnullterminator*/unsignedcharflags;/*3lsboftype,5unusedbits*/charbuf[];};

(5)redis有STRING,LIST,SET,ZSET,HASH,MODULE,STREAM七种数据类型;有sds,quicklist,ziplist,dict,zskiplist,stream七种底层数据结构;每种数据类型依据存储数据的大小,多少等,区分由不同的底层数据结构成功。例如list数据类型,由quicklist,ziplist区分成功;HASH数据类型,由dict,ziplist区分成功。

(6)dictEntry中的"*val"指向redisObject"结构,此结构中redisObject->type存储的是数据类型;redisObject->encoding存储的是底层的数据结构类型;redisObject->ptr存储详细的数据;相应的实如今object.c中。

//object.crobj*createQuicklistObject(void){quicklist*l=quicklistCreate();robj*o=createObject(OBJ_LIST,l);o->encoding=OBJ_ENCODING_QUICKLIST;returno;}robj*createZiplistObject(void){unsignedchar*zl=ziplistNew();robj*o=createObject(OBJ_LIST,zl);o->encoding=OBJ_ENCODING_ZIPLIST;returno;}robj*createSetObject(void){dict*d=dictCreate(&setDictType,NULL);robj*o=createObject(OBJ_SET,d);o->encoding=OBJ_ENCODING_HT;returno;}robj*createIntsetObject(void){intset*is=intsetNew();robj*o=createObject(OBJ_SET,is);o->encoding=OBJ_ENCODING_INTSET;returno;}robj*createHashObject(void){unsignedchar*zl=ziplistNew();robj*o=createObject(OBJ_HASH,zl);o->encoding=OBJ_ENCODING_ZIPLIST;returno;}

Part03、源码调试

3.1入口

正如一切的C代码一样,入口是service.c中的main函数。

图片

3.2redis命令入口

一切的redis命令定义在redisCommandTable数组中,类型为"redisCommand",经过函数指针的形式调用。例如下图中的Get和Set命令。

图片

图片

Part04、总结

以上区分从环境搭建,数据库的结构组织相关和源码调试启动了引见,假设你对redis源代码感兴味,执行起来吧!


redis常用数据结构介绍和业务应用场景分析

redis内置了很多常用数据结构,了解这些数据结构的功能和应用场景能够让我们在需求开发时灵活运用来解决实际问题。 String是redis中最基础的数据结构,你可以把它用作缓存最基础的kv(key-value)类型的缓存(value最大为512MB),只需要把需要缓存的对象进行string的编解码即可。 另外String也可以保存数值类型的数据,就可以来实现计数功能(redi提供了incr等原子操作) 常见应用场景 List列表更多的时候是把它当成队列使用(最大2^32 - 1个元素),使用入队出队功能,如果来使用它作为各种列表的话,很多时候不具备防重功能在使用的时候不是很方便。 常见应用场景 Set是一种无序不重复的集合,添加删除检查是否存在都是O(1)的时间复杂度。 常见应用场景 hash是一个map结构,可以像存储对象的多个字段一样存储一个key的多类数据。 常见应用场景 redis中的pub/sub可以实现广播功能,类似rocketmq中的broadcast 常见应用场景 除了上述最基本的数据结构外,redis还提供了一些其他的数据结构,有的是需要安装相关redis stack来使用的。 bitmap本质上还是使用的string字符串,不过可以通过bit来进行操作,把这个key的value值想象成bit组成的数组。 常见应用场景 bloomfilter(也叫布隆过滤器)可以理解成一种特殊的set集合,它可以用来判断一个值是否在这个集合中,不过不同于普通的set,它的判断存在一定误判的可能(假阳性),如果bloomfilter判断一个值不在这个集合中,那么一定不在,但是如果判断在,那么有可能不在。 常见应用场景 hyperloglog是一种概率性的去重计数数据结构,可以实现一定精度的去重计数 常见应用场景 geohash可以实现距离计算、距离查询等地理位置相关的功能 常见应用场景

redis缓存原理

1、Redis是一种内存高速cache,如果使用redis缓存,那经常被访问的内容会被缓存在内存中,需要使用的时候直接从内存调取,不知道比硬盘调取快了多少倍,并且支持复杂的数据结构,应用于许多高并发的场景中。 2、Redis支持主从同步。 数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。 这使得Redis可执行单层树复制。 存盘可以有意无意的对数据进行写操作。 由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。 同步对读取操作的可扩展性和数据冗余很有帮助。 zset是set的一个升级版本,他在set的基础上增加了一个顺序属性,这一属性在添加修改元素的时候可以指定,每次指定后,zset会自动重新按新的值调整顺序。 可以理解了有两列的mysql表,一列存value,一列存顺序。 操作中key理解为zset的名字。 更多关于redis缓存原理,进入:查看更多内容

免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。

标签: Redis

“深化了解缓存的神奇世界-浅析Redis数据结构 (缓存深度)” 的相关文章

Redis中分布式锁的防死锁机制 (redis中文网)

Redis中分布式锁的防死锁机制 (redis中文网)

分布式锁在分布式系统中是一种常见的需求。它用于防止对共享资源的并发访问,确保数据一致性和可靠性。在 Redis 中实现分布式锁可以通过使用 SETNX(SET if Not eXists)命令来尝...

排查与处置指南-Redis大Key危害 (排查与处置指的是什么)

排查与处置指南-Redis大Key危害 (排查与处置指的是什么)

这是一位同窗往年秋招参与得物一面遇到的疑问,完整面经如下: 这个疑问在面试中还是比拟容易遇到的,尤其是在调查性能优化相关常识点的时刻。 通常状况下,问了bigkey(大Key)还会继续...

Redis-使用哈希槽而非一致性哈希的原因 (redis淘汰策略有哪些)

Redis-使用哈希槽而非一致性哈希的原因 (redis淘汰策略有哪些)

引言 在分布式系统中,数据分片和负载均衡是至关重要的。哈希槽和一致性哈希两种方法都可以实现这些目标,但它们各有优缺点。本文将讨论为什么在某些情况下使用哈希槽而不是一致性哈希。 哈希槽 哈希...

上古程序猿推戴经常使用Redis的执著理由 (上古教程)

上古程序猿推戴经常使用Redis的执著理由 (上古教程)

最近,在知乎上看到这样一个疑问: 有些上古程序猿不时保持推戴经常使用怎样办? 终究用不用Redis?为什么用?怎样用?让咱们看看网友怎样说…… @灵剑...

成功多规则限流的思索与通常-Redis (成功的规则)

成功多规则限流的思索与通常-Redis (成功的规则)

市面上很多引见如何成功限流的,然而大局部都有一个缺陷,就是只能成功繁多的限流,比如1分钟访问1次或许60分钟访问10次这种,然而假构想一个接口两种规则都须要满足呢,咱们的名目又是散布式名目,应该如何处...

Redis-全面了解数据耐久性和复原机制-深度解析-耐久化 (redis淘汰策略有哪些)

Redis-全面了解数据耐久性和复原机制-深度解析-耐久化 (redis淘汰策略有哪些)

我们都知道在关于的开发或许面试的环节中,很容易就会遇到这个关于Redis耐久化的疑问,而我们在面试的时刻,经常会有小同伴只能说出这个Redis耐久化的两种形式,后续或许还会对比一些区别,然而关于怎...

解锁你的海量数据摸索之旅-Redis-全文搜查-的弱小新配置 (解锁海量任务)

解锁你的海量数据摸索之旅-Redis-全文搜查-的弱小新配置 (解锁海量任务)

在2021年我就了解到earch这个名目,并曾经把它用于我的开源名目newbee-mall-pro中。 就我的经常使用体验来说,便捷场景下,用来平替Elasticsearch的经常使用场景曾...

Redis内存治理与淘汰战略 (redis内存淘汰策略配置)

Redis内存治理与淘汰战略 (redis内存淘汰策略配置)

欢迎到来写代码那些事!在的环球里,内存治理是一门关键的艺术。本教程将带你深化了解Redis内存淘汰战略,教你如何在数据存储和性能之间找到最佳平衡点。 目录: 1.内存淘汰...