共计 4749 个字符,预计需要花费 12 分钟才能阅读完成。
一、9 种数据类型
概述
咱们先通过一张图理解下 Redis 外部内存治理中是如何形容这些不同数据类型的:
首先 Redis 外部应用一个 redisObject 对象来示意所有的 key 和 value,redisObject 最次要的信息如上图所示:type 代表一个 value 对象具体是何种数据类型,encoding 是不同数据类型在 redis 外部的存储形式。
redis 反对丰盛的数据类型,不同的场景应用适合的数据类型能够无效的优化内存数据的寄存空间:
- string:最根本的数据类型,二进制平安的字符串,最大 512M。
- list:依照增加程序放弃程序的字符串列表。
- set:无序的字符串汇合,不存在反复的元素。
- sorted set:已排序的字符串汇合。
- hash:key-value 对的一种汇合。
- bitmap:更细化的一种操作,以 bit 为单位。
- hyperloglog:基于概率的数据结构。# 2.8.9 新增
- Geo: 地理位置信息储存起来,并对这些信息进行操作 # 3.2 新增
- 流(Stream)# 5.0 新增
String 字符串
常用命令:
setnx,set,get,decr,incr,mget 等。
利用场景:
字符串是最罕用的数据类型,他可能存储任何类型的字符串,当然也包含二进制、JSON 化的对象、甚至是 Base64 编码之后的图片。在 Redis 中一个字符串最大的容量为 512MB,能够说是无所不能了。redis 的 key 和 string 类型 value 限度均为 512MB。
- 缓存,热点数据
- 分布式 session
- 分布式锁
- INCR 计数器
- 文章的浏览量,微博点赞数,容许肯定的提早,先写入 Redis 再定时同步到数据库
-
全局 ID
INT 类型,INCRBY,利用原子性
- INCR 限流
以访问者的 IP 和其余信息作为 key,拜访一次减少一次计数,超过次数则返回 false。 -
setbit 位操作
外部编码:
- int:8 个字节的长整型(long,2^63-1)
- embstr:小于等于 44 个字节的字符串,embstr 格局的 SDS(Simple Dynamic String)
- raw:SDS 大于 44 个字节的字符串
redis 为什么要本人写一个 SDS 的数据类型,次要是为了解决 C 语言 char[] 的四个问题
- 字符数组必须先给指标变量调配足够的空间,否则可能会溢出
- 查问字符数组长度 工夫复杂度 O(n)
- 长度变动,须要从新分配内存
- 通过从字符串开始到结尾碰到的第一个 \0 来标记字符串的完结,因而不能保留图片、音频、视频、压缩文件等二进制 (bytes) 保留的内容,二进制不平安
redis SDS
- 不必放心内存溢出问题,如果须要会对 SDS 进行扩容
- 因为定义了 len 属性,查问数组长度工夫复杂度 O(1) 固定长度
- 空间预调配,惰性空间开释
- 依据长度 len 来判断是完结,而不是 \0
Hash 哈希表
常用命令:
hget,hsetnx,hset,hvals,hgetall,hmset,hmget 等。
利用场景:
咱们简略举个实例来形容下 Hash 的利用场景,比方咱们要存储一个用户信息对象数据,蕴含以下信息:用户 ID 为查找的 key,存储的 value 用户对象蕴含姓名,年龄,生日等
外部编码:
- ziplist(压缩列表):当哈希类型中元素个数小于 hash-max-ziplist-entries 配置(默认 512 个),同时所有值都小于 hash-max-ziplist-value 配置(默认 64 字节)时,Redis 会应用 ziplist 作为哈希的外部实现。
- hashtable(哈希表):当上述条件不满足时,Redis 则会采纳 hashtable 作为哈希的外部实现。
List 列表
常用命令:
lpush,rpush,lpop,rpop,lrange 等。
列表(list)用来存储多个有序的字符串,每个字符串称为元素;一个列表能够存储 2^32- 1 个元素。Redis 中的列表反对两端插入和弹出,并能够取得指定地位(或范畴)的元素,能够充当数组、队列、栈等
利用场景
比方 twitter 的关注列表,粉丝列表等都能够用 Redis 的 list 构造来实现,能够利用 lrange 命令,做基于 Redis 的分页性能,性能极佳,用户体验好。
音讯队列
列表类型能够应用 rpush 实现先进先出的性能,同时又能够应用 lpop 轻松的弹出(查问并删除)第一个元素,所以列表类型能够用来实现音讯队列
发红包的场景
在发红包的场景中,假如发一个 10 元,10 个红包,须要保障抢红包的人不会多抢到,也不会少抢到.
上面咱们通过下图来看一下 Redis 中列表类型的插入和弹出操作:
上面咱们看一下 Redis 中列表类型的获取与删除操作:
Redis 列表类型的特点如下:
- 列表中所有的元素都是有序的,所以它们是能够通过索引获取的 lindex 命令。并且在 Redis 中列表类型的索引是从 0 开始的。
- 列表中的元素是能够反复的,也就是说在 Redis 列表类型中,能够保留同名元素
外部编码:
- ziplist(压缩列表):当列表中元素个数小于 512(默认)个,并且列表中每个元素的值都小于 64(默认)个字节时,Redis 会抉择用 ziplist 来作为列表的外部实现以缩小内存的应用。当然上述默认值也能够通过相干参数批改:list-max-ziplist-entried(元素个数)、list-max-ziplist-value(元素值)。
- linkedlist(链表):当列表类型无奈满足 ziplist 条件时,Redis 会抉择用 linkedlist 作为列表的外部实现。
Set 汇合
常用命令:
sadd,spop,smembers,sunion,scard,sscan,sismember 等。
利用场景:
Redis set 对外提供的性能与 list 相似是一个列表的性能,非凡之处在于 set 是能够主动排重的,当你须要存储一个列表数据,又不心愿呈现反复数据时,set 是一个很好的抉择,并且 set 提供了判断某个成员是否在一个 set 汇合内的重要接口,这个也是 list 所不能提供的。
1. 知乎点赞数
2. 存储社交关系
用户 (编号 user001) 关注
sadd focus:user001 user003
sadd focus:user002 user003 user004
互相关注
sadd focus:user001 user002
sadd focus:user002 user001
实现形式:
set 的外部实现是一个 value 永远为 null 的 HashMap,理论就是通过计算 hash 的形式来疾速排重的,这也是 set 能提供判断一个成员是否在汇合内的起因。
Redis 中的汇合类型,也就是 set。在 Redis 中 set 也是能够保留多个字符串的,常常有人会分不清 list 与 set,上面咱们重点介绍一下它们之间的不同:
set 中的元素是不能够反复的,而 list 是能够保留反复元素的。set 中的元素是无序的,而 list 中的元素是有序的。set 中的元素不能通过索引下标获取元素,而 list 中的元素则能够通过索引下标获取元素。除此之外
set 还反对更高级的性能,例如多个 set 取交加、并集、差集等
外部编码
- intset(整数汇合):当汇合中的元素都是整数,并且汇合中的元素个数小于 512 个时,Redis 会选用 intset 作为底层外部实现。
- hashtable(哈希表):当上述条件不满足时,Redis 会采纳 hashtable 作为底层实现。
备注:咱们能够通过 set-max-intset-entries 参数来设置上述中的默认参数。
Sorted set 有序汇合
常用命令:
zadd,zrange,zrem,zcard,zscore,zcount,zlexcount 等
上面先看一下列表、汇合、有序汇合三种数据类型之间的区别:
外部编码:
- ziplist(压缩列表):当有序汇合的元素个数小于 128 个(默认设置),同时每个元素的值都小于 64 字节(默认设置),Redis 会采纳 ziplist 作为有序汇合的外部实现。
- skiplist(跳跃表):当上述条件不满足时,Redis 会采纳 skiplist 作为外部编码。
备注:上述中的默认值,也能够通过以下参数设置:zset-max-ziplist-entries 和 zset-max-ziplist-value。
利用场景
Redis sorted set 的应用场景与 set 相似,区别是 set 不是主动有序的,而 sorted set 能够通过用户额定提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即主动排序。当你须要一个有序的并且不反复的汇合列表,那么能够抉择 sorted set 数据结构,比方 twitter 的 public timeline 能够以发表工夫作为 score 来存储,这样获取时就是主动按工夫排好序的。点击数做出排行榜。
1. 商品的评估标签,能够记录商品的标签,统计标签次数,减少标签次数,按标签的分值进行排序
BitMap 位图
在利用场景中,有一些数据只有两个属性,比方是否是学生,是否是党员等等,对于这些数据,最节约内存的形式就是用 bit 去记录,以是否是学生为例,1 代表是学生,0 代表不是学生。那么 1000110 就代表 7 集体中 3 个是学生,这就是 BitMaps 的存储需要。Bitmaps 是一个能够对位进行操作的字符串,咱们能够把 Bitmaps 设想成是一串二进制数字,每个地位只存储 0 和 1。下标是 Bitmaps 的偏移量。BitMap 就是通过一个 bit 位来示意某个元素对应的值或者状态, 其中的 key 就是对应元素自身,实际上底层也是通过对字符串的操作来实现。Redis 从 2.2.0 版本开始新增了 setbit,getbit,bitcount 等几个 bitmap 相干命令。尽管是新命令,然而并没有新增新的数据类型,因为 setbit 等命令只不过是在 set 上的扩大。
应用场景
1. 用户签到
很多网站都提供了签到性能(这里不思考数据落地事宜),并且须要展现最近一个月的签到状况
2. 统计沉闷用户
应用工夫作为 cacheKey,而后用户 ID 为 offset,如果当日沉闷过就设置为 1
那么我该如果计算某几天 / 月 / 年的沉闷用户呢 (暂且约定,统计工夫内只有有一天在线就称为沉闷),有请下一个 redis 的命令
命令 BITOP operation destkey key [key …]
阐明:对一个或多个保留二进制位的字符串 key 进行位元操作,并将后果保留到 destkey 上。
阐明:BITOP 命令反对 AND、OR、NOT、XOR 这四种操作中的任意一种参数
3. 用户在线状态
前段时间开发一个我的项目,对方给我提供了一个查问以后用户是否在线的接口。不理解对方是怎么做的,本人思考了一下,应用 bitmap 是一个节约空间效率又高的一种办法,只须要一个 key,而后用户 ID 为 offset,如果在线就设置为 1,不在线就设置为 0,和下面的场景一样,5000W 用户只须要 6MB 的空间。
外部编码
这个就是 Redis 实现的 BloomFilter,BloomFilter 非常简单,如下图所示,假如曾经有 3 个元素 a、b 和 c,别离通过 3 个 hash 算法 h1()、h2()和 h2()计算而后对一个 bit 进行赋值,接下来假如须要判断 d 是否曾经存在,那么也须要应用 3 个 hash 算法 h1()、h2()和 h2()对 d 进行计算,而后失去 3 个 bit 的值,恰好这 3 个 bit 的值为 1,这就可能阐明:d 可能存在汇合中。再判断 e,因为 h1(e)算进去的 bit 之前的值是 0,那么阐明:e 肯定不存在汇合中:
须要阐明的是,bitmap 并不是一种实在的数据结构,它实质上是 String 数据结构,只不过操作的粒度变成了位,即 bit。因为 String 类型最大长度为 512MB,所以 bitmap 最多能够存储 2^32 个 bit。
HyperLogLog 基数统计、Geo 地理位置、Streams 流(5.5 引入)
这三种不罕用,后续再讲