redis八种基本数据类型及其应用
文章目录
1.简介
Redis是一个开源的,内存中的数据结构存储系统,它可以用做数据库,缓存和消息中间件。
支持多种类型的数据结构
- 字符串 strings
- 散列 hashes
- 列表 lists
- 集合 sets
- 有序集合 sorted sets
- bitmaps
- hyperloglogs
- 地理空间 geospatial 索引半径查询
支持每秒10w次查询请求
2.安装redis
设置alias方便操作
ls |grep redis #找到redis的安装路径
alias rcli='/usr/bin/redis-cli' #设置别名
#使用别名登录
rcli
- 1
- 2
- 3
- 4
3.基本命令
推荐网站 http://redisdoc.com/
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h82HM4Tu-1579594343657)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120110919117.png)]](https://i-blog.csdnimg.cn/blog_migrate/db68e1c980a70bdad1aa8a23d62810df.png)
3.1SET命令
网站上已经介绍的很清楚了,本文就不赘述了,我们直接看效果。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dRrAAhTJ-1579594343659)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120111238082.png)]](https://i-blog.csdnimg.cn/blog_migrate/ba06772223ce3ff7db9cd81b1141279c.png)
这有个小问题 (error) NOAUTH Authentication required. 提示没有认证。我们需要输入密码即可
AUTH password。
- set qingshan 666 设置key=qingshan value=666
- get qingshan 获取key=qingshan的value值
那么我们一般 set 的数据在redis中是什么类型?
type qingshan - > string
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o1vKR6yZ-1579594343659)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120111949262.png)]](https://i-blog.csdnimg.cn/blog_migrate/5bc657cccde6f6f0bee20cdfa0e2cdd6.png)
4.基本数据类型
官网数据类型介绍地址 https://redis.io/topics/data-types-intro
官网有 8 种,前面 5 种为常用数据结构
- string 二进制安全的字符串
- Lists: 按插入顺序排序的字符串元素的集合。他们基本上就是链表(linked lists)。
- Sets: 不重复且无序的字符串元素的集合。
- Sorted sets,类似Sets,但是每个字符串元素都关联到一个叫score浮动数值(floating number value)。里面的元素总是通过score进行着排序,所以不同的是,它是可以检索的一系列元素。(例如你可能会问:给我前面10个或者后面10个元素)。
- Hashes,由field和关联的value组成的map。field和value都是字符串的。这和Ruby、Python的hashes很像。
- Bit arrays (或者说 simply bitmaps): 通过特殊的命令,你可以将 String 值当作一系列 bits 处理:可以设置和清除单独的 bits,数出所有设为 1 的 bits 的数量,找到最前的被设为 1 或 0 的 bit,等等。
- HyperLogLogs: 这是被用于估计一个 set 中元素数量的概率性的数据结构。
- Streams:5.0版本新增, append-only collections of map-like entries that provide an abstract log data type.
- 可以用来做持久化的消息队列
4.1 String 字符串
存储原理
假设存储 key = hello vlaue = word
set hello word
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vkaWlhrs-1579594343660)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120115354305.png)]](https://i-blog.csdnimg.cn/blog_migrate/08c3a0e74f03df09df7edffcba7836f9.png)
String的三种编码
- int,存储8个字节的长整型(long,2^63-1)
- embstr,embstr格式的SDS(Simple Dynamic String)
- raw,SDS,存储大于44个字节的字符串
redis 为什么要自己写一个SDS的数据类型
主要是为了解决C语言 char[] 的四个问题
- 字符数组必须先给目标变量分配足够的空间,否则可能会溢出
- 查询字符数组长度 时间复杂度O(n)
- 长度变化,需要重新分配内存
- 通过从字符串开始到结尾碰到的第一个
\0来标记字符串的结束,因此不能保存图片、音频、视频、压缩文件等二进制(bytes)保存的内容,二进制不安全
redis SDS
- 不用担心内存溢出问题,如果需要会对 SDS 进行扩容
- 因为定义了 len 属性,查询数组长度时间复杂度O(1) 固定长度
- 空间预分配,惰性空间释放
- 根据长度
len来判断是结束,而不是\0
embstr和raw
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-98KQgtzI-1579594343660)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120144602150.png)]](https://i-blog.csdnimg.cn/blog_migrate/fd59e61a2a2168bad162c85b6dfc3285.png)
- 当 value 的值为整型时,编码为 int
- 当 value 值为字符时,存储的编码为 embstr,连续的内存空间,只需要分配一次
- 当 value 值字符长度超过 44 时,存储的编码为 raw,不是连续的内存空间,需要分配两次
- 如果 value 的值为 int 或者 embstr ,然后通过 append 添加字符的时候,也会转化为 raw 类型(因为 embstr 设计的是只读的,如果发生变化只能再开辟一块空间),而且这个过程是不可逆的。
应用场景
- 缓存,热点数据
- 分布式session
- set key value NX EX 分布式锁
- INCR计数器
- 文章的阅读量,微博点赞数,允许一定的延迟,先写入 Redis 再定时同步到数据库
- 全局ID
- INT 类型,INCRBY,利用原子性
- INCR 限流
- 以访问者的 IP 和其他信息作为 key,访问一次增加一次计数,超过次数则返回 false。
- setbit 位操作
4.2 Hash 哈希
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P08IOaaL-1579594343661)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120162911742.png)]](https://i-blog.csdnimg.cn/blog_migrate/1d08e0d4c8cbab4af163e878c4745c21.png)
对于这种类似于数据库表的结构,redis中可以使用hash进行存储
批量设置
hmset coder:xwf age 30 addr wuhan tag java
- 1
批量获取
hmget coder:xwf age addr tag
- 1
执行效果:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HV3H4be0-1579594343661)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120163552719.png)]](https://i-blog.csdnimg.cn/blog_migrate/e79c7bd0b5e15fa7c9e58346f8fa21b2.png)
**同样是存储字符串,Hash 与 String 的主要区别? **
1、把所有相关的值聚集到一个 key 中,节省内存空间
2、只使用一个 key,减少 key 冲突
3、当需要批量获取值的时候,只需要使用一个命令,减少内存/IO/CPU 的消耗
Hash 不适合的场景:
1、Field 不能单独设置过期时间
2、没有 bit 操作
3、需要考虑数据量分布的问题(value 值非常大的时候,无法分布到多个节点)
hash表有两种存储的数据编码
如果Field的个数超过 512 个 或者 Field 中任意一个 键或者值 的长度大于 64个字节,hash表会用ht来存储
redis配置文件
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
- 1
- 2
ziplist 压缩列表
ziplist 是一个经过特殊编码的双向链表,它不存储指向上一个链表节点和指向下一 个链表节点的指针,而是存储上一个节点长度和当前节点长度,通过牺牲部分读写性能, 来换取高效的内存空间利用率,是一种时间换空间的思想。只用在字段个数少,字段值小的场景里面
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3mS2sFKm-1579594343661)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120165318390.png)]](https://i-blog.csdnimg.cn/blog_migrate/38dd921dcdfcd85abb06343f236b345c.png)
ht(hashtable) 哈希表
在 Redis 中,hashtable 被称为字典(dictionary),它是一个数组+链表的结构。
为什么有 ht[0] 和 ht[1] 两个hash表,是为了扩容。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DFDCxy29-1579594343662)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120192718161.png)]](https://i-blog.csdnimg.cn/blog_migrate/7b1a2a588f056ae223ebab06b2d9827e.png)
应用场景
购物车
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l3qoFn7w-1579594343662)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120184047773.png)]](https://i-blog.csdnimg.cn/blog_migrate/f619782d098ecfd865c065c4ed1f7b8b.png)
| 存储 | 命令 |
|---|---|
| 用户id | key |
| 商品id | field1 |
| 商品数量 | value1 |
| 商品价格 | field2 |
| 商品价格值 | value2 |
| 操作 | 命令 |
|---|---|
| 商品+1 | hincr |
| 商品-1 | hdecr |
| 删除 | hdel |
| 全选 | hgetall |
| 商品数量 | hlen |
4.3 List 列表
有序,左边是列表头,从左到右
存储有序的字符串(从左到右),元素可以重复。可以充当队列和栈的角色。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O5aYoeT2-1579594343663)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120190102111.png)]](https://i-blog.csdnimg.cn/blog_migrate/fe9c97a7859a87535ab13f4cd892e55f.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v9JoHrOm-1579594343663)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200121160924862.png)]](https://i-blog.csdnimg.cn/blog_migrate/b933333112c706f9356126b416136e49.png)
127.0.0.1:6379> lpush queue a
(integer) 1
127.0.0.1:6379> lpush queue b c
(integer) 3
127.0.0.1:6379> lrange queue 0 -1
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> rpush queue d e
(integer) 5
127.0.0.1:6379> lrange queue 0 -1
1) "c"
2) "b"
3) "a"
4) "d"
5) "e"
127.0.0.1:6379> lpop queue
"c"
127.0.0.1:6379> lrange queue 0 -1
1) "b"
2) "a"
3) "d"
4) "e"
127.0.0.1:6379> rpop queue
"e"
127.0.0.1:6379> lrange queue 0 -1
1) "b"
2) "a"
3) "d"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
List 存储原理(quicklist)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KaH2a3M6-1579594343664)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120185909116.png)]](https://i-blog.csdnimg.cn/blog_migrate/1778e0bb85e325e4262debdbd6c6543c.png)
内部是一个双向链表,*zl 指针指向的是 ziplist 压缩列表,数据真正还是存储在 ziplist 中。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TChTwnro-1579594343664)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120191151179.png)]](https://i-blog.csdnimg.cn/blog_migrate/a08be83534909aa78e941ba01587ce15.png)
应用场景
- 时间线
- 队列
- 栈
4.4 Set 集合
一个 set 集合可以存储 2^63-1 个元素
127.0.0.1:6379> sadd xwfset 123 a b c d e f g 456
(integer) 9
127.0.0.1:6379> smembers xwfset
1) "e"
2) "f"
3) "b"
4) "d"
5) "g"
6) "123"
7) "a"
8) "c"
9) "456"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
存储结构
- intset
- hashtable
127.0.0.1:6379> object encoding xwfset
"hashtable"
127.0.0.1:6379> sadd intsets 1 2 3
(integer) 3
127.0.0.1:6379> object encoding intsets
"intset"
- 1
- 2
- 3
- 4
- 5
- 6
应用场景
1.知乎点赞数

2.京东的商品筛选
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7UWFCFsm-1579594343665)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120194833288.png)]](https://i-blog.csdnimg.cn/blog_migrate/399ffd0ca374f4089ffa8a077c38a51f.png)
127.0.0.1:6379> sadd brand:apple iPhone11
(integer) 1
127.0.0.1:6379> sadd brand:ios iPhone11
(integer) 1
127.0.0.1:6379> sadd screensize:6.0-6.24 iPhone11
(integer) 1
127.0.0.1:6379> sadd memorysize:256GB iPhone11
(integer) 1
127.0.0.1:6379> sinter brand:apple brand:ios screensize:6.0-6.24 memorysize:256GB
1) "iPhone11"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
筛选商品,苹果,IOS,屏幕6.0-6.24,内存大小256G
sinter brand:apple brand:ios screensize:6.0-6.24 memorysize:256GB
3.微博关注
用户(编号user001)关注
sadd focus:user001 user003
sadd focus:user002 user003 user004
相互关注
sadd focus:user001 user002
sadd focus:user002 user001
#判断用户2是否关注了用户1
127.0.0.1:6379> SISMEMBER focus:user002 user001
(integer) 1
- 1
- 2
- 3
我关注得到人也关注了他(共同关注)
#获取关注的交集
127.0.0.1:6379> sinter focus:user001 focus:user002
1) "user003"
- 1
- 2
- 3
可能认识的人
#将所有的人存放到allusers集合
127.0.0.1:6379> SUNIONSTORE alluser:user001 focus:user001 focus:user002
(integer) 4
127.0.0.1:6379> SDIFF alluser:user001 focus:user001
1) "user004"
2) "user001"
#剔除掉自己
127.0.0.1:6379> SREM alluser:user001 user001
(integer) 1
127.0.0.1:6379> SDIFF alluser:user001 focus:user001
1) "user004"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
4.5 ZSet 有序集合
每个元素有一个对应的分数,基于分数进行排序;如果分数相等,以key值的 ascii 值进行排序。
数据结构对比
| 数据结构 | 是否允许重复元素 | 是否有序 | 有序实现方式 |
|---|---|---|---|
| list | 是 | 是 | 索引下标 |
| set | 否 | 否 | 无 |
| zset | 否 | 是 | 分值score |
存储结构
-
ziplist
-
skiplist+dict 跳表+字典
redis配置文件
如果元素的个数超过 128 个 或者 元素中任意一个 value 的大小超过 64个字节,存储会采用 skiplist 跳表
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
- 1
- 2
什么是 skiplist ?
上面的是普通的链表,下面的是跳表,level 是随机的
普通链表查找一个元素的时间复杂度为O(n)
跳表的时间复杂度为O(m*log2n)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dPDRBP4F-1579594343666)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200121103942711.png)]](https://i-blog.csdnimg.cn/blog_migrate/bc12edf86b11290641b08125f944eb27.png)
假设我们找元素19
1.先从起始的 level3 指针中查找 26 大于 19
2.退回到起始的 level2 的指针,大于7 继续往后,找到19
3.通过三次就找到了19
简书的一篇文章:redis用到的非常高效的数据结构–跳表
应用场景
1.商品的评价标签,可以记录商品的标签,统计标签次数,增加标签次数,按标签的分值进行排序
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-97TPeJgR-1579594343666)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120195514557.png)]](https://i-blog.csdnimg.cn/blog_migrate/d94ac73175d8a1a086fbaa5f1e1d8d8e.png)
#添加商品(编号i5001)的标签tag和对应标签的评价次数
127.0.0.1:6379> zadd good_tag:i5001 442 tag1 265 tag2 264 tag3
(integer) 3
#不带分数
127.0.0.1:6379> zrange good_tag:i5001 0 -1
1) "tag3"
2) "tag2"
3) "tag1"
#带分数
127.0.0.1:6379> zrange good_tag:i5001 0 -1 withscores
1) "tag3"
2) "264"
3) "tag2"
4) "265"
5) "tag1"
6) "442"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
2.百度搜索热点
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pJv8D7rq-1579594343667)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200120202817364.png)]](https://i-blog.csdnimg.cn/blog_migrate/ce5d84e554c87074b678eafc3bf09724.png)
#维护2020年1月21号的热点新闻
127.0.0.1:6379> zadd hotspot:20200121 520 pot1 263 pot2 244 pot3
(integer) 3
127.0.0.1:6379> zrange hotspot:20200121 0 -1 withscores
1) "pot3"
2) "244"
3) "pot2"
4) "263"
5) "pot1"
6) "520"
#增加点击次数
127.0.0.1:6379> ZINCRBY hotspot 1 pot1
"521"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
4.6 BitMaps
Bitmaps 是在字符串类型上面定义的位操作。一个字节由 8 个二进制位组成。
应用场景:
用户访问统计
在线用户统计
4.7 Hyperloglogs
Hyperloglogs:提供了一种不太准确的基数统计方法,比如统计网站的 UV,存在一定的误差。
4.8 Streams
5.0 推出的数据类型。支持多播的可持久化的消息队列,用于实现发布订阅功能,借鉴了 kafka 的设计。
5.总结
数据结构
| 对象 | 对象type属性值 | type命令输出 | object encoding |
|---|---|---|---|
| 字符串 | OBJ_STRING | “string” | int/embstr/raw |
| 列表 | OBJ_LIST | “list” | quicklist |
| 哈希 | OBJ_HASH | “hash” | ziplist/hashtable |
| 集合 | OBJ_SET | “set” | intset/hashtable |
| 有序集合 | OBJ_ZSET | “zset” | ziplist/skiplist |
编码转换
| 对象 | 元素编码 | 升级编码 | 再次升级 |
|---|---|---|---|
| 字符串 | INT 整数并且小于 log 2^63-1 | embstr 超过44字节被修改 | raw |
| 哈希 | ziplist 键和值的长度小于64字节,键值对个数不超过521个 | hashtable | |
| 列表 | quicklist | ||
| 集合 | intset 元素都是整数,元素个数小于512 | hashtable | |
| 有序集合 | ziplist 任何一个member长度小于64字节,元素个数不超过128个 | skiplist |
6.参考
咕泡学院 青山老师 redis-基础篇(原版更加具体,对照redis的源码进行讲解)
转载自:https://blog.youkuaiyun.com/xiewenfeng520/article/details/104063062
本文详细介绍了Redis中的八种基本数据类型,包括字符串、哈希、列表、集合、有序集合、位图、HyperLogLogs和Stream,以及它们的存储原理、应用场景和编码转换。适合理解Redis数据结构并应用于实际项目中。
1032

被折叠的 条评论
为什么被折叠?



