10
10
11
11
#### 介绍
12
12
13
- String 是 Redis 中最简单同时也是最常用的一个数据结构。它是一种二进制安全的数据结构,可以用来存储任何类型的数据比如字符串、整数、浮点数、图片(图片的 base64 编码或者解码或者图片的路径)、序列化后的对象。
13
+ String 是 Redis 中最简单同时也是最常用的一个数据结构。
14
14
15
- ![ ] ( https://redis.com/wp-content/uploads/2019/07/data-structures-_strings.svg?&auto=webp&quality=85,75&width=800 )
15
+ String 是一种二进制安全的数据结构,可以用来存储任何类型的数据比如字符串、整数、浮点数、图片(图片的 base64 编码或者解码或者图片的路径)、序列化后的对象。
16
16
17
- 虽然 Redis 是用 C 语言写的,但是 Redis 并没有使用 C 的字符串表示,而是自己构建了一种 ** 简单动态字符串** (simple dynamic string,** SDS** )。相比于 C 的原生字符串,Redis 的 SDS 不光可以保存文本数据还可以保存二进制数据,并且获取字符串长度复杂度为 O(1)(C 字符串为 O(N)),除此之外,Redis 的 SDS API 是安全的,不会造成缓冲区溢出。
17
+ ![ ] ( https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/image-20220719124403897.png )
18
+
19
+ 虽然 Redis 是用 C 语言写的,但是 Redis 并没有使用 C 的字符串表示,而是自己构建了一种 ** 简单动态字符串** (Simple Dynamic String,** SDS** )。相比于 C 的原生字符串,Redis 的 SDS 不光可以保存文本数据还可以保存二进制数据,并且获取字符串长度复杂度为 O(1)(C 字符串为 O(N)),除此之外,Redis 的 SDS API 是安全的,不会造成缓冲区溢出。
18
20
19
21
#### 常用命令
20
22
89
91
90
92
#### 应用场景
91
93
94
+ ** 需要存储数据的场景**
95
+
96
+ - 举例 :缓存 session、token、图片地址、序列化后的对象(相比较于 Hash 存储更节省内存)。
97
+ - 相关命令 : ` SET ` 、` GET ` 。
98
+
92
99
** 需要计数的场景**
93
100
94
- 比如用户的访问次数、热点文章的点赞转发数量等等。
101
+ - 举例 :用户单位时间的请求数(简单限流可以用到)、
102
+ - 相关命令 :` SET ` 、` GET ` 、 ` INCR ` 、` DECR ` 。
103
+
104
+ ** 分布式锁**
105
+
106
+ 利用 ` SETNX key value ` 命令可以实现一个最简易的分布式锁(存在一些缺陷,通常不建议这样实现分布式锁)。
95
107
96
108
### List(列表)
97
109
@@ -101,7 +113,7 @@ Redis 中的 List 其实就是链表数据结构的实现。我在 [线性数据
101
113
102
114
许多高级编程语言都内置了链表的实现比如 Java 中的 ` LinkedList ` ,但是 C 语言并没有实现链表,所以 Redis 实现了自己的链表数据结构。Redis 的 List 的实现为一个 ** 双向链表** ,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。
103
115
104
- ![ img ] ( https://redis. com/wp-content/uploads/2019/07/data-structures-_lists.svg?&auto=webp&quality=85,75&width=500 )
116
+ ![ ] ( https://guide-blog-images.oss-cn-shenzhen.aliyuncs. com/github/javaguide/database/redis/image-20220719124413287.png )
105
117
106
118
#### 常用命令
107
119
@@ -172,18 +184,17 @@ Redis 中的 List 其实就是链表数据结构的实现。我在 [线性数据
172
184
173
185
#### 应用场景
174
186
175
- ** Timeline 信息流展示**
176
-
177
- Timeline 信息流中内存都是按照时间来排序,比较典型的产品有微信朋友圈、QQ 空间、微博关注者动态、Twitter 最新推文。
178
-
179
- 像这种场景,Redis List 就非常适合用来作为存储数据结构了。
180
-
181
187
** 消息队列**
182
188
183
189
Redis List 数据结构可以用来做消息队列,只是功能过于简单,不建议这样做。
184
190
185
191
相对来说,Redis 5.0 新增加的一个数据结构 ` Stream ` 更适合做消息队列一些,只是功能依然非常简陋。和专业的消息队列相比,还是有很多欠缺的地方比如消息丢失和堆积问题不好解决。
186
192
193
+ ** 信息流展示**
194
+
195
+ - 举例 :最新文章、最新动态。
196
+ - 相关命令 : ` LPUSH ` 、` LRANGE ` 。
197
+
187
198
### Hash(哈希)
188
199
189
200
#### 介绍
@@ -192,7 +203,7 @@ Hash 是一个 String 类型的 field 和 value 的映射表,特别适合用
192
203
193
204
Hash 类似于 JDK1.8 前的 ` HashMap ` ,内部实现也差不多(数组 + 链表)。不过,Redis 的 Hash 做了更多优化。
194
205
195
- ![ ] ( https://redis. com/wp-content/uploads/2019/07/data-structures-_hashes.svg?&auto=webp&quality=85,75&width=800 )
206
+ ![ ] ( https://guide-blog-images.oss-cn-shenzhen.aliyuncs. com/github/javaguide/database/redis/image-20220719124421703.png )
196
207
197
208
#### 常用命令
198
209
235
246
236
247
#### 应用场景
237
248
238
- 对象数据的存储。
249
+ ** 对象数据存储场景 **
239
250
240
- ### Set(集合)
251
+ - 举例 :用户信息、商品信息、文章信息、购物车信息。
252
+ - 相关命令 :` HSET ` (设置单个字段的值)、` HMSET ` (设置多个字段的值)、` HGET ` (获取单个字段的值)、` HMGET ` (获取多个字段的值)。
241
253
242
- #### 介绍
254
+ String 存储还是 Hash 存储对象数据更好呢?
255
+
256
+ - String 存储的是序列化后的对象数据,存放的是整个对象。Hash 是对对象的每个字段单独存储,可以获取部分字段的信息,也可以修改或者添加部分字段,节省网络流量。如果对象中某些字段需要经常变动或者经常需要单独查询对象中的个别字段信息,Hash 就非常适合。
257
+ - String 存储相对来说更加节省内存,缓存相同数量的对象数据,String 消耗的内存约是 Hash 的一半。并且,存储具有多层嵌套的对象时也方便很多。如果系统对性能和资源消耗非常敏感的话,String 就非常适合。
258
+
259
+ 在绝大部分情况,我们建议使用 String 来存储对象数据即可!
260
+
261
+ 那购物车信息用 String 存储还是 Hash 存储更好呢?
243
262
244
- Redis 中的 Set 类型是一种无序集合,集合中的元素没有先后顺序但都唯一,有点类似于Java 中的 ` HashSet ` 。当你需要存储一个列表数据,又不希望出现重复数据时,Set 是一个很好的选择,并且 Set 提供了判断某个元素是否在一个 Set 集合内的重要接口,这个也是 List 所不能提供的。
263
+ 购物车信息建议使用 Hash 存储:
245
264
246
- 你可以基于 Set 轻易实现交集、并集、差集的操作,比如你可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。这样的话,Set 可以非常方便的实现如共同关注、共同粉丝、共同喜好等功能。这个过程也就是求交集的过程。
265
+ - 用户 id 为 key
266
+ - 商品 id 为 field,商品数量为 value
247
267
268
+ 由于购物车中的商品频繁修改和变动,这个时候 Hash 就非常适合了!
269
+
270
+ ### Set(集合)
271
+
272
+ #### 介绍
248
273
274
+ Redis 中的 Set 类型是一种无序集合,集合中的元素没有先后顺序但都唯一,有点类似于 Java 中的 ` HashSet ` 。当你需要存储一个列表数据,又不希望出现重复数据时,Set 是一个很好的选择,并且 Set 提供了判断某个元素是否在一个 Set 集合内的重要接口,这个也是 List 所不能提供的。
249
275
250
- ![ ] ( https://redis.com/wp-content/uploads/2019/07/data-structures-_sets.svg?&auto=webp&quality=85,75&width=800 )
276
+ 你可以基于 Set 轻易实现交集、并集、差集的操作,比如你可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。这样的话,Set 可以非常方便的实现如共同关注、共同粉丝、共同喜好等功能。这个过程也就是求交集的过程。
277
+
278
+ ![ ] ( https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/image-20220719124430264.png )
251
279
252
280
#### 常用命令
253
281
@@ -263,6 +291,8 @@ Redis 中的 Set 类型是一种无序集合,集合中的元素没有先后顺
263
291
| SUNIONSTORE destination key1 key2 ... | 将给定所有集合的并集存储在 destination 中 |
264
292
| SDIFF key1 key2 ... | 获取给定所有集合的差集 |
265
293
| SDIFFSTORE destination key1 key2 ... | 将给定所有集合的差集存储在 destination 中 |
294
+ | SPOP key | 随机移除并获取指定集合中一个或多个元素 |
295
+ | SRANDMEMBER key count | 随机获取指定集合中指定数量的元素 |
266
296
267
297
更多 Redis Set 命令以及详细使用指南,请查看 Redis 官网对应的介绍:https://redis.io/commands/?group=set 。
268
298
@@ -285,7 +315,7 @@ Redis 中的 Set 类型是一种无序集合,集合中的元素没有先后顺
285
315
```
286
316
287
317
- ` mySet ` : ` value1 ` 、` value2 ` 。
288
- - ` mySet2 ` : ` value2 ` 、` value3 ` 。
318
+ - ` mySet2 ` : ` value2 ` 、` value3 ` 。
289
319
290
320
** 求交集** :
291
321
@@ -314,28 +344,45 @@ Redis 中的 Set 类型是一种无序集合,集合中的元素没有先后顺
314
344
315
345
#### 应用场景
316
346
317
- 当我们需要存放的数据不能重复,并且需要获取多个数据源交集、并集和差集的时候(比如共同好友) Set 就非常适合。
347
+ ** 需要存放的数据不能重复的场景**
348
+
349
+ - 举例:网站 UV 统计(数据量巨大的场景还是 ` HyperLogLog ` 更适合一些)、文章点赞、动态点赞等场景。
350
+ - 相关命令:` SCARD ` (获取集合数量) 。
351
+
352
+ ![ ] ( https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/image-20220719073733851.png )
353
+
354
+ ** 需要获取多个数据源交集、并集和差集的场景**
355
+
356
+ - 举例 :共同好友(交集)、共同粉丝(交集)、共同关注(交集)、好友推荐(差集)、音乐推荐(差集) 、订阅号推荐(差集+交集) 等场景。
357
+ - 相关命令:` SINTER ` (交集)、` SINTERSTORE ` (交集)、` SUNION ` (并集)、` SUNIONSTORE ` (并集)、` SDIFF ` (交集)、` SDIFFSTORE ` (交集)。
358
+
359
+ ![ ] ( https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/image-20220719074543513.png )
360
+
361
+ ** 需要随机获取数据源中的元素的场景**
362
+
363
+ - 举例 :抽奖系统、随机。
364
+ - 相关命令:` SPOP ` (随机获取集合中的元素并移除,适合不允许重复中奖的场景)、` SRANDMEMBER ` (随机获取集合中的元素,适合允许重复中奖的场景)。
318
365
319
366
### Sorted Set(有序集合)
320
367
321
368
#### 介绍
322
369
323
370
Sorted Set 类似于 Set,但和 Set 相比,Sorted Set 增加了一个权重参数 ` score ` ,使得集合中的元素能够按 ` score ` 进行有序排列,还可以通过 ` score ` 的范围来获取元素的列表。有点像是 Java 中 ` HashMap ` 和 ` TreeSet ` 的结合体。
324
371
325
- ![ ] ( https://redis. com/wp-content/uploads/2019/07/data-structures-_sorted-sets.svg?&auto=webp&quality=85,75&width=500 )
372
+ ![ ] ( https://guide-blog-images.oss-cn-shenzhen.aliyuncs. com/github/javaguide/database/redis/image-20220719124437791.png )
326
373
327
374
#### 常用命令
328
375
329
376
| 命令 | 介绍 |
330
377
| --------------------------------------------- | ------------------------------------------------------------ |
331
- | ZADD key score1 member1 score2 member2 ... | 向指定有序集合添加一个或多个元素 |
378
+ | ZADD key score1 member1 score2 member2 ... | 向指定有序集合添加一个或多个元素 |
332
379
| ZCARD KEY | 获取指定有序集合的元素数量 |
333
380
| ZSCORE key member | 获取指定有序集合中指定元素的 score 值 |
334
381
| ZINTERSTORE destination numkeys key1 key2 ... | 将给定所有有序集合的交集存储在 destination 中,对相同元素对应的 score 值进行 SUM 聚合操作,numkeys 为集合数量 |
335
382
| ZUNIONSTORE destination numkeys key1 key2 ... | 求并集,其它和 ZINTERSTORE 类似 |
336
- | ZDIFF destination numkeys key1 key2 ... | 求差集,其它和 ZINTERSTORE 类似 |
337
- | ZRANGE key start end | 获取指定有序集合 start 和 end 之间的元素 |
338
- | ZREVRANGE key start end | 获取指定有序集合 start 和 end 之间的元素(score从高到底) |
383
+ | ZDIFF destination numkeys key1 key2 ... | 求差集,其它和 ZINTERSTORE 类似 |
384
+ | ZRANGE key start end | 获取指定有序集合 start 和 end 之间的元素(score 从低到高) |
385
+ | ZREVRANGE key start end | 获取指定有序集合 start 和 end 之间的元素(score 从高到底) |
339
386
| ZREVRANK key member | 获取指定有序集合中指定元素的排名(score 从大到小排序) |
340
387
341
388
更多 Redis Sorted Set 命令以及详细使用指南,请查看 Redis 官网对应的介绍:https://redis.io/commands/?group=sorted-set 。
@@ -361,7 +408,7 @@ Sorted Set 类似于 Set,但和 Set 相比,Sorted Set 增加了一个权重
361
408
```
362
409
363
410
- ` myZset ` : ` value1 ` (2.0)、` value2 ` (1.0) 。
364
- - ` myZset2 ` : ` value2 ` (4.0)、` value3 ` (3.0) 。
411
+ - ` myZset2 ` : ` value2 ` (4.0)、` value3 ` (3.0) 。
365
412
366
413
** 获取指定元素的排名** :
367
414
@@ -406,23 +453,33 @@ value1
406
453
407
454
#### 应用场景
408
455
409
- 需要对数据根据某个权重进行排序的场景。比如在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息。
456
+ ** 需要随机获取数据源中的元素根据某个权重进行排序的场景 **
410
457
411
- ## 特殊数据结构
458
+ - 举例 :各种排行榜比如直播间送礼物的排行榜、朋友圈的微信步数排行榜、王者荣耀中的段位排行榜、话题热度排行榜等等。
459
+ - 相关命令 :` ZRANGE ` (从小到大排序) 、 ` ZREVRANGE ` (从大到小排序)、` ZREVRANK ` (指定元素排名)。
412
460
461
+ ![ ] ( https://img-blog.csdnimg.cn/2021060714195385.png )
413
462
463
+ [ 《Java 面试指北》] ( https://www.yuque.com/docs/share/f37fc804-bfe6-4b0d-b373-9c462188fec7 ) 的「技术面试题篇」就有一篇文章详细介绍如何使用 Sorted Set 来设计制作一个排行榜。
414
464
415
- ### sorted set
465
+ ![ ] ( https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/image-20220719071115140.png )
416
466
467
+ ** 需要存储的数据有优先级或者重要程度的场景** 比如优先级任务队列。
417
468
469
+ - 举例 :优先级任务队列。
470
+ - 相关命令 :` ZRANGE ` (从小到大排序) 、 ` ZREVRANGE ` (从大到小排序)、` ZREVRANK ` (指定元素排名)。
418
471
472
+ ## 特殊数据结构
473
+
474
+ ### Bitmap
419
475
476
+ #### 介绍
420
477
421
- ### bitmap
478
+ Bitmap 存储的是连续的二进制数字(0 和 1),通过 Bitmap, 只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身 。我们知道 8 个 bit 可以组成一个 byte,所以 Bitmap 本身会极大的节省储存空间。
479
+
480
+ #### 常用命令
422
481
423
- 1 . ** 介绍:** bitmap 存储的是连续的二进制数字(0 和 1),通过 bitmap, 只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身 。我们知道 8 个 bit 可以组成一个 byte,所以 bitmap 本身会极大的节省储存空间。
424
- 2 . ** 常用命令:** ` setbit ` 、` getbit ` 、` bitcount ` 、` bitop `
425
- 3 . ** 应用场景:** 适合需要保存状态信息(比如是否签到、是否登录...)并需要进一步对这些信息进行分析的场景。比如用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)。
482
+ ` setbit ` 、` getbit ` 、` bitcount ` 、` bitop `
426
483
427
484
``` bash
428
485
# SETBIT 会返回之前位的值(默认是 0)这里会生成 7 个位
@@ -441,17 +498,19 @@ value1
441
498
(integer) 2
442
499
```
443
500
444
- 针对上面提到的一些场景,这里进行进一步说明。
501
+ #### 应用场景
502
+
503
+ 适合需要保存状态信息(比如是否签到、是否登录...)并需要进一步对这些信息进行分析的场景。比如用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)
445
504
446
- ** 使用场景一: 用户行为分析**
505
+ ** 用户行为分析**
447
506
很多网站为了分析你的喜好,需要研究你点赞过的内容。
448
507
449
508
``` bash
450
509
# 记录你喜欢过 001 号小姐姐
451
510
> setbit beauty_girl_001 uid 1
452
511
```
453
512
454
- ** 使用场景二: 统计活跃用户**
513
+ ** 统计活跃用户**
455
514
456
515
使用时间作为 key,然后用户 ID 为 offset,如果当日活跃过就设置为 1
457
516
@@ -492,13 +551,19 @@ BITOP operation destkey key [key ...]
492
551
(integer) 2
493
552
```
494
553
495
- ** 使用场景三: 用户在线状态**
554
+ ** 用户在线状态**
496
555
497
- 对于获取或者统计用户在线状态,使用 bitmap 是一个节约空间且效率又高的一种方法。
556
+ 对于获取或者统计用户在线状态,使用 Bitmap 是一个节约空间且效率又高的一种方法。
498
557
499
558
只需要一个 key,然后用户 ID 为 offset,如果在线就设置为 1,不在线就设置为 0。
500
559
560
+ ### HyperLogLog
561
+
562
+ ### Stream
563
+
501
564
## 参考
502
565
503
566
- Redis Data Structures :https://redis.com/redis-enterprise/data-structures/ 。
504
- - Redis Commands : https://redis.io/commands/ 。
567
+ - Redis Commands : https://redis.io/commands/ 。
568
+ - Redis Data types tutorial:https://redis.io/docs/manual/data-types/data-types-tutorial/ 。
569
+ - Redis 存储对象信息是用 Hash 还是 String : https://segmentfault.com/a/1190000040032006
0 commit comments