百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

redis专题系列1_数据结构底层设计

cac55 2024-10-07 06:38 17 浏览 0 评论

redis数据结构解析

redis安装

1. 下载redis的安装包(直接去官网下一个就行)

2. tar -zxvf 解压

3. cd 到解压后的目录

4. 执行make 完成编译

可能会遇到的错误

- 需要安装tcl (yum -y install tcl 、 yum -y install gcc)

- error: jemalloc/jemalloc.h: No such file or directory 说关于分配器allocator, 如果有MALLOC 这个 环境变量, 会有用这个环境变量的 去建立Redis。 而且libc 并不是默认的 分配器, 默认的是 jemalloc, 因为 jemalloc 被证明 有更少的 fragmentation problems 比libc。 但是如果你又没有jemalloc 而只有 libc 当然 make 出错。 所以加这么一个参数。 解决办法 make MALLOC=libc

5. make test 测试编译状态

6. make install {PREFIX=/path} (示例:make PREFIX=/soft/redis install)

7. 环境变量配置

export REDIS_HOME=/soft/redis

export PATH=$PATH:$REDIS_HOME/bin

redis服务文件相关命令

Redis-server Redis服务器

Redis-cli Redis命令行客户端

Redis-benchmark Redis性能测试工具

Redis-check-aof Aof文件修复工具

Redis-check-dump Rdb文件检查工具

Redis-sentinel Sentinel服务器(2.8以后)

reids对基于key-value存储,数据基础命令

KEYS * 获得当前数据库的所有键

EXISTS key [key ...] 判断键是否存在,返回个数,如果key有一样的也是叠加数

DEL key [key ...] 删除键,返回删除的个数

TYPE key 获取减值的数据类型(string,hash,list,set,zset)

FLUSHALL 清空所有数据库

CONFIG [get、set] redis配置

详解redis数据结构

Redis的五种数据类型:

字符串(String)

存储说明:

字符串类型是redis中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据。你可以用它存储用户的邮箱、json化的对象甚至是图片。一个字符类型键允许存储的最大容量是512M。

数据结构:

在Redis内部,String类型通过int、SDS(simpledynamicstring)作为结构存储,int用来存放整型数据,sds存放字节/字符串和浮点型数据.redis是用C语言写的。可以在redis的源码[sds.h]中看到sds的结构如下:

typedef char *sds;

redis3.2分支引入了五种sdshdr类型,默认是sdshdr8。目的是为了满足不同长度字符串可以使用不同大小的Header,从而节省内存,每次在创建一个sds时根据sds的实际长度判断应该选择什么类型的sdshdr,不同类型的sdshdr占用的内存空间不同。这样细分一下可以省去很多不必要的内存开销。

sdshdr8数据结构如下:

struct __attribute__ ((__packed__)) sdshdr8 { 
 //8表示字符串最大长度是2^8-1 (长度为255)
uint8_t len;//表示当前sds的长度(单位是字节)
uint8_t alloc; //表示已为sds分配的内存大小(单位是字节)
unsigned char flags; //用一个字节表示当前sdshdr的类型,因为有sdshdr有五种类型,所以至少需要3位来表示000:sdshdr5,001:sdshdr8,010:sdshdr16,011:sdshdr32,100:sdshdr64。高5位用不到所以都为0。
char buf[];//sds实际存放的位置};

String的函数说明:

最基本的命令:GET、SET 语法:GET key,SET key value value如果有空格需要双引号以示区分

整数递增:INCR 语法:INCR key 默认值为0,所以首先执行命令得到 1 ,不是整型提示错误

增加指定的整数:INCRBY 语法:INCRBY key increment

整数递减:DECR 语法:DECR key 默认值为0,所以首先执行命令得到 -1,不是整型提示错误

减少指定的整数:DECRBY 语法:DECRBY key increment

增加指定浮点数:INCRBYFLOAT 语法:INCRBYFLOAT key increment

与INCR命令类似,只不过可以递增一个双精度浮点数

向尾部追加值:APPEND 语法:APPEND key value redis客户端并不是输出追加后的字符串,而是输出字符串总长度

获取字符串长度:STRLEN 语法:STRLEN key 如果键不存在返回0,注意如果有中文时,一个中文长度是3,redis是使用UTF-8编码中文的

获取多个键值:MGET 语法:MGET key [key ...] 例如:MGET key1 key2

设置多个键值:MSET 语法:MSET key value [key value ...] 例如:MSET key1 1 key2 "hello redis"

二进制指定位置值:GETBIT 语法:GETBIT key offset 例如:GETBIT key1 2 ,key1为hello 返回 1,返回的值只有0或1,当key不存在或超出实际长度时为0

设置二进制位置值:SETBIT 语法:SETBIT key offset value ,返回该位置的旧值

二进制是1的个数:BITCOUNT 语法:BITCOUNT key [start end] ,start 、end为开始和结束字节

位运算:BITOP 语法:BITOP operation destkey key [key ...] ,operation支持AND、OR、XOR、NOT

偏移:BITPOS 语法:BITPOS key bit [start] [end]

列表(list)

存储说明:

列表类型(list)可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素或者获得列表的某一个片段,value值的列表元素只能是字符串。

数据结构:

redis3.2之后使用的是quicklist实现的列表。其中quicklist是否ziplist的双向列表。

redis查询两端的复杂度是O(1),中间查询复杂度很高。

quicklist 的指针指向quicklistnode,其中quicklistnode就包含了ziplist,

ziplist一个经过特殊处理的双向链表。可以存储多个数据

list的函数说明:

添加左边元素:LPUSH 语法:LPUSH key value [value ...] ,返回添加后的列表元素的总个数

添加右边元素:RPUSH 语法:RPUSH key value [value ...] ,返回添加后的列表元素的总个数

移除左边第一个元素:LPOP 语法:LPOP key ,返回被移除的元素值

移除右边第一个元素:RPOP 语法:RPOP key ,返回被移除的元素值

列表元素个数:LLEN 语法:LLEN key, 不存在时返回0,redis是直接读取现成的值,并不是统计个数

获取列表片段:LRANGE 语法:LRANGE key start stop,如果start比stop靠后时返回空列表,0 -1 返回整个列表

正数时:start 开始索引值,stop结束索引值(索引从0开始)

负数时:例如 lrange num -2 -1,-2表示最右边第二个,-1表示最右边第一个

删除指定值:LREM 语法:LREM key count value,返回被删除的个数

ount>0,从左边开始删除前count个值为value的元素

count<0,从右边开始删除前|count|个值为value的元素

count=0,删除所有值为value的元素

索引元素值:LINDEX 语法:LINDEX key index ,返回索引的元素值,-1表示从最右边的第一位

设置元素值:LSET 语法:LSET key index value

保留列表片段:LTRIM 语法:LTRIM key start stop,start、top 参考lrange命令

一个列表转移另一个列表:RPOPLPUSH 语法:RPOPLPUSH source desctination ,从source列表转移到desctination列表该命令分两步看,首先source列表RPOP右移除,再desctination列表LPUSH

hash类型

存储说明:

value值是一个map结构

数据结构:

map提供两种结构来存储,一种是hashtable、另一种是前面讲的ziplist,数据量小的时候用ziplist. 在redis中,哈希表分为三层,分别是,源码地址【dict.h】

对于hashmap大家可能非常熟悉了,但是redis如何实现,桶位置确认,hash碰撞和rehash的扩容呢。分析redis底层map结构:

1. dictEntry

管理一个key-value,同时保留同一个桶中相邻元素的指针,用来维护哈希桶的内部链;

typedef struct dictEntry {
void *key;
union { //因为value有多种类型,所以value用了union来存储
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;//下一个节点的地址,用来处理碰撞,所有分配到同一索引的元素通过next指针链接起来形成链

2. dictht

这个结构体就是对于桶大小和元素位置的存储

实现一个hash表会使用一个buckets存放dictEntry的地址,一般情况下通过hash(key)%len得到的值就是buckets的索引,这个值决定了我们要将此dictEntry节点放入buckets的哪个索引里,这个buckets实际上就是我们说的hash表。dict.h的dictht结构中table存放的就是buckets的地址

typedef struct dictht {
dictEntry **table;//buckets的地址
unsigned long size;//buckets的大小,总保持为 2^n
unsigned long sizemask;//掩码,用来计算hash值对应的buckets索引
unsigned long used;//当前dictht有多少个dictEntry节点
} dictht;

3. dict

这个结构体用于扩容

dictht实际上就是hash表的核心,但是只有一个dictht还不够,比如rehash、遍历hash等操作,所以redis定义了一个叫dict的结构以支持字典的各种操作,当dictht需要扩容/缩容时,用来管理dictht的迁移

typedef struct dict {
dictType *type;//dictType里存放的是一堆工具函数的函数指针,
void *privdata;//保存type中的某些函数需要作为参数的数据
dictht ht[2];//两个dictht,ht[0]平时用,ht[1] rehash时用
long rehashidx; //当前rehash到buckets的哪个索引,-1时表示非rehash状态
int iterators; //安全迭代器的计数。
}dict;

Hash的函数说明:

设置单个:HSET 语法:HSET key field value,不存在时返回1,存在时返回0,没有更新和插入之分

设置多个:HMSET 语法:HMSET key field value [field value ...]

读取单个:HGET 语法:HGET key field,不存在是返回nil

读取多个:HMGET 语法:HMGET key field [field ...]

读取全部:HGETALL 语法:HGETALL key,返回时字段和字段值的列表

判断字段是否存在:HEXISTS 语法:HEXISTS key field,存在返回1 ,不存在返回0

字段不存在时赋值:HSETNX 语法:HSETNX key field

value,与hset命令不同,hsetnx是键不存在时设置值

增加数字:HINCRBY 语法:HINCRBY key field increment ,返回增加后的数,不是整数时会提示错误

删除字段:HDEL 语法:HDEL key field [field ...] ,返回被删除字段的个数

只获取字段名:HKEYS 语法:HKEYS key ,返回键的所有字段名

只获取字段值:HVALS 语法:HVALS key ,返回键的所有字段值

字段数量:HLEN 语法:HLEN key ,返回字段总数

集合类型(set)

存储说明:

集合类型中,每个元素都是不同的,也就是不能有重复数据,同时集合类型中的数据是无序的。集合类型和列表类型的最大的区别是有序性和唯一性集合类型的常用操作是向集合中加入或删除元素、判断某个元素是否存在。由于集合类型在redis内部是使用的值为空的散列表(hashtable),所以这些操作的时间复杂度都是O(1).

数据结构:

Set在的底层数据结构以intset或者hashtable来存储。当set中只包含整数型的元素时,采用intset来存储,否则,采用hashtable存储,但是对于set来说,该hashtable的value值用于为NULL。通过key来存储元素,hashtable取key的复杂度是O(1)的。

Set的函数说明:

添加元素:SADD 语法:SADD key member [member ...] ,向一个集合添加一个或多个元素,因为集合的唯一性,所以添加相同值时会被忽略。

返回成功添加元素的数量。

删除元素:SREM 语法:SREM key member [member ...] 删除集合中一个或多个元素,返回成功删除的个数。

获取全部元素:SMEMBERS 语法:SMEMBERS key ,返回集合全部元素

值是否存在:SISMEMBER 语法:SISMEMBER key member ,如果存在返回1,不存在返回0

差运算:SDIFF 语法:SDIFF key [key ...] ,例如:集合A和集合B,差集表示A-B,在A里有的元素B里没有,返回差集合;多个集合(A-B)-C

交运算:SINTER 语法:SINTER key [key ...],返回交集集合,每个集合都有的元素

并运算:SUNION 语法:SUNION key [key ...],返回并集集合,所有集合的元素

集合元素个数:SCARD 语法:SCARD key ,返回集合元素个数

弹出元素:SPOP 语法:SPOP key [count] ,因为集合是无序的,所以spop会随机弹出一个元素

有序集合

储存说明:

有序集合类型,顾名思义,和前面讲的集合类型的区别就是多了有序的功能在集合类型的基础上,有序集合类型为集合中的每个元素都关联了一个分数,这使得我们不仅可以完成插入、删除和判断元素是否存在等集合类型支持的操作,还能获得分数最高(或最低)的前N个元素、获得指定分数范围内的元素等与分数有关的操作。虽然集合中每个元素都是不同的,但是他们的分数却可以相同

数据结构:

zset类型的数据结构就比较复杂一点,内部是以ziplist或者skiplist+hashtable来实现,这里面最核心的一个结构就是skiplist,也就是跳跃表,跳跃表是实现有序集合的核心,跳跃表的设计思路和方法本人目前也未融会贯通,后续算法博客补上.

zset的函数说明:

添加集合元素:ZADD 语法:ZADD key [NX|XX] [CH] [INCR] score member [score member ...],不存在添加,存在更新。

获取元素分数:ZSCORE 语法:ZSCORE key member ,返回元素成员的score 分数

元素小到大:ZRANGE 语法:ZRANGE key start top [WITHSCORES] ,参考LRANGE ,加上withscores 返回带元素,即元素,分数

当分数一样时,按元素排序

元素大到小:ZREVRANGE 语法:ZREVRANGE key start [WITHSCORES] ,与zrange区别在于zrevrange是从大到小排序

指定分数范围元素:ZRANGEBYSCORE 语法:ZRANGEBYSCORE key min max [WITHSCORE] [LIMIT offest count]返回从小到大的在min和max之间的元素,(符号表示不包含,例如:80-100,(80 100,withscore返回带分数limit offest count向左偏移offest个元素,并获取前count个元素

指定分数范围元素:ZREVRANGESCORE 语法:ZREVRANGEBYSCORE key max min [WITHSCORE] [LIMIT offest count]与zrangebyscore类似,只不过该命令是从大到小排序的。

增加分数:ZINCRBY 语法:ZINCRBY key increment member ,注意是增加分数,返回增加后的分数;如果成员不存在,则添加一个为0的成员。

更多精品博客请点击下方的了解更多:

相关推荐

MIRIX重塑AI记忆:超Gemini 410%,节省99.9%内存,APP同步上线

MIRIX,一个由UCSD和NYU团队主导的新系统,正在重新定义AI的记忆格局。在过去的十年里,我们见证了大型语言模型席卷全球,从写作助手到代码生成器,无所不能。然而,即使最强大的模型依...

硬盘坏了怎么把数据弄出来对比10种硬盘数据恢复软件

机械硬盘或固态硬盘损坏导致数据丢失时,应立即停止对硬盘的读写操作,并根据损坏类型选择逻辑层恢复工具或专业物理恢复服务。紧急处置措施立即停止通电使用:发现硬盘异响、无法识别或数据异常时,需立即断开连接,...

蓝宝石B850A WIFI主板新玩法:内存小参调节体验

蓝宝石前段时间发布了一款性价比极高的主板:NITRO氮动B850AWIFI主板。这款主板的售价只要1349元,相比普遍1500元以上的B850主板,确实极具竞争力。虽然价格实惠,蓝宝石NITR...

内存卡损坏读不出怎么修复?这5个数据恢复工具汇总,3秒挽回!

在数字化生活的浪潮中,内存卡凭借小巧便携与大容量存储的特性,成为相机、手机、行车记录仪等设备存储数据的得力助手,承载着无数珍贵回忆与重要文件。然而,当内存卡突然损坏无法读取,无论是误删、格式化、病毒入...

内存卡修复不再难,2025年必学的6款软件工具

内存卡出现问题时,通常是因为文件系统损坏、物理损坏或病毒感染。通过专业的修复工具,我们可以尝试恢复数据并修复内存卡。内存卡修复利器:万兴恢复专家万兴恢复专家是一款功能强大的数据恢复软件,支持多种设备和...

有5款内存卡修复工具汇总,内存卡数据轻松找回!

在如今的数字时代,内存卡作为不可或缺的存储介质,广泛应用于相机、手机、行车记录仪等各类设备中,承载着我们珍贵的照片、视频以及重要文件。然而,数据丢失的风险却如影随形,误删、格式化、病毒入侵、硬件故障等...

揭秘:如何通过多种方式精准查询内存条型号及规避风险?

以下是内存条型号查询的常用方法及注意事项,综合了物理查看、软件检测、编码解析等多种方式:一、物理标签查看法1.拆机查看标签打开电脑主机/笔记本后盖找到内存条,观察标签上的型号标识。例如内存标签通常标...

内存卡数据恢复5个工具汇总推荐,轻松找回珍贵记忆!

在这个数字化时代,内存卡作为我们存储珍贵照片、重要文件的常用载体,广泛应用于手机、相机、平板电脑等设备。但数据丢失的意外却常常不期而至,误删除、格式化、病毒攻击,甚至内存卡的物理损坏,都可能让辛苦保存...

电脑内存智能监控清理,优化性能的实用软件

软件介绍Memorycleaner是一款内存清理软件。功能很强,效果很不错。Memorycleaner会在内存用量超出80%时,自动执行“裁剪进程工作集”“清理系统缓存”以及“用全部可能的方法清理...

TechPowerUp MemTest64:内存稳定性测试利器

TechPowerUpMemTest64:内存稳定性测试利器一、软件简介TechPowerUpMemTest64,由知名硬件信息工具GPU-Z的出品公司TechPowerUp发布,是一款专为64位...

微软推出AI恶意软件检测智能体Project Ire,精确度高达98%

IT之家8月6日消息,当地时间周二,微软宣布推出可自主分析恶意软件的AI检测系统原型——ProjectIre。该项目由微软研究院、Defender研究团队及Discovery&a...

农村老木匠常用的20种老工具,手艺人靠它养活一家人,你认识几种

生活中的手艺老匠人是非常受到尊敬和崇拜的,特别是在农村曾经的老匠人都是家里的“座上宾”。对于民间传统的手艺人,有一种说法就是传统的八大匠:木匠、泥匠、篾匠、铁匠、船匠、石匠、油匠和剃头匠。木匠的祖始爷...

恶意木马新变种伪装成聊天工具诱人点击

国家计算机病毒应急处理中心通过对互联网监测发现,近期出现一种恶意木马程序变种Trojan_FakeQQ.CTU。该变种通过伪装成即时聊天工具,诱使计算机用户点击运行。该变种运行后,将其自身复制到受感染...

学习网络安全 这些工具你知道吗?

工欲善其事必先利其器,在新入门网络安全的小伙伴而言。这些工具你必须要有所了解。本文我们简单说说这些网络安全工具吧!Web安全类web类工具主要是通过各种扫描工具,发现web站点存在的各种漏洞...

5分钟盗走你的隐私照片,这个全球性漏洞到底有多可怕?

这个时代,大家对电脑出现漏洞,可能已经习以为常。但如果机哥告诉大家,这个漏洞能够在5分钟内,破解并盗取你所有加密文件,而且还无法通过软件和补丁修复...这可就有点吓人啦。事情是酱婶的。来自荷兰埃因...

取消回复欢迎 发表评论: