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字符串类型
命令名称 | 样例 | 命令描述 |
---|---|---|
set | set age 20 | 赋值 |
get | get age | 取值 |
getset | getset age 33 | 取值并赋值 |
setnx | set age 20 nx | 当value不存在时赋值;set age 33 nx px 3000 原子操作 |
append | append name 01 | 向尾部追加 |
strlen | strlen key | 获取字符串长度 |
incr | incr key | 递增数字 |
incrby | incrby key increment | 增加指定的数 |
decr | decr key | 递增数字 |
decrby | decrby 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序列化生成
- 消息遍历
- 消息阻塞和非阻塞读取
- 消息分组消费
- 未完成的消息处理
- 消息队列监控
底层数据结构
- 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位存最近访问次数
}
- 字符串对象
redis使用SDS(simple dynamic string)存储字符串和整型数据,其结构如下:
struct sdshdr{
int len; //记录buf数组中已使用的字节数量
int free; // 数组中未使用的字节数量
char buf[]; // 字符串数组,用于保存字符串,并切以\0结束
}
buf的长度=len+free+1
SDS的优势:
- 获取长度复杂度位O(1);
- 记录了长度,内存分配时更简单,杜绝缓冲区溢出
- 可以存储二进制数据
主要应用场景:字符串和整型数据存储,存储key,AOF缓冲区和用户输入缓冲区
- 跳跃表
跳跃表是有序集合的底层实现,效率高,实现简单,其基本思想是:将有序链表中的部分节点分层抽取,每一层都是一个有序链表。类似二叉树和二分法的实现,利用空间换时间的策略,提高查询效率。查找层级如下(sorted-set)
1 5 9 null
1 3 5 7 9 null
1 2 3 4 5 6 7 8 9
- 字典
字典dict又称为散列表(hash),用来存储键值对的数据结构。其底层使用数组存储,当hash冲突时,采用链表存储,查找冲突数据时遍历比较,数组下标=hash(key)%数组容量,初始容量位4,扩容(rehash)阈值为0.75,扩容大小为当前容量的2倍。 - 压缩列表
压缩列表是连续内存块组成的顺序数据结构,比如list采用双向链表和压缩列表结合的方式存储,sorted-set和hash在元素个数少的情况下且是整数或短字符串时使用其存储。 - 快速列表
底层采用双向链表和压缩列表结合实现
缓存淘汰策略
- 不设置maxmemory的场景
redis为了保证数据的完整性,不能淘汰,当达到物理内存后,内存与硬盘虚拟内存频繁io,性能急剧下降。 - 设置maxmemory
当内存达到最大内存的3/4后,采用内存淘汰策略,删除内存中的对象。设置LRU和LFU等方式主动删除,也会存在key被删除后,缓存穿透,DB压力剧增的问题,所以两种方式综合考虑,合理选用。一般使用默认方式,不设置最大值,redis做主从,cluster方式扩大有效内存,启动时xml一次性加入到redis中。 - 删除策略
分为定时删除,惰性删除,主动删除三种。目前采用的方式是惰性删除和主动删除两种方式:
- 定时删除:创建定时器,当过期时间来临时,立即执行删除
- 惰性删除:当key被访问时,发现已经过期就会删除它(默认)
- 主动删除
- 默认不删除,即不设置maxmemory
- LRU 最近最少使用原则
- LFU 最不经常使用
- Random 随机
- TTL 挑选要过期的数据进行删除