1
- 你可以自己本机安装 redis 或者通过 redis 官网提供的[ 在线 redis 环境] ( https://try.redis.io/ ) 来实际体验 Redis。
2
-
3
- ![ try-redis] ( ./images/redis-all/try-redis.png )
4
-
5
1
你可以在 Redis 官网上找到 Redis 数据结构非常详细的介绍:[ Redis Data Structures] ( https://redis.com/redis-enterprise/data-structures/ ) 。未来随着 Redis 新版本的发布,可能会有新的数据结构出现,通过查阅 Redis 官网对应的介绍,你总能获取到最靠谱的信息。
6
2
7
- ## 基本数据结构
8
-
9
- ### String(字符串)
3
+ ## String(字符串)
10
4
11
- #### 介绍
5
+ ### 介绍
12
6
13
7
String 是 Redis 中最简单同时也是最常用的一个数据结构。
14
8
@@ -18,7 +12,7 @@ String 是一种二进制安全的数据结构,可以用来存储任何类型
18
12
19
13
虽然 Redis 是用 C 语言写的,但是 Redis 并没有使用 C 的字符串表示,而是自己构建了一种 ** 简单动态字符串** (Simple Dynamic String,** SDS** )。相比于 C 的原生字符串,Redis 的 SDS 不光可以保存文本数据还可以保存二进制数据,并且获取字符串长度复杂度为 O(1)(C 字符串为 O(N)),除此之外,Redis 的 SDS API 是安全的,不会造成缓冲区溢出。
20
14
21
- #### 常用命令
15
+ ### 常用命令
22
16
23
17
| 命令 | 介绍 |
24
18
| ------------------------------ | -------------------------------- |
89
83
(integer) 56
90
84
```
91
85
92
- #### 应用场景
86
+ ### 应用场景
93
87
94
- ** 需要存储数据的场景 **
88
+ ** 需要存储常规数据的场景 **
95
89
96
90
- 举例 :缓存 session、token、图片地址、序列化后的对象(相比较于 Hash 存储更节省内存)。
97
91
- 相关命令 : ` SET ` 、` GET ` 。
98
92
99
93
** 需要计数的场景**
100
94
101
- - 举例 :用户单位时间的请求数(简单限流可以用到)、
95
+ - 举例 :用户单位时间的请求数(简单限流可以用到)、页面单位时间的访问数。
102
96
- 相关命令 :` SET ` 、` GET ` 、 ` INCR ` 、` DECR ` 。
103
97
104
98
** 分布式锁**
105
99
106
100
利用 ` SETNX key value ` 命令可以实现一个最简易的分布式锁(存在一些缺陷,通常不建议这样实现分布式锁)。
107
101
108
- ### List(列表)
102
+ ## List(列表)
109
103
110
- #### 介绍
104
+ ### 介绍
111
105
112
106
Redis 中的 List 其实就是链表数据结构的实现。我在 [ 线性数据结构 :数组、链表、栈、队列] ( https://javaguide.cn/cs-basics/data-structure/linear-data-structure.html ) 这篇文章中详细介绍了链表这种数据结构,我这里就不多做介绍了。
113
107
114
108
许多高级编程语言都内置了链表的实现比如 Java 中的 ` LinkedList ` ,但是 C 语言并没有实现链表,所以 Redis 实现了自己的链表数据结构。Redis 的 List 的实现为一个 ** 双向链表** ,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。
115
109
116
110
![ ] ( https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/image-20220719124413287.png )
117
111
118
- #### 常用命令
112
+ ### 常用命令
119
113
120
114
| 命令 | 介绍 |
121
115
| --------------------------- | ------------------------------------------ |
@@ -182,30 +176,30 @@ Redis 中的 List 其实就是链表数据结构的实现。我在 [线性数据
182
176
(integer) 3
183
177
```
184
178
185
- #### 应用场景
179
+ ### 应用场景
180
+
181
+ ** 信息流展示**
182
+
183
+ - 举例 :最新文章、最新动态。
184
+ - 相关命令 : ` LPUSH ` 、` LRANGE ` 。
186
185
187
186
** 消息队列**
188
187
189
188
Redis List 数据结构可以用来做消息队列,只是功能过于简单,不建议这样做。
190
189
191
190
相对来说,Redis 5.0 新增加的一个数据结构 ` Stream ` 更适合做消息队列一些,只是功能依然非常简陋。和专业的消息队列相比,还是有很多欠缺的地方比如消息丢失和堆积问题不好解决。
192
191
193
- ** 信息流展示**
194
-
195
- - 举例 :最新文章、最新动态。
196
- - 相关命令 : ` LPUSH ` 、` LRANGE ` 。
192
+ ## Hash(哈希)
197
193
198
- ### Hash(哈希)
199
-
200
- #### 介绍
194
+ ### 介绍
201
195
202
196
Hash 是一个 String 类型的 field 和 value 的映射表,特别适合用于存储对象,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。
203
197
204
198
Hash 类似于 JDK1.8 前的 ` HashMap ` ,内部实现也差不多(数组 + 链表)。不过,Redis 的 Hash 做了更多优化。
205
199
206
200
![ ] ( https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/image-20220719124421703.png )
207
201
208
- #### 常用命令
202
+ ### 常用命令
209
203
210
204
| 命令 | 介绍 |
211
205
| ----------------------------------------- | -------------------------------------------------------- |
244
238
" GuideGeGe"
245
239
```
246
240
247
- #### 应用场景
241
+ ### 应用场景
248
242
249
243
** 对象数据存储场景**
250
244
251
245
- 举例 :用户信息、商品信息、文章信息、购物车信息。
252
246
- 相关命令 :` HSET ` (设置单个字段的值)、` HMSET ` (设置多个字段的值)、` HGET ` (获取单个字段的值)、` HMGET ` (获取多个字段的值)。
253
247
254
- String 存储还是 Hash 存储对象数据更好呢?
255
-
256
- - String 存储的是序列化后的对象数据,存放的是整个对象。Hash 是对对象的每个字段单独存储,可以获取部分字段的信息,也可以修改或者添加部分字段,节省网络流量。如果对象中某些字段需要经常变动或者经常需要单独查询对象中的个别字段信息,Hash 就非常适合。
257
- - String 存储相对来说更加节省内存,缓存相同数量的对象数据,String 消耗的内存约是 Hash 的一半。并且,存储具有多层嵌套的对象时也方便很多。如果系统对性能和资源消耗非常敏感的话,String 就非常适合。
258
-
259
- 在绝大部分情况,我们建议使用 String 来存储对象数据即可!
260
-
261
- 那购物车信息用 String 存储还是 Hash 存储更好呢?
262
-
263
- 购物车信息建议使用 Hash 存储:
264
-
265
- - 用户 id 为 key
266
- - 商品 id 为 field,商品数量为 value
248
+ ## Set(集合)
267
249
268
- 由于购物车中的商品频繁修改和变动,这个时候 Hash 就非常适合了!
269
-
270
- ### Set(集合)
271
-
272
- #### 介绍
250
+ ### 介绍
273
251
274
252
Redis 中的 Set 类型是一种无序集合,集合中的元素没有先后顺序但都唯一,有点类似于 Java 中的 ` HashSet ` 。当你需要存储一个列表数据,又不希望出现重复数据时,Set 是一个很好的选择,并且 Set 提供了判断某个元素是否在一个 Set 集合内的重要接口,这个也是 List 所不能提供的。
275
253
276
254
你可以基于 Set 轻易实现交集、并集、差集的操作,比如你可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。这样的话,Set 可以非常方便的实现如共同关注、共同粉丝、共同喜好等功能。这个过程也就是求交集的过程。
277
255
278
256
![ ] ( https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/image-20220719124430264.png )
279
257
280
- #### 常用命令
258
+ ### 常用命令
281
259
282
260
| 命令 | 介绍 |
283
261
| ------------------------------------- | ----------------------------------------- |
@@ -342,7 +320,7 @@ Redis 中的 Set 类型是一种无序集合,集合中的元素没有先后顺
342
320
1) " value1"
343
321
```
344
322
345
- #### 应用场景
323
+ ### 应用场景
346
324
347
325
** 需要存放的数据不能重复的场景**
348
326
@@ -363,15 +341,15 @@ Redis 中的 Set 类型是一种无序集合,集合中的元素没有先后顺
363
341
- 举例 :抽奖系统、随机。
364
342
- 相关命令:` SPOP ` (随机获取集合中的元素并移除,适合不允许重复中奖的场景)、` SRANDMEMBER ` (随机获取集合中的元素,适合允许重复中奖的场景)。
365
343
366
- ### Sorted Set(有序集合)
344
+ ## Sorted Set(有序集合)
367
345
368
- #### 介绍
346
+ ### 介绍
369
347
370
348
Sorted Set 类似于 Set,但和 Set 相比,Sorted Set 增加了一个权重参数 ` score ` ,使得集合中的元素能够按 ` score ` 进行有序排列,还可以通过 ` score ` 的范围来获取元素的列表。有点像是 Java 中 ` HashMap ` 和 ` TreeSet ` 的结合体。
371
349
372
350
![ ] ( https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/image-20220719124437791.png )
373
351
374
- #### 常用命令
352
+ ### 常用命令
375
353
376
354
| 命令 | 介绍 |
377
355
| --------------------------------------------- | ------------------------------------------------------------ |
@@ -451,7 +429,7 @@ value1
451
429
2
452
430
```
453
431
454
- #### 应用场景
432
+ ### 应用场景
455
433
456
434
** 需要随机获取数据源中的元素根据某个权重进行排序的场景**
457
435
@@ -469,98 +447,6 @@ value1
469
447
- 举例 :优先级任务队列。
470
448
- 相关命令 :` ZRANGE ` (从小到大排序) 、 ` ZREVRANGE ` (从大到小排序)、` ZREVRANK ` (指定元素排名)。
471
449
472
- ## 特殊数据结构
473
-
474
- ### Bitmap
475
-
476
- #### 介绍
477
-
478
- Bitmap 存储的是连续的二进制数字(0 和 1),通过 Bitmap, 只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身 。我们知道 8 个 bit 可以组成一个 byte,所以 Bitmap 本身会极大的节省储存空间。
479
-
480
- #### 常用命令
481
-
482
- ` setbit ` 、` getbit ` 、` bitcount ` 、` bitop `
483
-
484
- ``` bash
485
- # SETBIT 会返回之前位的值(默认是 0)这里会生成 7 个位
486
- > setbit mykey 7 1
487
- (integer) 0
488
- > setbit mykey 7 0
489
- (integer) 1
490
- > getbit mykey 7
491
- (integer) 0
492
- > setbit mykey 6 1
493
- (integer) 0
494
- > setbit mykey 8 1
495
- (integer) 0
496
- # 通过 bitcount 统计被被设置为 1 的位的数量。
497
- > bitcount mykey
498
- (integer) 2
499
- ```
500
-
501
- #### 应用场景
502
-
503
- 适合需要保存状态信息(比如是否签到、是否登录...)并需要进一步对这些信息进行分析的场景。比如用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)
504
-
505
- ** 用户行为分析**
506
- 很多网站为了分析你的喜好,需要研究你点赞过的内容。
507
-
508
- ``` bash
509
- # 记录你喜欢过 001 号小姐姐
510
- > setbit beauty_girl_001 uid 1
511
- ```
512
-
513
- ** 统计活跃用户**
514
-
515
- 使用时间作为 key,然后用户 ID 为 offset,如果当日活跃过就设置为 1
516
-
517
- 那么我该如何计算某几天/月/年的活跃用户呢(暂且约定,统计时间内只要有一天在线就称为活跃),有请下一个 redis 的命令
518
-
519
- ``` bash
520
- # 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
521
- # BITOP 命令支持 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种参数
522
- BITOP operation destkey key [key ...]
523
- ```
524
-
525
- 初始化数据:
526
-
527
- ``` bash
528
- > setbit 20210308 1 1
529
- (integer) 0
530
- > setbit 20210308 2 1
531
- (integer) 0
532
- > setbit 20210309 1 1
533
- (integer) 0
534
- ```
535
-
536
- 统计 20210308~ 20210309 总活跃用户数: 1
537
-
538
- ``` bash
539
- > bitop and desk1 20210308 20210309
540
- (integer) 1
541
- > bitcount desk1
542
- (integer) 1
543
- ```
544
-
545
- 统计 20210308~ 20210309 在线活跃用户数: 2
546
-
547
- ``` bash
548
- > bitop or desk2 20210308 20210309
549
- (integer) 1
550
- > bitcount desk2
551
- (integer) 2
552
- ```
553
-
554
- ** 用户在线状态**
555
-
556
- 对于获取或者统计用户在线状态,使用 Bitmap 是一个节约空间且效率又高的一种方法。
557
-
558
- 只需要一个 key,然后用户 ID 为 offset,如果在线就设置为 1,不在线就设置为 0。
559
-
560
- ### HyperLogLog
561
-
562
- ### Stream
563
-
564
450
## 参考
565
451
566
452
- Redis Data Structures :https://redis.com/redis-enterprise/data-structures/ 。
0 commit comments