文章目录
- Redis基础知识
- Redis 概念
- Redis 应用场景
- Redis 数据结构
- String(字符串)
- 存储结构
- 应用场景
- 缓存对象
- 常规计数
- 分布式锁
- List(列表)
- 存储结构
- 补充:ziplist(压缩列表)
- 应用场景
- 消息队列
- Hash(哈希)
- 存储结构
- 补充:hashtable 编码
- 应用场景
- 缓存对象
- 购物车数据
- Set(集合)
- 存储结构
- 应用场景
- 点赞
- 共同关注
- 抽奖活动
- Sorted Set(有序集合)
- 存储结构
- 举例说明
- 补:跳表查询
- 应用场景
- 排行榜
- 电话、姓名排序
- BitMap
- HyperLogLog
- Stream
- Redis 数据结构相关命令操作
- 数据结构注意点
- set与zset区别
- Redis中的watch命令
- 说说Redis中List结构的相关操作
Redis基础知识
Redis 概念
Redis是一种基于键值对的NoSQL数据库,而键值对的值是由多种数据结构和算法组成的。Redis的数据都存储于内存中,因此它的速度惊人,读写性能可达10万/秒,远超关系型数据库。
关系型数据库是基于二维数据表来存储数据的,它的数据格式更为严谨,并支持关系查询。关系型数据库的数据存储于磁盘上,可以存放海量的数据,但性能远不如Redis。
Redis 应用场景
- Redis最常用来做缓存,是实现分布式缓存的首先中间件;
- Redis可以作为数据库,实现诸如点赞、关注、排行等对性能要求极高的互联网需求;
- Redis可以作为计算工具,能用很小的代价,统计诸如PV/UV、用户在线天数等数据;
- Redis还有很多其他的使用场景,例如:可以实现分布式锁,可以作为消息队列使用
Redis 数据结构
- Redis支持5种核心的数据类型,分别是字符串、哈希、列表、集合、有序集合;
- 另外Redis还提供了Bitmap、HyperLogLog、Geo类型,但这些类型都是基于上述核心数据类型实现的;
- Redis在5.0新增加了Streams数据类型,它是一个功能强大的、支持多播的、可持久化的消息队列
注意:这里的数据类型实际描述的是 value 的类型,key 都是 string,常见数据类型(value)有如下类型
- string(embstr、raw、int)
- list(quicklist,由多个 ziplist 双向链表组成)
- hash(ziplist,键值比较少、hashtable键值超过某些阈值或者单个键值比较大)
- set(intset、hashtable)
- sorted set(ziplist、skiplist)
- bitmap
- hyperloglog
每一种类型都用 redisObject 结构体来表示,每种类型根据情况不同,有不同的编码 encoding(即每种结构体的底层数据结构)
下面来详细介绍一下:
String(字符串)
String 是最基本的 key-value 结构,key 是唯一标识,value 是具体的值,value其实不仅是字符串, 也可以是数字(整数或浮点数),value 最多可以容纳的数据长度是 512M
。
存储结构
如果字符串保存的是整数值,则底层编码为 int,实际使用 long (8字节)来存储
如果字符串保存的是非整数值(浮点数字或其它字符)使用的是 SDS(简单动态字符串)来存储,又分两种情况
- 长度 <= 39 字节,使用 embstr 编码来保存,即将 redisObject 和 sdshdr 结构体保存在一起,分配内存只需一次
- 长度 > 39 字节,使用 raw 编码来保存,即 redisObject 结构体分配一次内存,sdshdr 结构体分配一次内存,用指针相连
sdshdr(SDS )称为简单动态字符串,实现上有点类似于 java 中的 StringBuilder,Redis是用C语言实现的,sdshdr 是底层代码定义的一个结构体,它有如下特性
- 可以单独存储字符长度,相比
char*
获取长度效率高(char*
是 C 语言原生字符串表示)- 支持动态扩容,方便字符串拼接操作
- 预留空间,减少内存分配、释放次数(< 1M 时容量是字符串实际长度 2 倍,>= 1M 时容量是原有容量 + 1M)
- 二进制安全,例如传统
char*
以\0
作为结束字符,这样就不能保存视频、图片等二进制数据,而 sds 以长度来进行读取
应用场景
缓存对象
使用 String 来缓存对象有两种方式:
- 直接缓存整个对象的 JSON,命令例子:
SET user:1 '{"name":"xiaolin", "age":18}'
- 采用将 key 进行分离为 user:ID:属性,采用 MSET 存储,用 MGET 获取各属性值,命令例子:
MSET user:1:name laoniu user:1:age 18 user:2:name xiaoqian user:2:age 20
常规计数
因为 Redis 处理命令是单线程,所以执行命令的过程是原子的。因此 String 数据类型适合计数场景,比如计算访问次数、点赞、转发、库存数量等等。
比如计算文章的阅读量:
# 初始化文章的阅读量
> SET aritcle:readcount:1001 0
OK
#阅读量+1
> INCR aritcle:readcount:1001
(integer) 1
#阅读量+1
> INCR aritcle:readcount:1001
(integer) 2
#阅读量+1
> INCR aritcle:readcount:1001
(integer) 3
# 获取对应文章的阅读量
> GET aritcle:readcount:1001
"3"
分布式锁
分布式锁,即分布式系统中的锁。在单体应用中我们通过锁解决的是控制共享资源访问的问题,而分布式锁,就是解决了分布式系统中控制共享资源访问的问题。与单体应用不同的是,分布式系统中竞争共享资源的最小粒度从线程升级成了进程。
我们可以基于reids实现分布式锁,如下:
SET 命令有个 NX 参数可以实现「key不存在才插入」,可以用它来实现分布式锁:
- 如果 key 不存在,则显示插入成功,可以用来表示加锁成功;
- 如果 key 存在,则会显示插入失败,可以用来表示加锁失败。
一般而言,还会对分布式锁加上过期时间,分布式锁的命令如下:
SET lock_key unique_value NX PX 10000
- lock_key 就是 key 键;
- unique_value 是客户端生成的唯一的标识;
- NX 代表只在 lock_key 不存在时,才对 lock_key 进行设置操作;
- PX 10000 表示设置 lock_key 的过期时间为 10s,这是为了避免客户端发生异常而无法释放锁。
而解锁的过程就是将 lock_key 键删除,但不能乱删,要保证执行操作的客户端就是加锁的客户端。所以,解锁的时候,我们要先判断锁的 unique_value 是否为加锁客户端,是的话,才将 lock_key 键删除。
可以看到,解锁是有两个操作,这时就需要 Lua 脚本来保证解锁的原子性,因为 Redis 在执行 Lua 脚本时,可以以原子性的方式执行,保证了锁释放操作的原子性。
// 释放锁时,先比较 unique_value 是否相等,避免锁的误释放
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
这样一来,就通过使用 SET 命令和 Lua 脚本在 Redis 单节点上完成了分布式锁的加锁和解锁。
List(列表)
List 列表是简单的字符串列表,按照插入顺序排序,可以从头部或尾部向 List 列表添加元素。
列表的最大长度为 2^32 - 1
,也即每个列表支持超过 40 亿
个元素。
存储结构
从 Redis 3.2 开始,Redis 采用 quicklist 作为其编码方式,它是一个双向链表,节点元素是 ziplist
quicklist 是大链表 大链表里套了多个小链表(ziplist)
List(列表)特点如下:
- 由于是链表,内存上不连续
- 操作头尾效率高,时间复杂度 O(1)
- 链表中 ziplist 的大小和元素个数都可以设置,其中大小默认 8kb(默认空间可以以后将他们串起来成quicklist )
补充:ziplist(压缩列表)
ziplist 用一块连续的内存存储数据,设计目标是让数据存储更紧凑,减少碎片开销,节约内存,它的结构如下
- zlbytes – 记录整个 ziplist 占用字节数
- zltail-offset – 记录尾节点偏移量:用于快速定位尾结点,倒着遍历
- zllength – 记录节点数量:
- entry – 节点,1 ~ N 个,每个 entry 记录了前一 entry 长度(也是为了倒序遍历 减去字节),本 entry 的编码、长度、实际数据,为了节省内存,根据实际数据长度不同,用于记录长度的字节数也不同,例如前一 entry 长度是 253 时,需要用 1 个字节,但超过了 253,需要用 5 个字节
- zlend – 结束标记
ziplist 适合存储少量元素,否则查询效率不高,并且长度可变的设计会带来连锁更新问题
应用场景
消息队列
Hash(哈希)
Hash 是一个键值对(key - value)集合,其中 value 的形式如: value=[{field1,value1},...{fieldN,valueN}]
。Hash 特别适合用于存储对象。
存储结构
Hash 类型的底层数据结构是由压缩列表或哈希表实现的:
- 如果哈希类型元素个数小于
512
个,所有值小于64
字节的话,Redis 会使用**(ziplist)压缩列表**作为 Hash 类型的底层数据结构; - 如果哈希类型元素不满足上面条件,Redis 会使用hashtable 编码作为 Hash 类型的 底层数据结构。
补充:hashtable 编码
hash 函数,Redis 5.0 采用了 SipHash 算法
采用拉链法解决 key 冲突
rehash 时机
① 当元素数 < 1 * 桶个数时,不扩容
② 当元素数 > 5 * 桶个数时,一定扩容
③ 当 1 * 桶个数 <= 元素数 <= 5 * 桶个数时,如果此时没有进行 AOF 或 RDB 操作时
④ 当元素数 < 桶个数 / 10 时,缩容
rehash 要点
① 每个字典有两个哈希表,桶个数为 ,平时使用 ht[0],ht[1] 开始为 null,扩容时新数组大小为元素个数 * 2
② 渐进式 rehash,即不是一次将所有桶都迁移过去,每次对这张表 CRUD 仅迁移一个桶
③ active rehash,server 的主循环中,每 100 ms 里留出 1s 进行主动迁移
④ rehash 过程中,新增操作 ht[1] ,其它操作先操作 ht[0],若没有,再操作 ht[1]
⑤ redis 所有 CRUD 都是单线程,因此 rehash 一定是线程安全的
应用场景
缓存对象
Hash 类型的 (key,field, value) 的结构与对象的(对象id, 属性, 值)的结构相似,也可以用来存储对象。
我们以用户信息为例,它在关系型数据库中的结构是这样的:
uid | name | age |
1 | Meng | 12 |
2 | Qingqiu | 23 |
我们可以使用如下命令,将用户对象的信息存储到 Hash 类型:
# 存储一个哈希表uid:1的键值
> HMSET uid:1 name Meng age 12
2
# 存储一个哈希表uid:2的键值
> HMSET uid:2 name Qingqiu age 23
2
# 获取哈希表用户id为1中所有的键值
> HGETALL uid:1
1) "name"
2) "Meng"
3) "age"
4) "12"
购物车数据
以用户 id 为 key,商品 id 为 field,商品数量为 value,恰好构成了购物车的3个要素,如下图所示。
涉及的命令如下:
- 添加商品:
HSET cart:{用户id} {商品id} 1
- 添加数量:
HINCRBY cart:{用户id} {商品id} 1
- 商品总数:
HLEN cart:{用户id}
- 删除商品:
HDEL cart:{用户id} {商品id}
- 获取购物车所有商品:
HGETALL cart:{用户id}
当前仅仅是将商品ID存储到了Redis 中,在回显商品具体信息的时候,还需要拿着商品 id 查询一次数据库,获取完整的商品的信息。
Set(集合)
Set 类型是一个无序并唯一的键值集合,它的存储顺序不会按照插入的先后顺序进行存储。
一个集合最多可以存储 2^32-1
个元素。概念和数学中个的集合基本类似,可以交集,并集,差集等等,所以 Set 类型除了支持集合内的增删改查,同时还支持多个集合取交集、并集、差集。
Set 类型和 List 类型的区别如下:
- List 可以存储重复元素,Set 只能存储非重复元素;
- List 是按照元素的先后顺序存储元素的,而 Set 则是无序方式存储元素的。
存储结构
Set 类型的底层数据结构是由整数集合或哈希表实现的:
- 如果集合中的元素都是整数且元素个数小于
512
个,Redis 会使用intset编码作为 Set 类型的底层数据结构; - 如果集合中的元素不满足上面条件,则 Redis 使用hashtable 编码类型的底层数据结构。
应用场景
集合的主要几个特性,无序、不可重复、支持并交差等操作。
因此 Set 类型比较适合用来数据去重和保障数据的唯一性,还可以用来统计多个集合的交集、错集和并集等,当我们存储的数据是无序并且需要去重的情况下,比较适合使用集合类型进行存储。
但是要提醒你一下,这里有一个潜在的风险。Set 的差集、并集和交集的计算复杂度较高,在数据量较大的情况下,如果直接执行这些计算,会导致 Redis 实例阻塞。
在主从集群中,为了避免主库因为 Set 做聚合计算(交集、差集、并集)时导致主库被阻塞,我们可以选择一个从库完成聚合统计,或者把数据返回给客户端,由客户端来完成聚合统计。
点赞
Set 类型可以保证一个用户只能点一个赞,这里举例子一个场景,key 是文章id,value 是用户id。
uid:1
、uid:2
、uid:3
三个用户分别对 article:1 文章点赞了。
# uid:1 用户对文章 article:1 点赞
> SADD article:1 uid:1
(integer) 1
# uid:2 用户对文章 article:1 点赞
> SADD article:1 uid:2
(integer) 1
# uid:3 用户对文章 article:1 点赞
> SADD article:1 uid:3
(integer) 1
uid:1
取消了对 article:1 文章点赞。
> SREM article:1 uid:1
(integer) 1
获取 article:1 文章所有点赞用户 :
> SMEMBERS article:1
1) "uid:3"
2) "uid:2"
获取 article:1 文章的点赞用户数量:
> SCARD article:1
(integer) 2
判断用户 uid:1
是否对文章 article:1 点赞了:
> SISMEMBER article:1 uid:1
(integer) 0 # 返回0说明没点赞,返回1则说明点赞了
共同关注
因为 Set 类型支持交集运算,所以可以用来计算共同关注的好友、公众号等。
key 可以是用户id,value 则是已关注的公众号的id。
uid:1
用户关注公众号 id 为 5、6、7、8、9,uid:2
用户关注公众号 id 为 7、8、9、10、11。
# uid:1 用户关注公众号 id 为 5、6、7、8、9
> SADD uid:1 5 6 7 8 9
(integer) 5
# uid:2 用户关注公众号 id 为 7、8、9、10、11
> SADD uid:2 7 8 9 10 11
(integer) 5
uid:1
和 uid:2
共同关注的公众号:
# 获取共同关注
> SINTER uid:1 uid:2
1) "7"
2) "8"
3) "9"
给 uid:2
推荐 uid:1
关注的公众号:
> SDIFF uid:1 uid:2
1) "5"
2) "6"
验证某个公众号是否同时被 uid:1
或 uid:2
关注:
> SISMEMBER uid:1 5
(integer) 1 # 返回0,说明关注了
> SISMEMBER uid:2 5
(integer) 0 # 返回0,说明没关注
抽奖活动
存储某活动中中奖的用户名 ,Set 类型因为有去重功能,可以保证同一个用户不会中奖两次。
key为抽奖活动名,value为员工名称,把所有员工名称放入抽奖箱 :
>SADD lucky Tom Meng John Sean Marry Lindy Sary Yu
(integer) 5
如果允许重复中奖,可以使用 SRANDMEMBER 命令。
# 抽取 1 个一等奖:
> SRANDMEMBER lucky 1
1) "Tom"
# 抽取 2 个二等奖:
> SRANDMEMBER lucky 2
1) "Yu"
2) "Meng"
# 抽取 3 个三等奖:
> SRANDMEMBER lucky 3
1) "Sary"
2) "Tom"
3) "Meng"
如果不允许重复中奖,可以使用 SPOP 命令。
# 抽取一等奖1个
> SPOP lucky 1
1) "Sary"
# 抽取二等奖2个
> SPOP lucky 2
1) "Meng"
2) "Yu"
# 抽取三等奖3个
> SPOP lucky 3
1) "John"
2) "Sean"
3) "Lindy"
Sorted Set(有序集合)
Zset 类型(有序集合类型)相比于 Set 类型多了一个排序属性 score(分值),对于有序集合 ZSet 来说,每个存储元素相当于有两个值组成的,一个是有序结合的元素值,一个是排序值。
有序集合保留了集合不能有重复成员的特性(分值可以重复),但不同的是,有序集合中的元素可以排序。
存储结构
Zset 类型的底层数据结构是由压缩列表或跳表实现的:
- 如果有序集合的元素个数小于
128
个,并且每个元素的值小于64
字节时,Redis 会使用ziplist作为 Zset 类型的底层数据结构; - 如果有序集合的元素不满足上面的条件,Redis 会使用skiplist+hashtable作为 Zset 类型的底层数据结构;
举例说明
- 在数据量较小时,采用 ziplist 作为其编码,按 score 有序,当键或值长度过大(64)或个数过多(128)时,转为 skiplist + hashtable 编码,同时采用的理由是
- 只用 hashtable,CRUD 是 O(1),但要执行有序操作,需要排序,带来额外时间空间复杂度
- 只用 skiplist,虽然范围操作优点保留,但时间复杂度上升
- 虽然同时采用了两种结构,但由于采用了指针,元素并不会占用双份内存
- skiplist 要点:多层链表、排序规则、 backward、level(span,forward)
- score 存储分数、member 存储数据、按 score 排序,如果 score 相同再按 member 排序
- backward 存储上一个节点指针
- 每个节点中会存储层级信息(level),同一个节点可能会有多层,每个 level 有属性:
- foward 同层中下一个节点指针
- span 跨度,用于计算排名,不是所有跳表都实现了跨度,Redis 实现特有
- 多层链表可以加速查询,规则为,从顶层开始
- 大于同层右边的,继续在同层向右找
- 相等找到了
- 小于同层右边的或右边为 NULL,下一层,重复 1、2 步骤
- 以查找【崔八】为例
- 从顶层(4)层向右找到【王五】节点,22 > 7 继续向右找,但右侧是 NULL,下一层
- 在【王五】节点的第 3 层向右找到【孙二】节点,22 < 37,下一层
- 在【王五】节点的第 2 层向右找到【赵六】节点,22 > 19,继续向右找到【孙二】节点,22 < 37,下一层
- 在【赵六】节点的第 1 层向右找到【崔八】节点,22 = 22,返回
注意
- 数据量较小时,不能体现跳表的性能提升,跳表查询的时间复杂度是 ,与二叉树性能相当
补:跳表查询
skiplist 查找要点,从顶层开始
右边的,继续向右
= 找到了
< 右边的或右边为 NULL,下一层,重复 1、2 步骤
以查找 score = 22 为例:
按照一层链表,我们找到 22 得查 5 次
跳表:先查第一层找到7 发现 7 的右边是null了,再从7 查第二层,右边是 37 比22 大,再从7下一层,下一个元素是19 ,19小于22,19的下一个是37,还得下一层,下一层的下一个就是22了,找到了
跳表查询的时间复杂度
应用场景
Zset 类型(Sorted Set,有序集合) 可以根据元素的权重来排序,我们可以自己来决定每个元素的权重值。比如说,我们可以根据元素插入 Sorted Set 的时间确定权重值,先插入的元素权重小,后插入的元素权重大。
在面对需要展示最新列表、排行榜等场景时,如果数据更新频繁或者需要分页显示,可以优先考虑使用 Sorted Set。
排行榜
有序集合比较典型的使用场景就是排行榜。例如学生成绩的排名榜、游戏积分排行榜、视频播放排名、电商系统中商品的销量排名等。
我们以博文点赞排名为例,发表了五篇博文,分别获得赞为 200、40、100、50、150。
# arcticle:1 文章获得了200个赞
> ZADD user:mengmeng:ranking 200 arcticle:1
(integer) 1
# arcticle:2 文章获得了40个赞
> ZADD user:mengmeng:ranking 40 arcticle:2
(integer) 1
# arcticle:3 文章获得了100个赞
> ZADD user:mengmeng:ranking 100 arcticle:3
(integer) 1
# arcticle:4 文章获得了50个赞
> ZADD user:mengmeng:ranking 50 arcticle:4
(integer) 1
# arcticle:5 文章获得了150个赞
> ZADD user:mengmeng:ranking 150 arcticle:5
(integer) 1
文章 arcticle:4 新增一个赞,可以使用 ZINCRBY 命令(为有序集合key中元素member的分值加上increment):
> ZINCRBY user:mengmeng:ranking 1 arcticle:4
"51"
查看某篇文章的赞数,可以使用 ZSCORE 命令(返回有序集合key中元素个数):
> ZSCORE user:mengmeng:ranking arcticle:4
"50"
获取文章赞数最多的 3 篇文章,可以使用 ZREVRANGE 命令(倒序获取有序集合 key 从start下标到stop下标的元素):
# WITHSCORES 表示把 score 也显示出来
> ZREVRANGE user:mengmeng:ranking 0 2 WITHSCORES
1) "arcticle:1"
2) "200"
3) "arcticle:5"
4) "150"
5) "arcticle:3"
6) "100"
获取 100 赞到 200 赞的文章,可以使用 ZRANGEBYSCORE 命令(返回有序集合中指定分数区间内的成员,分数由低到高排序):
> ZRANGEBYSCORE user:mengmeng:ranking 100 200 WITHSCORES
1) "arcticle:3"
2) "100"
3) "arcticle:5"
4) "150"
5) "arcticle:1"
6) "200"
电话、姓名排序
使用有序集合的 ZRANGEBYLEX
或 ZREVRANGEBYLEX
可以帮助我们实现电话号码或姓名的排序,我们以 ZRANGEBYLEX
(返回指定成员区间内的成员,按 key 正序排列,分数必须相同)为例。
注意:不要在分数不一致的 SortSet 集合中去使用 ZRANGEBYLEX和 ZREVRANGEBYLEX 指令,因为获取的结果会不准确。
1、电话排序
我们可以将电话号码存储到 SortSet 中,然后根据需要来获取号段:
> ZADD phone 0 13100111100 0 13110114300 0 13132110901
(integer) 3
> ZADD phone 0 13200111100 0 13210414300 0 13252110901
(integer) 3
> ZADD phone 0 13300111100 0 13310414300 0 13352110901
(integer) 3
获取所有号码:
> ZRANGEBYLEX phone - +
1) "13100111100"
2) "13110114300"
3) "13132110901"
4) "13200111100"
5) "13210414300"
6) "13252110901"
7) "13300111100"
8) "13310414300"
9) "13352110901"
获取 132 号段的号码:
> ZRANGEBYLEX phone [132 (133
1) "13200111100"
2) "13210414300"
3) "13252110901"
获取132、133号段的号码:
> ZRANGEBYLEX phone [132 (134
1) "13200111100"
2) "13210414300"
3) "13252110901"
4) "13300111100"
5) "13310414300"
6) "13352110901"
2、姓名排序
> zadd names 0 Toumas 0 Jake 0 Bluetuo 0 Gaodeng 0 Aimini 0 Aidehua
(integer) 6
获取所有人的名字:
> ZRANGEBYLEX names - +
1) "Aidehua"
2) "Aimini"
3) "Bluetuo"
4) "Gaodeng"
5) "Jake"
6) "Toumas"
获取名字中大写字母A开头的所有人:
> ZRANGEBYLEX names [A (B
1) "Aidehua"
2) "Aimini"
获取名字中大写字母 C 到 Z 的所有人:
> ZRANGEBYLEX names [C [Z
1) "Gaodeng"
2) "Jake"
3) "Toumas"
BitMap
Bitmap,即位图,是一串连续的二进制数组(0和1),可以通过偏移量(offset)定位元素。BitMap通过最小的单位bit来进行0|1
的设置,表示某个元素的值或者状态,时间复杂度为O(1)。
由于 bit 是计算机中最小的单位,使用它进行储存将非常节省空间,特别适合一些数据量大且使用二值统计的场景。
HyperLogLog
Redis HyperLogLog 是 Redis 2.8.9 版本新增的数据类型,是一种用于「统计基数」的数据集合类型,基数统计就是指统计一个集合中不重复的元素个数。但要注意,HyperLogLog 是统计规则是基于概率完成的,不是非常准确,标准误算率是 0.81%。
所以,简单来说 HyperLogLog 提供不精确的去重计数。
HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的内存空间总是固定的、并且是很小的。
Stream
Redis Stream 是 Redis 5.0 版本新增加的数据类型,Redis 专门为消息队列设计的数据类型。
在 Redis 5.0 Stream 没出来之前,消息队列的实现方式都有着各自的缺陷,例如:
- 发布订阅模式,不能持久化也就无法可靠的保存消息,并且对于离线重连的客户端不能读取历史消息的缺陷;
- List 实现消息队列的方式不能重复消费,一个消息消费完就会被删除,而且生产者需要自行实现全局唯一 ID。
基于以上问题,Redis 5.0 便推出了 Stream 类型也是此版本最重要的功能,用于完美地实现消息队列,它支持消息的持久化、支持自动生成全局唯一 ID、支持 ack 确认消息的模式、支持消费组模式等,让消息队列更加的稳定和可靠。
Redis 数据结构相关命令操作
内容过多,参考我的另一篇博文:
数据结构注意点
set与zset区别
set:
- 集合中的元素是无序、不可重复的,一个集合最多能存储232-1个元素;
- 集合除了支持对元素的增删改查之外,还支持对多个集合取交集、并集、差集。
zset:
- 有序集合保留了集合元素不能重复的特点;
- 有序集合会给每个元素设置一个分数,并以此作为排序的依据;
- 有序集合不能包含相同的元素,但是不同元素的分数可以相同。
Redis中的watch命令
很多时候,要确保事务中的数据没有被其他客户端修改才执行该事务。Redis提供了watch命令来解决这类问题,这是一种乐观锁的机制。客户端通过watch命令,要求服务器对一个或多个key进行监视,如果在客户端执行事务之前,这些key发生了变化,则服务器将拒绝执行客户端提交的事务,并向它返回一个空值.
说说Redis中List结构的相关操作
列表是线性有序的数据结构,它内部的元素是可以重复的,并且一个列表最多能存储232-1个元素。列表包含如下的常用命令:
命令 | 说明 |
| 从列表的左侧/右侧添加数据; |
| 指定索引范围,并返回这个范围内的数据; |
| 返回指定索引处的数据; |
| 从列表的左侧/右侧弹出一个数据; |
| 从列表的左侧/右侧弹出一个数据,若列表为空则进入阻塞状态 |