Redis-初体验/数据结构

孤街浪徒 提交于 2020-07-28 03:48:01

定义:

Redis 是 C 语言开发的一个开源的(遵从 BSD 协议)高性能键值对(key-value)的内存数据库,可以用作数据库、缓存、消息中间件等。它是一种 NoSQL(not-only sql,泛指非关系型数据库)的数据库。

特点:

性能优秀,数据在内存中,读写速度非常快,支持并发 10W QPS。单进程单线程,是线程安全的,采用 IO 多路复用机制。丰富的数据类型,支持字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。支持数据持久化。可以将内存中数据保存在磁盘中,重启时加载。主从复制,哨兵,高可用。可以用作分布式锁。可以作为消息中间件使用,支持发布订阅

Redis内部内存对象管理 !

redis内存管理

Redis 内部使用一个 redisObject 对象来表示所有的 key 和 value,结构如下

typedef struct redisObject{
//对象的数据类型(String/Hash/List/Set/Zset)
unsigned type:4;
//表示redisObject对象的底层编码实现,主要有简单动态字符串,链表,字典,跳跃表,整数集合以及压缩列表,
unsigned encoding:4;
//指向底层数据结构的指针
void *ptr;
//引用计数器,初始值为1,被引用一次+1,反之则-1,为0则释放空间,可以用OBJECT REFCOUNT查看引用情况
int refCount;
//最后一次访问该对象的时间,可以通过Object idletime查看当前时间距离该键的lru的时间
unsigned lru:
}

在redisObject内部,type 表示一个 value 对象的具体数据类型(例如,type=string,则表示存储的是string类型的对象),encoding 是不同数据类型在 Redis 内部的存储方式

  • String

String是Reids的基本数据类型,value可以存储任何类型的数据,比如 jpg 图片或者序列化的对象。String 类型的单键的value最大能存储 512M. 常用命令,set/get

字符串对象的值底层都是由简单动态字符串实现的

一个 简单动态字符串(SDS) 示例如下:

数据结构如下:

struct sdshdr{
//记录buf数组中已使用字节的长度
int len;
//记录buf数组中剩余空间的长度
int free;
//字节数组,用于存储字符串
char buf[];
};

在SDS拼接发生以后,如果此时的len小于1MB则它会多分配和len大小相同的未使用空间,用free表示,如果大于1MB,则会分配1MB的为使用空间

应用场景:

1.缓存: 经典使用场景,把常用信息,字符串,图片或者视频等信息放到redis中,redis作为缓存层,mysql做持久化层,降低mysql的读写压力。

2.计数器:redis是单线程模型,一个命令执行完才会执行下一个,同时数据可以一步落地到其他的数据源。

3.session:常见方案spring session + redis实现session共享,

  • Hash

Hash是一个键值(key-value)的集合

当哈希对象保存的键值对数量小于 512,并且所有键值对的长度都小于 64 字节时,使用压缩列表存储;否则使用 hashtable 存储

使用压缩列表的时候,图示如下:

压缩列表(ziplist)的结构体

struct ziplist<T> {

    int32 zlbytes; // 整个压缩列表占用字节数

    int32 zltail_offset; // 最后一个元素距离压缩列表起始位置的偏移量,用于快速定位到最后一个节点

    int16 zllength; // 元素个数

    T[] entries; // 元素内容列表,挨个挨个紧凑存储

    int8 zlend; // 标志压缩列表的结束,值恒为 0xFF

}

图示如下:

节点entry结构体:

struct entry {

    int<var> prevlen; // 前一个 entry 的字节长度

    int<var> encoding; // 元素类型编码

    optional byte[] content; // 元素内容

}

图示如下:

Hashtable 对应的示意图如下:

应用场景:

缓存: 能直观,相比string更节省空间,的维护缓存信息,如用户信息,视频信息等。

常用命令:hget,hset,hgetall 等。

  • List

列表是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边),当列表的长度小于 512,并且所有元素的长度都小于 64 字节时,使用压缩列表(Hash中有描述)存储;否则使用 linkedlist 存储。

应用场景:List 应用场景非常多,也是 Redis 最重要的数据结构之一,比如 关注列表,粉丝列表等/可以用来当消息队列用

链表对应的示意图如下:

常用命令:lpush、rpush、lpop、rpop、lrange(获取列表片段)等。

  • Set

Set是String 类型的无序集合。集合是通过 hashtable 实现的。Set 中的元素是没有顺序的,而且是没有重复的

intset(整数集合)主要是为节省内存而设计的内存结构,它的优点就是节省内存,但缺点就是比其他结构要消耗更多的时间,所以 Redis 在数据量小的时候使用整数集合存储。

当集合的长度小于 512,并且所有元素都是整数时,使用整数集合存储;否则使用 hashtable 存储。

intset结构如下

typedef struct intset{
//编码方式
uint32_t encoding;
//元素数量
uint32_t length;
//存储元素的数组
int8_t contents[];
}

intset 编码 使用 Intset(数组) 作为底层实现。(以此来保证集合内唯一的元素) 图示如下:

hashtable结构如下:

typedef struct dictht{
//哈希表数组
dictEntry **table;
//哈希表大小
unsigned long size;
//哈希表掩码,总是等于size-1,存储时计算索引值
unsigned long sizemask;
//已有元素数量
unsigned long used;
}


使用字典实现,字典的每个键都是一个字符串对象(包含了一个集合元素)(以此来保证集合内唯一的元素) 图示如下:

应用场景:

1.标签(tag),给用户添加标签,或者用户给消息添加标签,这样有同一标签或者类似标签的可以给推荐关注的事或者关注的人。

2.点赞,或点踩,收藏等,可以放到set中实现

常用命令:sdd、spop、smembers、sunion 等。

  • Zset ①

是 String 类型元素的集合 有序 有压缩列表ziplist和跳跃链表skiplist

有序集合和集合有着必然的联系,保留了集合不能有重复成员的特性,区别是,有序集合中的元素是可以排序的,它给每个元素设置一个分数,作为排序的依据。

(有序集合中的元素不可以重复,但是score 分数 可以重复,就和一个班里的同学学号不能重复,但考试成绩可以相同)

跳跃表的结构如下:

typedef struct zskiplist{
//跳跃表的头结点
zskiplistNode header;
//尾节点
zskiplistNode tail;
//跳跃表中层数最大的节点的层数(不包括头结点)
unsigned long level;
//跳跃表长度(不包括头节点)
unsigned int length;

节点结构:

typedef struct zskiplistNode{
//后退指针
struct zskiplistNode *backward;
//分值
double score;
//成员对象
robj *obj;
//层
struct zskiplistLevel{
//前进指针
struct zskiplistNode *forward;
//跨度
unsigned int span;
}level[];
};

图示如下:

应用场景:

排行榜:有序集合经典使用场景。例如小说视频等网站需要对用户上传的小说视频做排行榜,榜单可以按照用户关注数,更新时间,字数等打分,做排行。

常用命令:zadd、zrange、zrem、zcard 等。

注: ①详解见链接:https://zsr.github.io/2017/07/03/redis-zset%E5%86%85%E9%83%A8%E5%AE%9E%E7%8E%B0/

本文参考: 1,Redis 学习笔记(篇五):对象(RedisObject)https://www.cnblogs.com/wind-snow/p/11172832.html

2,搞懂这些Redis知识点,吊打面试官!https://baijiahao.baidu.com/s?id=1660009541007805174&wfr=spider&for=pc

3,redis的五种基本数据类型及其内部实现 https://blog.csdn.net/jackFXX/article/details/82318080?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!