redis各种数据结构详解(redis5种数据结构)
mhr18 2024-10-28 16:17 19 浏览 0 评论
redis数据结构
redis全名(Remote Dictionary Server),即远程字典服务
redis的值的数据结构类型有String、List、Set、Hash、zset(sorted set,有序集合)、Bitmaps(位图)、HyperLogLogs
注意:我使用的版本是6.0.10,不同版本可能略有差别
redis中key的最大长度为512M
对象
typedef struct redisObject {
// 对象的类型
unsigned type:4;
// 编码
unsigned encoding:4;
// 记录最后一次被访问的时间
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
// 引用计数 * and most significant 16 bits access time). */
int refcount;
// 指向底层实现的指针
void *ptr;
} robj;
类型总览
redis中的数据类型,即为redisObject的type属性
// string
#define OBJ_STRING 0 /* String object. */
// list
#define OBJ_LIST 1 /* List object. */
// set
#define OBJ_SET 2 /* Set object. */
//zset
#define OBJ_ZSET 3 /* Sorted set object. */
//hash
#define OBJ_HASH 4 /* Hash object. */
// module
#define OBJ_MODULE 5 /* Module object. */
// stream
#define OBJ_STREAM 6 /* Stream object. */
#可以使用type命令来查看该键所对应值的类型
type key
redis的编码分类
对应于redisObject的ecoding属性,encoding是决定对象底层实现数据结构的
// 简单动态字符串 raw
#define OBJ_ENCODING_RAW 0 /* Raw representation */
// long类型的整数 int
#define OBJ_ENCODING_INT 1 /* Encoded as integer */
// 哈希表 hashtable
#define OBJ_ENCODING_HT 2 /* Encoded as hash table */
// 压缩 不再使用
#define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
// 双向链表 不再使用该结构
#define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */
// 压缩列表 ziplist
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
// 整数集合 intset
#define OBJ_ENCODING_INTSET 6 /* Encoded as intset */
// 跳表 skiplist
#define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
// embstr编码的简单动态字符串 embstr
#define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
// 快表 quicklist
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
// 流 stream
#define OBJ_ENCODING_STREAM 10 /* Encoded as a radix tree of listpacks */
可以使用命令
object encoding key
来查看该key使用的是哪种编码
127.0.0.1:6379> set test_int 1
OK
127.0.0.1:6379> object encoding test_int
"int"
127.0.0.1:6379> set test_raw zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
OK
127.0.0.1:6379> strlen test_raw
(integer) 44
127.0.0.1:6379> object encoding test_raw
"embstr"
127.0.0.1:6379> set test_raw zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
OK
127.0.0.1:6379> object encoding test_raw
"raw"
127.0.0.1:6379> strlen test_raw
(integer) 45
String类型
string类型属于单值单value,是一个可变的字节数组,就像StringBuilder似的,可以追加、获取长度、截取等操作
扩容:当字符串长度小于1M时,扩容是现有空间进行加倍;当字符串长度超过1M,扩容只会多扩1M的空间。且字符串最长为512M
源码结构
struct __attribute__ ((__packed__)) sdshdr5 {
// 存储了字符串的类型和长度,3位存类型,5位存长度
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used */
uint32_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
// 字符串长度
uint64_t len; /* used */
// 内存分配
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
// 字节数组
char buf[];
};
编码格式
| 编码 | 对象 | | ------------------- | ---------------------------------------------- | | OBJENCODINGINT | 使用整数值实现的字符串对象 | | OBJENCODINGEMBSTR | 使用embstr编码的简单动态字符串实现的字符串对象 | | OBJENCODINGRAW | 使用简单动态字符串实现的字符串对象 |
string有三种编码格式
int 整数值
embstr 用于存储短字符串的编码方式,字符串长度小于44字节使用,数据保存在一块连续的内存里
raw 字符串值长度大于44字节使用
embstr和raw两种编码的区别
embstr编码用于保存短字符串,与raw编码一样,都是使用redisObject结构和sdshdr结构来表示字符串对象,但是raw编码会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构,而embstr编码则通过调用一次内存分配函数来分配一块连续的内存空间,空间中依次包含redisObject和sdshdr两个结构
操作命令
值拼接
#给key对应的value进行拼接,返回的是拼接之后的字符长度
append k1 qwe
(integer) 5
值长度
strlen k1
数字运算操作
#加一
INCR k2
#减一
DECR k2
#加3
INCRBY k2 3
#减2
DECRBY k2 2
注意:这几个命令只能对数字进行操作,范围是Long.MIN~Long.MAX
获取值
get k1
#只获取该key所对应value的部分字符
getrange k1 0 2
设置值
# setrange覆盖部分值 其中0为从下标为0的字符开始替换
setrange k1 0 zx
(integer) 5
#设置值时设置过期时间
#setex key seconds value
setex k3 20 b
#如果key不存在设置值,防止覆盖(set if not exists)
#setnx key value
setnx k1 1
# 设置key的值,并返回key的旧值
getset k1 vv1
多值操作
#同时set多个键值
#mset key value [key value ...]
mset k4 v4 k5 v5
#同时获取多个键的值
#mget key [key ...]
mget k4 k5
#同时set多个键值(全部不存在时才会设置值)
#msetnx key value [key value ...]
msetnx k6 v6 k7 k8
List类型
List属于单值多value,链表用的是双向链表结构
list支持pop、push来操作头部和尾部,既可以用做栈也可以用做队列
源码结构
typedef struct listNode {
// 前驱节点
struct listNode *prev;
// 后继节点
struct listNode *next;
// 值
void *value;
} listNode;
typedef struct list {
// 头节点
listNode *head;
// 尾结点
listNode *tail;
// 节点值复制函数
void *(*dup)(void *ptr);
// 节点值释放函数
void (*free)(void *ptr);
// 节点值对比函数
int (*match)(void *ptr, void *key);
// 链表中包含的节点数量
unsigned long len;
} list;
这个结构不知道还用不用,因为看源码来说在创建list的时候创建的是quicklist
quicklist结构
typedef struct quicklist {
quicklistNode *head;
quicklistNode *tail;
unsigned long count; /* total count of all entries in all ziplists */
unsigned long len; /* number of quicklistNodes */
int fill : QL_FILL_BITS; /* fill factor for individual nodes */
unsigned int compress : QL_COMP_BITS; /* depth of end nodes not to compress;0=off */
unsigned int bookmark_count: QL_BM_BITS;
quicklistBookmark bookmarks[];
} quicklist;
typedef struct quicklistNode {
struct quicklistNode *prev;
struct quicklistNode *next;
unsigned char *zl;
unsigned int sz; /* ziplist size in bytes */
unsigned int count : 16; /* count of items in ziplist */
unsigned int encoding : 2; /* RAW==1 or LZF==2 */
unsigned int container : 2; /* NONE==1 or ZIPLIST==2 */
unsigned int recompress : 1; /* was this node previous compressed? */
unsigned int attempted_compress : 1; /* node can't compress; too small */
unsigned int extra : 10; /* more bits to steal for future usage */
} quicklistNode;
而对于quicklist编码的定义是
OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
看代码像是存到quicklist中,然后又使用ziplist压缩的,毕竟不是专业的c语言开发,看的并不是那么明白
操作命令
设置值
#lpush(指从左边进 左进右出 就想是栈一样)
#lpush key element [element ...]
lpush list1 1 2 3 4 5
#取值
#lrange key start end (负下标表示的是从后往前,如-1表示倒数第一)
lrange list1 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
#rpush(指从右边进 右进左出 就想是栈一样)
#rpush key element [element ...]
rpush list2 1 2 3 4 5
#给某个索引位置赋值
#lset key index element
lset list1 0 q
#在某个元素之前或之后插入一个元素
#linsert key before|after pivot element
linsert list1 before q zz
取值
#弹出栈顶元素(从左边开始弹出,弹出之后,list中就不存在该元素了)
#lpop key
lpop list1
#弹出栈顶元素(从右边开始弹出,弹出之后,list中就不存在该元素了)
#rpop key
rpop list1
#按照索引位置取值
#lindex key index
lindex list1 0
列表长度
llen list1
删除值
#删除几个某个元素
#lrem key count element
lrem list1 1 2
#截取指定范围的值赋给key(范围是索引)
#ltrim key start stop
ltrim list1 0 0
# 从头部删除元素 出栈
lpop list1
# 从尾部删除元素
rpop list1
出栈入栈
#从源列表右出栈压入左目标列表
#rpoplpush source dest
rpoplpush list2 list1
Set类型
set类型是单值多value,与List的区别在于不可重复,类似于HashSet,通过hash table实现的
set除了基本的增删改查操作之外,还可以使用集合来取并集、交集、差集,可以用来实现好友推荐等功能
编码格式
| 编码 | 对象 | | ------------------- | -------------------------- | | OBJENCODINGINTSET | 使用整数集合实现的集合对象 | | OBJENCODINGHT | 使用的hash table |
set有两种编码格式
intset 保存的元素全都是整数,且元素数量不超过512hash table 保存的不是整数
#根据该配置项来进行编码转换的
set-max-intset-entries 512
操作命令
设置值
#设置值
#sadd key member [member ...]
sadd set1 vv vc vb vv
取值
#取值
#smembers key
smembers set1
1) "vc"
2) "vb"
3) "vv"
#判断该元素是否在set中
#sismember key member
sismember set1 vv
#获取随机的元素(count表示获取的数量,默认为1)
#srandmember key [count]
srandmember set1 2
查看集合元素个数
#scard key
scard set1
删除
#srem key member
srem set1 vb
#随机出栈(默认数量为1)
#spop key [count]
spop set1
随机抽取
#随机从集合中抽取2个(默认1个)
#srandmember key [count]
srandmember set1 2
#将源集合中的值移至目标集合
#smove source dest member
smove set1 set2 5
差集 交集 并集
#差集 返回的是其他key与第一个key的差集
#sdiff key [key ...]
sdiff set1 set2
#交集
#sinter key [key ...]
sinter set1 set2
#并集
#sunion key [key ...]
sunion set1 set2
Hash类型
value是键值对,相当于HashMap,对于hash碰撞也是采用的HashMap的处理方式,数组+链表
更适合存储对象,将一个对象存储在hash类型中会占用更少的内存,且可以更方便的存取整个对象
编码格式
| 编码 | 对象 | | -------------------- | ---------------- | | OBJENCODINGZIPLIST | 使用ziplist | | OBJENCODINGHT | 使用的hash table |
set有两种编码格式
ziplist 一开始存储使用的ziplist,但是当满足一定条件时会转换为hash tablehash table
#根据该配置项来进行编码转换的
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
源码结构
typedef struct dictht {
// 哈希表数组
dictEntry **table;
// 哈希表大小
unsigned long size;
// 哈希表大小掩码,用于计算索引值
unsigned long sizemask;
// 哈希表已有节点数量
unsigned long used;
} dictht;
typedef struct dictEntry {
// 键
void *key;
// 值
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
// 下一个哈希节点,链表
struct dictEntry *next;
} dictEntry;
typedef struct dict {
// 类型
dictType *type;
// 私有数据
void *privdata;
// 哈希表
// ht[0]:用来存放真是的数据
// ht[1]:用于扩容
dictht ht[2];
//rehash 如果为-1表示没有进行rehash
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
int16_t pauserehash; /* If >0 rehashing is paused (<0 indicates coding error) */
} dict;
redis哈希冲突将新节点添加在链表的表头
操作命令
设置值
#Redis4.0之后可以设置多个值,与hmset功能相同
#hset key field value [field value ...]
hset user id 123
#设置多个字段
#hmset key field value [field value ...]
hmset user name zhangsan age 18
#不存在则设置值
#hsetnx key field value
hsetnx user id 12
获取值
#hget key field
hget user id
#获取多个字段的值
#hmget key field [field ...]
hmget user id name sex age
#可以获取该key所对应的map
#hgetall key
hgetall user
#获取key对应的map有几个字段
#hlen key
hlen user
#判断该key的某个字段是否存在
#hexists key field
hexists user id
#获取该key下所有的字段
#hkeys key
hkeys user
#获取该key下所有的字段值
#hvals key
hvals user
删除字段值
#支持删除多个
#hdel key field [field ...]
hdel user age
数值操作
# 加2
# hincrby key field increment
hincrby user id 2
Zset类型
zset是sorted set,即有序的集合,在set的基础上加了一个score,类似于TreeSet,使用score来进行排序,也可以根据score的范围来获取元素的列表
原本set值为k1 v1 k2 v2,而zset是k1 score1 v1 k2 score2 v2
底层使用的是hash和跳表,hash用来关联value和score,保证value的唯一性,同时通过value可以获取到score。跳表的作用在于给value排序以及根据score的范围来获取元素列表
编码格式
| 编码 | 对象 | | --------------------- | -------------- | | OBJENCODINGZIPLIST | 使用ziplist | | OBJENCODINGSKIPLIST | 使用的skiplist |
zset有两种编码格式
ziplist 满足条件使用ziplist,否则使用skiplistskiplist
#根据该配置项来进行编码转换的
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
操作命令
设置值
#zadd key score member [score member ...]
zadd zset1 1 q 2 w
取值
#WITHSCORES表示查询结果是否带着score
#zrange key start stop [WITHSCORES]
zrange zset1 0 -1
#根据score范围查询
#zrangebyscore key min max [WITHSCORES] [LIMIT offset count]
zrangebyscore zset2 0 1
#根据score的范围来计数
#zcount key min max
zcount zset2 0 10
#根据值来获取下标(根据score从小到大来排的序)
#zrank key member
zrank zset2 d
#根据值来获取下标(根据score从大到小来排的序)
#zrevrank key member
zrevrank zset2 d
#根据值来获取score
#zscore key member
zscore zset2 c
查看集合元素个数
#该key的元素个数
zcard zset2
删除
#zrem key member
zrem zset2 s
# 根据下标区间来删除(根据score从小到大来排的序)
#zremrangebyrank key start stop
zremrangebyrank zset1 5 8
# 根据score区间来删除
# zremrangebyscore key min max
zremrangebyscore zset1 7 10
数值操作
# 如果key中存在该元素,则该元素的score增加increment,否则新增该元素
# zincrby key increment member
zincrby zset1 2 b
Bitmap类型
位图不是一个真实的数据类型,是定义在字符串类型之上的面向位操作的集合。位图的最大优势在于节省空间
设置值
#setbit key offset value
# value只能是0或者1
setbit bittest 10 1
取值
#getbit key offset
# 如果offset超出范围的话返回0
getbit bittest 10
HyperLogLogs类型
暂时没有了解
各个类型的应用
- String: 缓存、限流、计数器、分布式锁、分布式Session
- List: 队列
- Set: 点赞、标签
- Hash: 存储对象
- Zset: 排行榜
相关推荐
- 如何检查 Linux 服务器是物理服务器还是虚拟服务器?
-
在企业级运维、故障排查和性能调优过程中,准确了解服务器的运行环境至关重要。无论是物理机还是虚拟机,都存在各自的优势与限制。在很多场景下,尤其是当你继承一台服务器而不清楚底层硬件细节时,如何快速辨识它是...
- 第四节 Windows 系统 Docker 安装全指南
-
一、Docker在Windows上的运行原理(一)架构限制说明Docker本质上依赖Linux内核特性(如Namespaces、Cgroups等),因此在Windows系统上无法直...
- C++ std:shared_ptr自定义allocator引入内存池
-
当C++项目里做了大量的动态内存分配与释放,可能会导致内存碎片,使系统性能降低。当动态内存分配的开销变得不容忽视时,一种解决办法是一次从操作系统分配一块大的静态内存作为内存池进行手动管理,堆对象内存分...
- Activiti 8.0.0 发布,业务流程管理与工作流系统
-
Activiti8.0.0现已发布。Activiti是一个业务流程管理(BPM)和工作流系统,适用于开发人员和系统管理员。其核心是超快速、稳定的BPMN2流程引擎。Activiti可以...
- MyBatis动态SQL的5种高级玩法,90%的人只用过3种
-
MyBatis动态SQL在日常开发中频繁使用,但大多数开发者仅掌握基础标签。本文将介绍五种高阶技巧,助你解锁更灵活的SQL控制能力。一、智能修剪(Trim标签)应用场景:动态处理字段更新,替代<...
- Springboot数据访问(整合Mybatis Plus)
-
Springboot整合MybatisPlus1、创建数据表2、引入maven依赖mybatis-plus-boot-starter主要引入这个依赖,其他相关的依赖在这里就不写了。3、项目结构目录h...
- 盘点金州勇士在奥克兰13年的13大球星 满满的全是...
-
见证了两个月前勇士与猛龙那个史诗般的系列赛后,甲骨文球馆正式成为了历史。那个大大的红色标志被一个字母一个字母地移除,在周四,一切都成为了过去式。然而这座,别名为“Roaracle”(译注:Roar怒吼...
- Mybatis入门看这一篇就够了(mybatis快速入门)
-
什么是MyBatisMyBatis本是apache的一个开源项目iBatis,2010年这个项目由apachesoftwarefoundation迁移到了googlecode,并且改名为M...
- Springboot数据访问(整合druid数据源)
-
Springboot整合druid数据源基本概念SpringBoot默认的数据源是:2.0之前:org.apache.tomcat.jdbc.pool.DataSource2.0及之后:com.z...
- Linux 中的 "/etc/profile.d" 目录有什么作用 ?
-
什么是/etc/profile.d/目录?/etc/profile.d/目录是Linux系统不可或缺的一部分保留配置脚本。它与/etc/profile文件相关联,这是一个启动脚本,该脚...
- 企业数据库安全管理规范(企业数据库安全管理规范最新版)
-
1.目的为规范数据库系统安全使用活动,降低因使用不当而带来的安全风险,保障数据库系统及相关应用系统的安全,特制定本数据库安全管理规范。2.适用范围本规范中所定义的数据管理内容,特指存放在信息系统数据库...
- Oracle 伪列!这些隐藏用法你都知道吗?
-
在Oracle数据库中,有几位特殊的“成员”——伪列,它们虽然不是表中真实存在的物理列,但却能在数据查询、处理过程中发挥出意想不到的强大作用。今天给大家分享Oracle伪列的使用技巧,无论...
- Oracle 高效处理数据的隐藏神器:临时表妙用
-
各位数据库搬砖人,在Oracle的代码世界里闯荡,处理复杂业务时,是不是总被数据“搅得头大”?今天给大家安利一个超实用的隐藏神器——临时表!当你需要临时存储中间计算结果,又不想污染正式数据表...
- Oracle 数据库查询:多表查询(oracle多表关联查询)
-
一、多表查询基础1.JOIN操作-INNERJOIN:返回两个表中满足连接条件的匹配行,不保留未匹配数据。SELECTa.emp_id,b.dept_nameFROMempl...
- 一文掌握怎么利用Shell+Python实现多数据源的异地备份程序
-
简介:在信息化时代,数据安全和业务连续性已成为企业和个人用户关注的焦点。无论是网站数据、数据库、日志文件,还是用户上传的文档、图片等,数据一旦丢失,损失难以估量。尤其是当数据分布在多个不同的目录、服务...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- 如何检查 Linux 服务器是物理服务器还是虚拟服务器?
- 第四节 Windows 系统 Docker 安装全指南
- C++ std:shared_ptr自定义allocator引入内存池
- Activiti 8.0.0 发布,业务流程管理与工作流系统
- MyBatis动态SQL的5种高级玩法,90%的人只用过3种
- Springboot数据访问(整合Mybatis Plus)
- 盘点金州勇士在奥克兰13年的13大球星 满满的全是...
- Mybatis入门看这一篇就够了(mybatis快速入门)
- Springboot数据访问(整合druid数据源)
- Linux 中的 "/etc/profile.d" 目录有什么作用 ?
- 标签列表
-
- oracle位图索引 (74)
- oracle基目录 (50)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (53)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)