From c6bf96e3a5fdf9f2e6966ee4028e0b1f4989956d Mon Sep 17 00:00:00 2001 From: guide Date: Thu, 21 Jul 2022 20:46:40 +0800 Subject: [PATCH] =?UTF-8?q?[docs=20add=20]Redis=203=20=E7=A7=8D=E7=89=B9?= =?UTF-8?q?=E6=AE=8A=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84=E8=AF=A6=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + docs/.vuepress/sidebar.ts | 1 + .../redis/redis-data-structures-01.md | 6 + .../redis/redis-data-structures-02.md | 139 ++++++++++++++++-- docs/database/redis/redis-questions-01.md | 18 ++- 5 files changed, 153 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index de53bdc2..8a8830c3 100755 --- a/README.md +++ b/README.md @@ -200,6 +200,7 @@ JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8 ](https://docs.oracle - [3种常用的缓存读写策略详解](docs/database/redis/3-commonly-used-cache-read-and-write-strategies.md) - [Redis 5 种基本数据结构详解](./docs/database/redis/redis-data-structures-01.md) +- [Redis 3 种特殊数据结构详解](./docs/database/redis/redis-data-structures-02.md) - [Redis 内存碎片详解](./docs/database/redis/redis-memory-fragmentation.md) - [Redis 集群详解](./docs/database/redis/redis-cluster.md) diff --git a/docs/.vuepress/sidebar.ts b/docs/.vuepress/sidebar.ts index e0a9de37..9c74761e 100644 --- a/docs/.vuepress/sidebar.ts +++ b/docs/.vuepress/sidebar.ts @@ -266,6 +266,7 @@ export const sidebarConfig = defineSidebarConfig({ children: [ "3-commonly-used-cache-read-and-write-strategies", "redis-data-structures-01", + "redis-data-structures-02", "redis-memory-fragmentation", "redis-cluster", ], diff --git a/docs/database/redis/redis-data-structures-01.md b/docs/database/redis/redis-data-structures-01.md index fc7782ef..b45b887e 100644 --- a/docs/database/redis/redis-data-structures-01.md +++ b/docs/database/redis/redis-data-structures-01.md @@ -3,6 +3,12 @@ title: Redis 5 种基本数据结构详解 category: 数据库 tag: - Redis +head: + - - meta + - name: keywords + content: Redis常见数据结构 + - name: description + content: Redis基础数据结构总结:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合) --- 你可以在 Redis 官网上找到 Redis 数据结构非常详细的介绍: diff --git a/docs/database/redis/redis-data-structures-02.md b/docs/database/redis/redis-data-structures-02.md index f7d437bf..27bfaadc 100644 --- a/docs/database/redis/redis-data-structures-02.md +++ b/docs/database/redis/redis-data-structures-02.md @@ -3,6 +3,12 @@ title: Redis 3 种特殊数据结构详解 category: 数据库 tag: - Redis +head: + - - meta + - name: keywords + content: Redis常见数据结构 + - name: description + content: Redis特殊数据结构总结:HyperLogLogs(基数统计)、Bitmap (位存储)、Geospatial (地理位置)。 --- ## Bitmap @@ -22,9 +28,9 @@ Bitmap 存储的是连续的二进制数字(0 和 1),通过 Bitmap, 只需 | SETBIT key offset value | 设置指定 offset 位置的值 | | GETBIT key offset | 获取指定 offset 位置的值 | | BITCOUNT key start end | 获取 start 和 end 之前值为 1 的元素个数 | -| BITOP operation destkey key1 key2 ... | 对一个或多个 Bitmap 进行运算,可用运算符有AND, OR, XOR以及NOT | - +| BITOP operation destkey key1 key2 ... | 对一个或多个 Bitmap 进行运算,可用运算符有 AND, OR, XOR 以及 NOT | +**Bitmap 基本操作演示** : ```bash # SETBIT 会返回之前位的值(默认是 0)这里会生成 7 个位 @@ -45,7 +51,7 @@ Bitmap 存储的是连续的二进制数字(0 和 1),通过 Bitmap, 只需 ### 应用场景 -**需要保存状态信息(0/1即可表示)的场景** +**需要保存状态信息(0/1 即可表示)的场景** - 举例 :用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)。 - 相关命令 :`SETBIT`、`GETBIT`、`BITCOUNT`、`BITOP`。 @@ -54,35 +60,146 @@ Bitmap 存储的是连续的二进制数字(0 和 1),通过 Bitmap, 只需 ### 介绍 -`HyperLogLog` 是一种有名的基数计数概率算法 ,并不是 Redis 特有的,Redis 只是实现了这个算法并提供了一些开箱即用的 API。 +HyperLogLog 是一种有名的基数计数概率算法 ,基于 LogLog Counting(LLC)优化改进得来,并不是 Redis 特有的,Redis 只是实现了这个算法并提供了一些开箱即用的 API。 -Redis 提供的 `HyperLogLog` 占用空间非常非常小,只需要 12k 的空间就能存储接近`2^64`个不同元素。这是真的厉害,这就是数学的魅力么!并且,Redis 对 HyperLogLog 的存储结构做了优化,采用两种方式计数: +Redis 提供的 HyperLogLog 占用空间非常非常小,只需要 12k 的空间就能存储接近`2^64`个不同元素。这是真的厉害,这就是数学的魅力么!并且,Redis 对 HyperLogLog 的存储结构做了优化,采用两种方式计数: - **稀疏矩阵** :计数较少的时候,占用空间很小。 - **稠密矩阵** :计数达到某个阈值的时候,占用 12k 的空间。 -不过, `HyperLogLog` 的计数结果并不是一个精确值,存在一定的误差(标准误差为 `0.81%` 。),这是由于它本质上是用概率算法导致的。 +Redis 官方文档中有对应的详细说明: + +![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/image-20220721091424563.png) + +基数计数概率算法为了节省内存并不会直接存储元数据,而是通过一定的概率统计方法预估基数值(集合中包含元素的个数)。因此, HyperLogLog 的计数结果并不是一个精确值,存在一定的误差(标准误差为 `0.81%` 。)。 ![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/image-20220720194154133.png) -`HyperLogLog` 的使用非常简单,但原理非常复杂。`HyperLogLog` 的原理以及在 Redis 中的实现可以看这篇文章:[HyperLogLog 算法的原理讲解以及 Redis 是如何应用它的](https://juejin.cn/post/6844903785744056333) 。 +HyperLogLog 的使用非常简单,但原理非常复杂。HyperLogLog 的原理以及在 Redis 中的实现可以看这篇文章:[HyperLogLog 算法的原理讲解以及 Redis 是如何应用它的](https://juejin.cn/post/6844903785744056333) 。 -再推荐一个可以帮助理解HyperLogLog原理的工具:[Sketch of the Day: HyperLogLog — Cornerstone of a Big Data Infrastructure](http://content.research.neustar.biz/blog/hll.html) 。 +再推荐一个可以帮助理解 HyperLogLog 原理的工具:[Sketch of the Day: HyperLogLog — Cornerstone of a Big Data Infrastructure](http://content.research.neustar.biz/blog/hll.html) 。 ### 常用命令 +HyperLogLog 相关的命令非常少,最常用的也就 3 个。 +| 命令 | 介绍 | +| ----------------------------------------- | ------------------------------------------------------------ | +| PFADD key element1 element2 ... | 添加一个或多个元素到 HyperLogLog 中 | +| PFCOUNT key1 key2 | 获取一个或者多个 HyperLogLog 的唯一计数。 | +| PFMERGE destkey sourcekey1 sourcekey2 ... | 将多个 HyperLogLog 合并到 destkey 中,destkey 会结合多个源,算出对应的唯一计数。 | + +**HyperLogLog 基本操作演示** : + +```bash +> PFADD hll foo bar zap +(integer) 1 +> PFADD hll zap zap zap +(integer) 0 +> PFADD hll foo bar +(integer) 0 +> PFCOUNT hll +(integer) 3 +> PFADD some-other-hll 1 2 3 +(integer) 1 +> PFCOUNT hll some-other-hll +(integer) 6 +> PFMERGE desthll hll some-other-hll +"OK" +> PFCOUNT desthll +(integer) 6 +``` ### 应用场景 +**数量量巨大(百万、千万级别以上)的计数场景** + +- 举例 :热门网站每日/每周/每月访问 ip 数统计、热门帖子 uv 统计、 +- 相关命令 :`PFADD`、`PFCOUNT` 。 + ## Geospatial index -地理空间数据管理。 +### 介绍 + +Geospatial index(地理空间索引,简称 GEO) 主要用于存储地理位置信息,基于 Sorted Set 实现。 + +通过 GEO 我们可以轻松实现两个位置距离的计算、获取指定位置附近的元素等功能。 ![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/image-20220720194359494.png) -## Stream +### 常用命令 + +| 命令 | 介绍 | +| ------------------------------------------------ | ------------------------------------------------------------ | +| GEOADD key longitude1 latitude1 member1 ... | 添加一个或多个元素对应的经纬度信息到 GEO 中 | +| GEOPOS key member1 member2 ... | 返回给定元素的经纬度信息 | +| GEODIST key member1 member2 M/KM/FT/MI | 返回两个给定元素之间的距离 | +| GEORADIUS key longitude latitude radius distance | 获取指定位置附近 distance 范围内的其他元素,支持 ASC(由近到远)、DESC(由远到近)、Count(数量) 等参数 | +| GEORADIUSBYMEMBER key member radius distance | 类似于 GEORADIUS 命令,只是参照的中心点是 GEO 中的元素 | + +**基本操作** : + +```bash +> GEOADD personLocation 116.33 39.89 user1 116.34 39.90 user2 116.35 39.88 user3 +3 +> GEOPOS personLocation user1 +116.3299986720085144 +39.89000061669732844 +> GEODIST personLocation user1 user2 km +1.4018 +``` + +通过 Redis 可视化工具查看 `personLocation` ,果不其然,底层就是 Sorted Set。 + +GEO 中存储的地理位置信息的经纬度数据通过 GeoHash 算法转换成了一个整数,这个整数作为 Sorted Set 的 score(权重参数)使用。 + +![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/image-20220721201545147.png) + +**获取指定位置范围内的其他元素** : + +```bash +> GEORADIUS personLocation 116.33 39.87 3 km +user3 +user1 +> GEORADIUS personLocation 116.33 39.87 2 km +> GEORADIUS personLocation 116.33 39.87 5 km +user3 +user1 +user2 +> GEORADIUSBYMEMBER personLocation user1 5 km +user3 +user1 +user2 +> GEORADIUSBYMEMBER personLocation user1 2 km +user1 +user2 +``` + +`GEORADIUS` 命令的底层原理解析可以看看阿里的这篇文章:[Redis 到底是怎么实现“附近的人”这个功能的呢?](https://juejin.cn/post/6844903966061363207) 。 + +**移除元素** : + +GEO 底层是 Sorted Set ,你可以对 GEO 使用 Sorted Set 相关的命令。 + +```bash +> ZREM personLocation user1 +1 +> ZRANGE personLocation 0 -1 +user3 +user2 +> ZSCORE personLocation user2 +4069879562983946 +``` + +### 应用场景 + +**需要管理使用地理空间数据的场景** + +- 举例:附近的人。 +- 相关命令: `GEOADD`、`GEORADIUS`、`GEORADIUSBYMEMBER` 。 ## 参考 -- \ No newline at end of file +- Redis Data Structures :https://redis.com/redis-enterprise/data-structures/ 。 +- 《Redis 深度历险:核心原理与应用实践》1.6 四两拨千斤——HyperLogLog +- 布隆过滤器,位图,HyperLogLog:https://hogwartsrico.github.io/2020/06/08/BloomFilter-HyperLogLog-BitMap/index.html \ No newline at end of file diff --git a/docs/database/redis/redis-questions-01.md b/docs/database/redis/redis-questions-01.md index 1767b5b1..75e2d754 100644 --- a/docs/database/redis/redis-questions-01.md +++ b/docs/database/redis/redis-questions-01.md @@ -122,7 +122,9 @@ Redis 5.0 新增加的一个数据结构 `Stream` 可以用来做消息队列, - **5 种基础数据结构** :String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。 - **3 种特殊数据结构** :HyperLogLogs(基数统计)、Bitmap (位存储)、Geospatial (地理位置)。 -关于 5 种基础数据类型的详细介绍请看这篇文章:[Redis 5 种基本数据结构详解](./redis-data-structures-01.md)。 +关于 5 种基础数据结构的详细介绍请看这篇文章:[Redis 5 种基本数据结构详解](./redis-data-structures-01.md)。 + +关于 3 种特殊数据结构的详细介绍请看这篇文章:[Redis 3 种特殊数据结构详解](./redis-data-structures-02.md)。 ### String 的应用场景有哪些? @@ -199,6 +201,20 @@ Redis 中有一个叫做 `sorted set` 的数据结构经常被用在各种排行 (integer) 2 ``` +### 使用 HyperLogLog 统计页面 UV 怎么做? + +1、将访问指定页面的每个用户 ID 添加到 `HyperLogLog` 中。 + +```bash +PFADD PAGE_1:UV USER1 USER2 ...... USERn +``` + +2、统计指定页面的 UV。 + +```bash +PFCOUNT PAGE_1:UV +``` + ## Redis 线程模型 ### Redis 单线程模型了解吗?