分布式缓存设计之Redis底层数据结构和缓存原理(二)

Redis数据类型和应用场景

  • redis是一个key-value的存储系统,key是字符串,常见的value类型分为:
    • String字符串类型
    • List列表类型:双向链表,模拟栈和队列使用
    • Set集合类型
    • SortedSet(Zset)有序集合类型:有序特性的使用
    • Hash类型
  • 不常见的类型:
    • BitMap位图类型:0和1组成,多用于表示状态
    • geo地理位置类型: 利用Z阶曲线,Base32编码和geohash算法
    • Stream类型: 可用为消息队列

Redis的key的设计

用:分割,表名做前缀,第二个字段放id,第三个字段放列名

// user表的id为1的name字端
列如: user:1:name

string字符串类型

命令名称样例命令描述
setset age 20赋值
getget age取值
getsetgetset age 33取值并赋值
setnxset age 20 nx当value不存在时赋值;set age 33 nx px 3000 原子操作
appendappend name 01向尾部追加
strlenstrlen key获取字符串长度
incrincr key递增数字
incrbyincrby key increment增加指定的数
decrdecr key递增数字
decrbydecrby key decrement递增指定的数

incr等命令递增递减数字,常配合watch实现乐观锁,之后的文章中会扩展。

list列表类型

双向链表的数据结构,从头部或尾部获取数据是极快的;

  • 作为栈或队列使用
  • 存储各种列表使用
命令含义
lpush从左侧插入列表
lpop从左侧弹出
rpush从右侧插入列表
rpop从右侧弹出
lrange返回指定区间的元素
…………

set集合类型

无序,元素唯一,常见于随机抽奖

命令含义
sadd新增
srem删除
smembers获取集合中的所有元素
scard获取集合中元素的数量
sunion并集
sinter交集
sdiff差集
…………

zset有序集合类型

有序且不重复,每个元素关联一个score,常见于排行榜等功能

命令含义
zadd新增
zrem删除
zrank按分值从小到大获取排名
zcard获取集合中元素的数量
…………

hash散列表

常用于对象的存储,表数据的映射

命令含义
hset新增,不区别新增和修改
hmset批量赋值
hget取值
hexists查看某个字段是否存在
hincrby指定字段自增
…………

bitmap位图

用0和1占位,表示状态,应用场景:

  • 用户每月签到
  • 统计活跃用户
  • 查询用户在线状态

geo地理位置

用于处理位置信息,使用z阶曲线,base32算法,geohash算法

  • 记录地理位置
  • 计算距离
  • 查找附近的人

steam数据流类型

几乎满足了消息队列具备的全部内容

  • 消息id序列化生成
  • 消息遍历
  • 消息阻塞和非阻塞读取
  • 消息分组消费
  • 未完成的消息处理
  • 消息队列监控

底层数据结构

  1. RedisObject结构
    redis的value是一个对象,包含字符串对象,列表对象,哈希对象,集合对象和有序集合对象。结构信息概览:
typedef struct redisObject{
	unsigned type :4; // 类型,5种对象类型
	unsigned encoding:4;  //编码,不同对象有不同编码,提高灵活性和效率
	void *ptr; //指向底层实现的数据结构的指针,即真正value的存放地址
	// ....
	int refcount; //引用计数
	unsigned lru:LRU_BITS; // 最后一次被命令访问的时间,共24位,高16位存最近访问时间,低8位存最近访问次数
}
  1. 字符串对象
    redis使用SDS(simple dynamic string)存储字符串和整型数据,其结构如下:
struct sdshdr{
	int len;  //记录buf数组中已使用的字节数量
	int free; // 数组中未使用的字节数量
	char buf[]; // 字符串数组,用于保存字符串,并切以\0结束
}

buf的长度=len+free+1
SDS的优势:

  • 获取长度复杂度位O(1);
  • 记录了长度,内存分配时更简单,杜绝缓冲区溢出
  • 可以存储二进制数据
    主要应用场景:字符串和整型数据存储,存储key,AOF缓冲区和用户输入缓冲区
  1. 跳跃表
    跳跃表是有序集合的底层实现,效率高,实现简单,其基本思想是:将有序链表中的部分节点分层抽取,每一层都是一个有序链表。类似二叉树和二分法的实现,利用空间换时间的策略,提高查询效率。查找层级如下(sorted-set)
1	        5	        9	null
1     3     5	  7	    9	null
1  2  3  4  5  6  7  8  9
  1. 字典
    字典dict又称为散列表(hash),用来存储键值对的数据结构。其底层使用数组存储,当hash冲突时,采用链表存储,查找冲突数据时遍历比较,数组下标=hash(key)%数组容量,初始容量位4,扩容(rehash)阈值为0.75,扩容大小为当前容量的2倍。
  2. 压缩列表
    压缩列表是连续内存块组成的顺序数据结构,比如list采用双向链表和压缩列表结合的方式存储,sorted-set和hash在元素个数少的情况下且是整数或短字符串时使用其存储。
  3. 快速列表
    底层采用双向链表和压缩列表结合实现

缓存淘汰策略

  1. 不设置maxmemory的场景
    redis为了保证数据的完整性,不能淘汰,当达到物理内存后,内存与硬盘虚拟内存频繁io,性能急剧下降。
  2. 设置maxmemory
    当内存达到最大内存的3/4后,采用内存淘汰策略,删除内存中的对象。设置LRU和LFU等方式主动删除,也会存在key被删除后,缓存穿透,DB压力剧增的问题,所以两种方式综合考虑,合理选用。一般使用默认方式,不设置最大值,redis做主从,cluster方式扩大有效内存,启动时xml一次性加入到redis中。
  3. 删除策略
    分为定时删除,惰性删除,主动删除三种。目前采用的方式是惰性删除和主动删除两种方式:
  • 定时删除:创建定时器,当过期时间来临时,立即执行删除
  • 惰性删除:当key被访问时,发现已经过期就会删除它(默认)
  • 主动删除
    • 默认不删除,即不设置maxmemory
    • LRU 最近最少使用原则
    • LFU 最不经常使用
    • Random 随机
    • TTL 挑选要过期的数据进行删除
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值