之前写过一点小知识:https://blog.csdn.net/qq_45927881/article/details/134959181?spm=1001.2014.3001.5501
参考链接
https://xiaolincoding.com/redis/data_struct/command.html#%E4%BB%8B%E7%BB%8D
目录
- 1. string(字符串)
- 2. Hash(哈希)
- 3. List(列表)
- 4. Set(集合)
- 5. Zset(有序集合)
1. string(字符串)
String 是最基本的 key-value 结构,key 是唯一标识,value 是具体的值,value其实不仅是字符串, 也可以是数字(整数或浮点数),value 最多可以容纳的数据长度是 512M
总结:
以下是Redis中string的主要特点和用法:
-
存储字符串数据: string类型可以存储任意长度的字符串数据,例如文本、JSON等。
-
存储整数和浮点数: string类型还可以存储整数和浮点数数据。当存储整数时,Redis会对整数进行特殊处理,可以对整数进行自增、自减等操作。当存储浮点数时,Redis会以字符串形式存储,并支持对浮点数进行加减乘除等数学运算。
-
常见命令: Redis提供了一系列用于操作string的命令,包括:
- SET:设置指定键的值。
- GET:获取指定键的值。
- DEL:删除指定键及其对应的值。
- INCR:将指定键的值增加1。
- DECR:将指定键的值减少1。
- APPEND:在指定键的值后面追加字符串。
-
内存优化: Redis对于小字符串的存储采用了一种优化策略,即使用SDS(Simple Dynamic String)来存储字符串数据,可以减少内存的碎片化和浪费。
-
应用场景: string类型在Redis中有着广泛的应用场景,例如==缓存、计数器、分布式锁==等。
分布式锁(还没完全了解,待更新…)
共享 Session 信息
问题:通常我们在开发后台管理系统时,会使用 Session 来保存用户的会话(登录)状态,这些 Session 信息会被保存在服务器端,但这只适用于单系统应用,如果是分布式系统此模式将不再适用。
例如用户一的 Session 信息被存储在服务器一,但第二次访问时用户一被分配到服务器二,这个时候服务器并没有用户一的 Session 信息,就会出现重复登录的问题,问题在于分布式系统每次会把请求随机分配到不同的服务器。
分布式系统单独存储 Session 流程图:
因此,需要借助 Redis 对这些 Session 信息进行统一的存储和管理,这样无论请求发送到哪台服务器,服务器都会去同一个 Redis 获取相关的 Session 信息,这样就解决了分布式系统下 Session 存储的问题。
分布式系统使用同一个 Redis 存储 Session 流程图:
2. Hash(哈希)
Hash 是一个键值对(key - value)集合,其中 value 的形式如: value=[{field1,value1},…{fieldN,valueN}]。Hash 特别适合用于存储对象。
Hash 与 String 对象的区别如下图所示:
总结
在Redis中,hash是一种用于存储键值对的数据结构,类似于字典或者关联数组。每个hash可以存储多个键值对,其中每个键都是唯一的,且与一个值关联。
以下是Redis中hash的主要特点和用法:
-
存储键值对: hash类型可以存储多个键值对,其中每个键都是唯一的,且与一个值关联。这些值可以是字符串、整数或者浮点数等类型。
-
内存优化: Redis对于小hash的存储采用了一种优化策略,可以减少内存的碎片化和浪费。
-
支持多字段操作: Redis提供了一系列用于操作hash的命令,包括:
- HSET:设置hash中指定字段的值。
- HGET:获取hash中指定字段的值。 -
HDEL:删除hash中指定字段及其对应的值。- HINCRBY:将hash中指定字段的值增加一个整数。
- HGETALL:获取hash中所有字段和对应的值。
- HMSET:同时设置多个字段的值。 HMGET:同时获取多个字段的值。
- 应用场景: hash类型在Redis中有着广泛的应用场景,例如存储对象的属性、缓存数据、统计数据等。它可以将相关的数据组织在一起,方便进行管理和操作。
缓存对象
在介绍 String 类型的应用场景时有所介绍,String + Json也是存储对象的一种方式,那么存储对象时,到底用 String + json 还是用 Hash 呢?
一般对象用 String + Json 存储,对象中某些频繁变化的属性可以考虑抽出来用 Hash 类型存储。
缓存对象的例子:
购物车
以用户 id 为 key(因为用户id不会频繁发生变化),商品 id 为 field(商品id会频繁发生变化),商品数量为 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查询一次数据库,获取完整的商品的信息
3. List(列表)
List 列表是简单的字符串列表,按照插入顺序排序,可以从头部或尾部向 List 列表添加元素。
总结
在Redis中,List(列表)是一种常用的数据结构,它可以存储一个有序的字符串列表。List中的每个元素都可以是一个字符串,它们按照插入顺序排列,并且支持从两端进行元素的插入和删除操作。
以下是Redis中List的主要特点和用法:
-
有序性: List中的元素按照插入顺序排列,保持了元素的有序性。这意味着元素的顺序可以被保留和控制,可以按照特定的顺序进行访问和处理。
-
动态增长: List是一个动态数据结构,它可以根据需要动态地增长和缩减。在List中添加元素时,List会自动增长以容纳新的元素;而删除元素时,List会自动缩减以释放空间。
-
支持重复元素: List中可以包含重复的元素,即同一个值可以被多次插入到List中。
-
常见命令: Redis提供了一系列用于操作List的命令,包括:
- LPUSH / RPUSH:将一个或多个元素从左端(LPUSH)或右端(RPUSH)插入到List中。
- LPOP / RPOP:从左端(LPOP)或右端(RPOP)删除并返回一个元素。
- LRANGE:获取List中指定范围的元素。
- LLEN:获取List的长度(即元素个数)。
- LINDEX:获取List中指定索引位置的元素。
- 应用场景: List在Redis中有着广泛的应用场景,例如消息队列、任务队列、最新消息列表、粉丝列表等。通过List可以方便地实现先进先出(FIFO)的数据结构,以及实时更新和处理数据列表。
消息队列
消息队列的定义:
消息队列(Message Queue)是一种基于消息的通信模式,用于在应用程序之间进行异步通信。它通常由消息生产者、消息队列和消息消费者组成,消息生产者负责将消息发送到队列中,消息消费者则从队列中获取消息并进行处理。消息队列的主要特点包括:
解耦和异步: 消息队列可以实现生产者和消费者之间的解耦,即生产者不需要知道消费者的存在,反之亦然。生产者可以将消息发送到队列中之后即可继续执行其他任务,而消费者则可以从队列中异步地获取消息并进行处理。
削峰填谷: 消息队列可以平滑处理系统的高峰流量和突发请求,通过缓冲消息并控制消息处理速率,可以有效地减轻系统负载和提高系统的稳定性。
数据传输和持久化: 消息队列通常提供可靠的消息传输和持久化机制,可以确保消息的可靠传递和持久化存储,即使在系统故障或者网络中断的情况下也不会丢失消息。
消息分发和路由: 消息队列通常支持灵活的消息分发和路由策略,可以根据消息的类型、优先级或者目的地进行消息的分发和路由,从而满足不同的业务需求。
队列管理和监控: 消息队列通常提供丰富的管理和监控功能,可以对队列进行监控和管理,包括队列的创建、删除、监控队列的状态、消息数量、消费者数量等。
消息队列在分布式系统、微服务架构、异步任务处理等场景中有着广泛的应用,可以提高系统的可伸缩性、可靠性和性能,实现系统之间的解耦和异步通信
消息队列在存取消息时,必须要满足三个需求,分别是消息保序、处理重复的消息和保证消息可靠性。
1、如何满足消息保序需求?
List 本身就是按先进先出【FIFO】的顺序对数据进行存取的,所以,如果使用 List 作为消息队列保存消息的话,就已经能满足消息保序的需求了。
List 可以使用 LPUSH + RPOP (或者反过来,RPUSH+LPOP)命令实现消息队列。
生产者使用 LPUSH key value[value…] 将消息插入到队列的头部,如果 key 不存在则会创建一个空的队列再插入消息。
消费者使用 RPOP key 依次读取队列的消息,先进先出。
不过,在消费者读取数据时,有一个潜在的性能风险点。
在生产者往 List 中写入数据时,List 并不会主动地通知消费者有新消息写入,如果消费者想要及时处理消息,就需要在程序中不停地调用 RPOP 命令(比如使用一个while(1)循环)。如果有新消息写入,RPOP命令就会返回结果,否则,RPOP命令返回空值,再继续循环。
所以,即使没有新消息写入List,消费者也要不停地调用 RPOP 命令,这就会导致消费者程序的 CPU 一直消耗在执行 RPOP 命令上,带来不必要的性能损失。
为了解决这个问题,Redis提供了 BRPOP 命令。BRPOP命令也称为阻塞式读取,客户端在没有读到队列数据时,自动阻塞,直到有新的数据写入队列,再开始读取新数据。 (类似go语言的管道channel)和消费者程序自己不停地调用RPOP命令相比,这种方式能节省CPU开销。
2、如何处理重复的消息?(因为 List中可以包含重复的元素)
消费者要实现重复消息的判断,需要 2 个方面的要求:
- 每个消息都有一个全局的 ID。
- 消费者要记录已经处理过的消息的 ID。当收到一条消息后,消费者程序就可以对比收到的消息 ID 和记录的已处理过的消息 ID,来判断当前收到的消息有没有经过处理。如果已经处理过,那么,消费者程序就不再进行处理了。
但是 List 并不会为每个消息生成 ID 号,所以我们需要自行为每个消息生成一个全局唯一ID,生成之后,我们在用 LPUSH 命令把消息插入 List 时,需要在消息中包含这个全局唯一 ID。
例如,我们执行以下命令,就把一条全局 ID 为 111000102、库存量为 99 的消息插入了消息队列:
LPUSH mq “111000102:stock:99”
(integer) 1
3、如何保证消息可靠性?
当消费者程序从 List 中读取一条消息后,List 就不会再留存这条消息了。所以,如果消费者程序在处理消息的过程出现了故障或宕机,就会导致消息没有处理完成,那么,消费者程序再次启动后,就没法再次从 List 中读取消息了。
为了留存消息,List 类型提供了 BRPOPLPUSH 命令,这个命令的作用是让消费者程序从一个 List 中读取消息,同时,Redis 会把这个消息再插入到另一个 List(可以叫作备份 List)留存。
这样一来,如果消费者程序读了消息但没能正常处理,等它重启后,就可以从备份 List 中重新读取消息并进行处理了。
基于 List 类型的消息队列,满足消息队列的三大需求(消息保序、处理重复的消息和保证消息可靠性)。
- 消息保序:使用 LPUSH + RPOP; (但是消费者循环读取消息,如果这时候队列中没有此消息,那么消费者会读取到空值,这不仅浪费资源,也没有得到结果,需要改进,所以加了阻塞读取)
- 阻塞读取:使用 BRPOP;
- 重复消息处理:生产者自行实现全局唯一 ID;
- 消息的可靠性:使用 BRPOPLPUSH
List 作为消息队列有什么缺陷?
-
List 不支持多个消费者消费同一条消息,因为一旦消费者拉取一条消息后,这条消息就从 List 中删除了,无法被其它消费者再次消费。
-
要实现一条消息可以被多个消费者消费,那么就要将多个消费者组成一个消费组,使得多个消费者可以消费同一条消息,但是== List 类型并不支持消费组的实现==。
这就要说起 Redis 从 5.0 版本开始提供的 Stream 数据类型 了,Stream 同样能够满足消息队列的三大需求,而且它还支持「消费组」形式的消息读取。
4. Set(集合)
Set 类型是一个无序并唯一的键值集合【ist 是按照元素的先后顺序存储元素,且支持重复元素】,它的存储顺序不会按照插入的先后顺序进行存储。
总结
在Redis中,set是一种无序、唯一的集合数据结构,它可以存储多个不重复的元素。Redis的set数据结构提供了高效的添加、删除、更新、查找等操作,常用于存储一组唯一的元素。
以下是Redis中set的主要特点和用法:
-
存储唯一元素: set类型可以存储多个不重复的元素,每个元素在set中只会出现一次,不会重复。
-
无序性: set类型中的元素是无序的,即存储元素的顺序不会影响元素的存储和查找。
-
Redis的set类型支持多个集合之间的交集、并集、差集等运算,可以方便地进行集合操作。
-
常见命令: Redis提供了一系列用于操作set的命令,包括:
- SADD:向指定集合中添加一个或多个元素。
- SREM:从指定集合中移除一个或多个元素。
- SISMEMBER:检查指定元素是否存在于集合中。
- SMEMBERS:获取集合中的所有元素。
- SCARD:获取集合中元素的数量。 SINTER:求多个集合的交集。
- SUNION:求多个集合的并集。
- SDIFF:求多个集合的差集。 集合运算:
- 应用场景: set类型在Redis中有着广泛的应用场景,例如标签系统、关注列表、粉丝列表等。它可以存储一组唯一的元素,并提供高效的操作命令,非常适合于需要存储一组唯一元素的场景。
点赞
Set 类型可以保证一个用户只能点一个赞,这里举例子一个场景,key 是文章id,value 是用户id。
共同关注
Set 类型支持交集运算,所以可以用来计算共同关注的好友、公众号等。
key 可以是用户id,value 则是已关注的公众号的id。
抽奖活动
存储某活动中中奖的用户名 ,Set 类型因为有去重功能,可以保证同一个用户不会中奖两次。
key为抽奖活动名,value为员工名称,把所有员工名称放入抽奖箱
5. Zset(有序集合)
Zset 类型(有序集合类型)相比于 Set 类型多了一个排序属性 score(分值),对于有序集合 ZSet 来说,每个存储元素相当于有两个值组成的,一个是有序集合的元素值,一个是排序值。
有序集合保留了集合不能有重复成员的特性(分值可以重复:80、80、81、88、88等),但不同的是,有序集合中的元素可以排序。
总结
在Redis中,Zset(有序集合)是一种有序的数据结构,它类似于普通的集合(set),但每个元素都关联了一个分数(score),使得元素可以按照分数进行排序。Zset中的元素是唯一的,但分数可以重复。(有序但可重复)
以下是Redis中Zset的主要特点和用法:
-
有序性: Zset中的元素是按照分数进行排序的,可以根据分数来获取元素的排名和范围。这种有序性使得Zset非常适合于需要按照某种顺序来处理元素的场景。
-
元素唯一性: Zset中的每个元素都是唯一的,即使分数相同也可以存储多个元素,但根据元素值来判断唯一性。
-
支持范围操作: Zset提供了一系列用于范围操作的命令,例如根据排名获取元素、根据分数范围获取元素等,可以方便地对Zset中的元素进行筛选和过滤。
-
常见命令: Redis提供了一系列用于操作Zset的命令,包括:
- ZADD:向Zset中添加一个或多个元素。
- ZSCORE:获取指定元素的分数。
- ZRANK:获取指定元素的排名。
- ZRANGE:根据排名范围获取元素列表。
- ZRANGEBYSCORE:根据分数范围获取元素列表。
- 应用场景: Zset在Redis中有着广泛的应用场景,例如排行榜、计分系统、事件调度等。它可以存储带有权重或者优先级的元素,并且可以根据分数来进行排序和过滤,非常适合于需要按照某种顺序来处理元素的场景。