From b2351c877d92220206b60deb7491f8bded7ac0c9 Mon Sep 17 00:00:00 2001 From: Guide Date: Fri, 24 Mar 2023 17:34:58 +0800 Subject: [PATCH] =?UTF-8?q?[docs=20update]=E5=AE=8C=E5=96=84Redis=E4=BA=8B?= =?UTF-8?q?=E5=8A=A1=E7=9A=84=E4=BB=8B=E7=BB=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../redis/images/hash-shopping-cart.png | Bin 6801 -> 0 bytes .../redis/images/redis-event-handler.drawio | 2 +- .../redis/images/redis-event-handler.png | Bin 16790 -> 0 bytes .../redis/redis-data-structures-01.md | 2 +- docs/database/redis/redis-persistence.md | 16 +++- docs/database/redis/redis-questions-01.md | 75 ++++++++++++------ docs/database/redis/redis-questions-02.md | 75 +++++++++++++----- 7 files changed, 125 insertions(+), 45 deletions(-) delete mode 100644 docs/database/redis/images/hash-shopping-cart.png delete mode 100644 docs/database/redis/images/redis-event-handler.png diff --git a/docs/database/redis/images/hash-shopping-cart.png b/docs/database/redis/images/hash-shopping-cart.png deleted file mode 100644 index 9e7e838798d6a4c4823c66d89fb27e319be59b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6801 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 \ No newline at end of file +7Vtbc6s2EP41ekyG++XR2DjnnPa0meah7VNHARmTYOSCnNj99ZWEMGDJSZz4QjJMZhxpdQPtp0+7KwTM8WJ9U8Dl/CeOUQYMLV4DcwIMQ9c1h/5jkk0lcT2/EiRFGotKjeAu/Q8JoSakqzRGZaciwTgj6bIrjHCeo4h0ZLAo8HO32gxn3VGXMEGS4C6CmSz9M43JvH4vx28KvqE0mddDO7ZVldzD6DEp8CoXAwLDnDrT6dSrihew7ky8aTmHMX5uicwQmOMCY1KlFusxytjk1vNWtZvuKd0+eIFy8pYGqHzI/7m6/QNOYkxulsFVsfnlSvTyBLMVql+DPyzZ1DPEXxGxTnRgBs/zlKC7JYxY6TPFBJXNySITxTEs59u6M5yTKVykGcPGD0SCAqZ5SXv/iXMsyu/wquB9zQmhKjdsc0R/6EuwH1ahvE4wTjIEl2l5HeEFL4hKXnU6q3qnyXb/thGIEUpS4MetYumUB/Ks1VOACoLWLZGYxRuEF4gUdBCtLvWERgXkdUvkn1sAqrU+b2HH0oQQCtAm274bvdGEUN0BajRkNYY2GNnAd0HoAC9kaSaZMMmuhul7k64aq3kb4wwXVJLjHDF1pVm2I4JZmuQ0G9HZRFQesFlM6eoaiYJFGsdsGCVuGmRpKugIsjC0XkDpCMAxtB3gODJwPAVujJPBRpOwgGJKjyKLCzLHCc5hFjbSHa01dX7FeCm094AI2Qj1wRXBXXDRCSw2f4n2PPM3y1zbdXaybhdONiLXwoTu9AITB9BLWT/IPl2YYvODRYLIC/XE8mV6ehFzBcogSZ+629zREWRKxFPi6BERXQZWltE9fR8VtOAhqblFO3SPjSHyZtFejro4Jo6xwfh2hye2vNHmCVvmCfdkPKFQ58ATl+EJ61I8wZuOigJuWhWWOKVz0+r5lgkaKJt6d8szzR0j9bD6NFE9QYPl7au8H97WHhKTbeGBxN5NYubFSUyhztOT2NcmI/skJCOxgqWpWWHbRcWGolWDk4PZyuqOY7n2y2xlXYCt7D1s9dvAVsdzzSyFT39WtnIkLcvqzeMRi4A1qui40DtRmVtIqIuec4mhmUoi+ERe96uU01KcrfCpa9kHmckw3evuPmfteusViUrcpOqqSyb+20juWLximIOR35d91X2jke8de//9EGe5Emd9p/38TkU89mgBfwRCDwQuGE2FxJuA0AW+BUYeS9BfL2BFwQh4UwmPB4WiJTLrbmqzGXKir72pSWaTwgTXVQFH51S7mifvaqEDfAd4LggtEAQgcHhixHGwldjAo8hwWOWACkMm8X0Gl9NCZGZ8cYg4ft8g4r9u+AwnUjta9J2uFnVToUVHoUXrZPZrHcfpLHXVwmabgMU3AY2v8H0LezikOg8j+F7XntVdBZZ0BZZOdkqly/G5wRfqoS+kazvhENt7pyuka6a/41bZ9nm9IV0Os3Bu0kEwEfxFmYtas9SUDfghe6ADzziE0d5rqqhCNEiPbeR+aVPFd3dOxWoVtYnJPKepoiuCNAqMUEkA/LDl8QwYORNGlObseTEiO8XcB55yRLQ+zaGWkc8Rwb7RsQaMnA8j3sUxonKLKX14jEEqHqEwUaJmwMhZMGIpvtQ6L0YMS7Z5h+jsZaKzYnm9Gp3Vj348+jEI2QOEPh2EnH5ByBkg9Okg1K8vRg35+/MBQn2HUL/OGQ2FvWw4GRHz3wGX8+8K1wVXJdck1YamO8t1U0hTCf/PDpqoUT3mVveY356w2UEki/BMuWT0Az7BG3ZpqR7yvmiau8zzp/4/c+MCZorXrR5oK37V6TrK64agQsO2dT8j3hm8R1mwveuksPbr9eGJfMtVCPgf75NQYOBcdFo+IhLN60x9MarnYda3uw+22Q2EGqobQqpTNf1w94FmmztkVfSzualnhv8D \ No newline at end of file diff --git a/docs/database/redis/images/redis-event-handler.png b/docs/database/redis/images/redis-event-handler.png deleted file mode 100644 index a9f85a51e7400b61a0e6379b2970e46a62deccdb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16790 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 AOF 重写期间的增量数据如何处理一直是个问题,在过去写期间的增量数据需要在内存中保留,写结束后再把这部分增量数据写入新的AOF文件中以保证数据完整性。可以看出来AOF 写会额外消耗内存和磁盘IO,这也是Redis AOF 写的痛点,虽然之前也进行过多次改进但是资源消耗的本质问题一直没有解决。 +> +> 阿里云的Redis企业版在最初也遇到了这个问题,在内部经过多次迭代开发,实现了Multi-part AOF机制来解决,同时也贡献给了社区并随此次7.0发布。具体方法是采用base(全量数据)+inc(增量数据)独立文件存储的方式,彻底解决内存和IO资源的浪费,同时也支持对历史AOF文件的保存管理,结合AOF文件中的时间信息还可以实现PITR按时间点恢复(阿里云企业版Tair已支持),这进一步增强了Redis的数据可靠性,满足用户数据回档等需求。 + **相关 issue** :[Redis AOF 重写描述不准确 #1439](https://github.com/Snailclimb/JavaGuide/issues/1439) ## Redis 4.0 对于持久化机制做了什么优化? @@ -151,4 +157,10 @@ Redis 7.0 版本之前,如果在重写期间有写入命令,AOF 可能会使 - Redis 保存的数据丢失一些也没什么影响的话,可以选择使用 RDB。 - 不建议单独使用 AOF,因为时不时地创建一个 RDB 快照可以进行数据库备份、更快的重启以及解决 AOF 引擎错误。 -- 如果保存的数据要求安全性比较高的话,建议同时开启 RDB 和 AOF 持久化或者开启 RDB 和 AOF 混合持久化。 \ No newline at end of file +- 如果保存的数据要求安全性比较高的话,建议同时开启 RDB 和 AOF 持久化或者开启 RDB 和 AOF 混合持久化。 + +## 参考 + +- Redis persistence - Redis 官方文档:https://redis.io/docs/management/persistence/ +- The difference between AOF and RDB persistence:https://www.sobyte.net/post/2022-04/redis-rdb-and-aof/ +- Redis AOF 持久化详解 - 程序员历小冰:http://remcarpediem.net/article/376c55d8/ \ 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 2c1464ac..0516fd13 100644 --- a/docs/database/redis/redis-questions-01.md +++ b/docs/database/redis/redis-questions-01.md @@ -18,11 +18,11 @@ head: [Redis](https://redis.io/) 是一个基于 C 语言开发的开源数据库(BSD 许可),与传统数据库不同的是 Redis 的数据是存在内存中的(内存数据库),读写速度非常快,被广泛应用于缓存方向。并且,Redis 存储的是 KV 键值对数据。 -为了满足不同的业务场景,Redis 内置了多种数据类型实现(比如 String、Hash、Sorted Set、Bitmap)。并且,Redis 还支持事务 、持久化、Lua 脚本、多种开箱即用的集群方案(Redis Sentinel、Redis Cluster)。 +为了满足不同的业务场景,Redis 内置了多种数据类型实现(比如 String、Hash、Sorted Set、Bitmap、HyperLogLog、GEO)。并且,Redis 还支持事务 、持久化、Lua 脚本、多种开箱即用的集群方案(Redis Sentinel、Redis Cluster)。 Redis 没有外部依赖,Linux 和 OS X 是 Redis 开发和测试最多的两个操作系统,官方推荐生产环境使用 Linux 部署 Redis。 -个人学习的话,你可以自己本机安装 Redis 或者通过 Redis 官网提供的[在线 Redis 环境](https://try.redis.io/)来实际体验 Redis。 +个人学习的话,你可以自己本机安装 Redis 或者通过 Redis 官网提供的[在线 Redis 环境](https://try.redis.io/)(少部分命令无法使用)来实际体验 Redis。 ![try-redis](https://oss.javaguide.cn/github/javaguide/database/redis/try.redis.io.png) @@ -30,11 +30,11 @@ Redis 没有外部依赖,Linux 和 OS X 是 Redis 开发和测试最多的两 ### Redis 为什么这么快? -Redis 内部做了非常多的性能优化,比较重要的主要有下面 3 点: +Redis 内部做了非常多的性能优化,比较重要的有下面 3 点: -- Redis 基于内存,内存的访问速度是磁盘的上千倍; -- Redis 基于 Reactor 模式设计开发了一套高效的事件处理模型,主要是单线程事件循环和 IO 多路复用(Redis 线程模式后面会详细介绍到); -- Redis 内置了多种优化过后的数据结构实现,性能非常高。 +1. Redis 基于内存,内存的访问速度是磁盘的上千倍; +2. Redis 基于 Reactor 模式设计开发了一套高效的事件处理模型,主要是单线程事件循环和 IO 多路复用(Redis 线程模式后面会详细介绍到); +3. Redis 内置了多种优化过后的数据结构实现,性能非常高。 下面这张图片总结的挺不错的,分享一下,出自 [Why is Redis so fast?](https://twitter.com/alexxubyte/status/1498703822528544770) 。 @@ -69,7 +69,7 @@ Memcached 是分布式缓存最开始兴起的那会,比较常用的。后来 3. **Redis 有灾难恢复机制。** 因为可以把缓存中的数据持久化到磁盘上。 4. **Redis 在服务器内存使用完之后,可以将不用的数据放到磁盘上。但是,Memcached 在服务器内存使用完之后,就会直接报异常。** 5. **Memcached 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;但是 Redis 目前是原生支持 cluster 模式的。** -6. **Memcached 是多线程,非阻塞 IO 复用的网络模型;Redis 使用单线程的多路 IO 复用模型。** (Redis 6.0 引入了多线程 IO ) +6. **Memcached 是多线程,非阻塞 IO 复用的网络模型;Redis 使用单线程的多路 IO 复用模型。** (Redis 6.0 针对网络数据的读写引入了多线程) 7. **Redis 支持发布订阅模型、Lua 脚本、事务等功能,而 Memcached 不支持。并且,Redis 支持更多的编程语言。** 8. **Memcached 过期数据的删除策略只用了惰性删除,而 Redis 同时使用了惰性删除与定期删除。** @@ -79,13 +79,13 @@ Memcached 是分布式缓存最开始兴起的那会,比较常用的。后来 下面我们主要从“高性能”和“高并发”这两点来回答这个问题。 -**高性能** +**1、高性能** 假如用户第一次访问数据库中的某些数据的话,这个过程是比较慢,毕竟是从硬盘中读取的。但是,如果说,用户访问的数据属于高频数据并且不会经常改变的话,那么我们就可以很放心地将该用户访问的数据存在缓存中。 **这样有什么好处呢?** 那就是保证用户下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。 -**高并发** +**2、高并发** 一般像 MySQL 这类的数据库的 QPS 大概都在 1w 左右(4 核 8g) ,但是使用 Redis 缓存之后很容易达到 10w+,甚至最高能达到 30w+(就单机 Redis 的情况,Redis 集群的话会更高)。 @@ -115,6 +115,8 @@ Memcached 是分布式缓存最开始兴起的那会,比较常用的。后来 > 实际项目中也没见谁使用 Redis 来做消息队列,对于这部分知识点大家了解就好了。 +先说结论:可以是可以,但不建议使用 Redis 来做消息队列。和专业的消息队列相比,还是有很多欠缺的地方。 + **Redis 2.0 之前,如果想要使用 Redis 来做消息队列的话,只能通过 List 来实现。** 通过 `RPUSH/LPOP` 或者 `LPUSH/RPOP`即可实现简易版消息队列 : @@ -145,7 +147,7 @@ null **Redis 2.0 引入了 发布订阅 (pub/sub) 解决了 List 实现消息队列没有广播机制的问题。** -pub/sub 中引入了一个概念叫 channel(频道),发布订阅机制的实现就是基于这个 channel 来做的。 +pub/sub 中引入了一个概念叫 **channel(频道)**,发布订阅机制的实现就是基于这个 channel 来做的。 pub/sub 涉及发布者和订阅者(也叫消费者)两个角色: @@ -184,7 +186,11 @@ pub/sub 既能单播又能广播,还支持 channel 的简单正则匹配。不 ### String 的应用场景有哪些? -- 常规数据(比如 session、token、、序列化后的对象)的缓存; +String 是 Redis 中最简单同时也是最常用的一个数据结构。String 是一种二进制安全的数据结构,可以用来存储任何类型的数据比如字符串、整数、浮点数、图片(图片的 base64 编码或者解码或者图片的路径)、序列化后的对象。 + +String 的常见应用场景如下: + +- 常规数据(比如 session、token、序列化后的对象、图片的路径)的缓存; - 计数比如用户单位时间的请求数(简单限流可以用到)、页面单位时间的访问数; - 分布式锁(利用 `SETNX key value` 命令可以实现一个最简易的分布式锁); - ...... @@ -282,7 +288,7 @@ struct sdshdr { - 用户 id 为 key - 商品 id 为 field,商品数量为 value -![Hash维护简单的购物车信息](./images/hash-shopping-cart.png) +![Hash维护简单的购物车信息](https://oss.javaguide.cn/github/javaguide/database/redis/hash-shopping-cart.png) 那用户购物车信息的维护具体应该怎么操作呢? @@ -302,18 +308,37 @@ Redis 中有一个叫做 `sorted set` 的数据结构经常被用在各种排行 ![](https://oss.javaguide.cn/github/javaguide/database/redis/2021060714195385.png) -[《Java 面试指北》](https://javaguide.cn/zhuanlan/java-mian-shi-zhi-bei.html) 的「技术面试题篇」就有一篇文章详细介绍如何使用 Sorted Set 来设计制作一个排行榜。 +[《Java 面试指北》](https://javaguide.cn/zhuanlan/java-mian-shi-zhi-bei.html) 的「技术面试题篇」就有一篇文章详细介绍如何使用 Sorted Set 来设计制作一个排行榜,感兴趣的小伙伴可以看看。 ![](https://oss.javaguide.cn/github/javaguide/database/redis/image-20220719071115140.png) -### 使用 Set 实现抽奖系统需要用到什么命令? +### Set 的应用场景是什么? +Redis 中 `Set` 是一种无序集合,集合中的元素没有先后顺序但都唯一,有点类似于 Java 中的 `HashSet` 。 + +Set 的常见应用场景如下: + +- 存放的数据不能重复的场景:网站 UV 统计(数据量巨大的场景还是 `HyperLogLog`更适合一些)、文章点赞、动态点赞等等。 +- 需要获取多个数据源交集、并集和差集的场景:共同好友(交集)、共同粉丝(交集)、共同关注(交集)、好友推荐(差集)、音乐推荐(差集) 、订阅号推荐(差集+交集) 等等。 +- 需要随机获取数据源中的元素的场景:抽奖系统、随机点名等等。 + +### 使用 Set 实现抽奖系统怎么做? + +如果想要使用 Set 实现一个简单的抽奖系统的话,直接使用下面这几个命令就可以了: + +- `SADD key member1 member2 ...`:向指定集合添加一个或多个元素。 - `SPOP key count` : 随机移除并获取指定集合中一个或多个元素,适合不允许重复中奖的场景。 - `SRANDMEMBER key count` : 随机获取指定集合中指定数量的元素,适合允许重复中奖的场景。 ### 使用 Bitmap 统计活跃用户怎么做? -使用日期(精确到天)作为 key,然后用户 ID 为 offset,如果当日活跃过就设置为 1。 +Bitmap 存储的是连续的二进制数字(0 和 1),通过 Bitmap, 只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身 。我们知道 8 个 bit 可以组成一个 byte,所以 Bitmap 本身会极大的节省储存空间。 + +你可以将 Bitmap 看作是一个存储二进制数字(0 和 1)的数组,数组中每个元素的下标叫做 offset(偏移量)。 + +![img](https://oss.javaguide.cn/github/javaguide/database/redis/image-20220720194154133.png) + +如果想要使用 Bitmap 统计活跃用户的话,可以使用日期(精确到天)作为 key,然后用户 ID 为 offset,如果当日活跃过就设置为 1。 初始化数据: @@ -346,6 +371,11 @@ Redis 中有一个叫做 `sorted set` 的数据结构经常被用在各种排行 ### 使用 HyperLogLog 统计页面 UV 怎么做? +使用 HyperLogLog 统计页面 UV主要需要用到下面这两个命令: + +- `PFADD key element1 element2 ...`:添加一个或多个元素到 HyperLogLog 中。 +- `PFCOUNT key1 key2`:获取一个或者多个 HyperLogLog 的唯一计数。 + 1、将访问指定页面的每个用户 ID 添加到 `HyperLogLog` 中。 ```bash @@ -358,7 +388,11 @@ PFADD PAGE_1:UV USER1 USER2 ...... USERn PFCOUNT PAGE_1:UV ``` -## Redis 线程模型 +## Redis 持久化机制(重要) + +Redis 持久化机制(RDB 持久化、AOF 持久化、RDB 和 AOF 的混合持久化) 相关的问题比较多,也比较重要,于是我单独抽了一篇文章来总结 Redis 持久化机制相关的知识点和问题: [Redis 持久化机制详解](./redis-persistence.md) 。 + +## Redis 线程模型(重要) 对于读写命令来说,Redis 一直是单线程模型。不过,在 Redis 4.0 版本之后引入了多线程来执行一些大键值对的异步删除操作, Redis 6.0 版本之后引入了多线程来处理网络请求(提高网络 IO 读写性能)。 @@ -388,7 +422,7 @@ Redis 通过 **IO 多路复用程序** 来监听来自客户端的大量连接 - 文件事件分派器(将 socket 关联到相应的事件处理器) - 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器) -![文件事件处理器](https://oss.javaguide.cn/github/javaguide/database/redis/redis-event-handler.png) +![文件事件处理器(file event handler)](https://oss.javaguide.cn/github/javaguide/database/redis/redis-event-handler.png) 相关阅读:[Redis 事件机制详解](http://remcarpediem.net/article/1aa2da89/) 。 @@ -520,15 +554,10 @@ Redis 提供 6 种数据淘汰策略: 7. **volatile-lfu(least frequently used)**:从已设置过期时间的数据集(`server.db[i].expires`)中挑选最不经常使用的数据淘汰。 8. **allkeys-lfu(least frequently used)**:当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key。 -## Redis 持久化机制 - -Redis 持久化机制(RDB 持久化、AOF 持久化、RDB 和 AOF 的混合持久化) 相关的问题比较多,也比较重要,于是我单独抽了一篇文章来总结 Redis 持久化机制相关的知识点和问题: [Redis 持久化机制详解](./redis-persistence.md) 。 - ## 参考 - 《Redis 开发与运维》 - 《Redis 设计与实现》 - Redis 命令手册:https://www.redis.com.cn/commands.html - WHY Redis choose single thread (vs multi threads): [https://medium.com/@jychen7/sharing-redis-single-thread-vs-multi-threads-5870bd44d153](https://medium.com/@jychen7/sharing-redis-single-thread-vs-multi-threads-5870bd44d153) -- The difference between AOF and RDB persistence:https://www.sobyte.net/post/2022-04/redis-rdb-and-aof/ -- Redis AOF 持久化详解 - 程序员历小冰:http://remcarpediem.net/article/376c55d8/ + diff --git a/docs/database/redis/redis-questions-02.md b/docs/database/redis/redis-questions-02.md index 9651d36a..3a5b5c72 100644 --- a/docs/database/redis/redis-questions-02.md +++ b/docs/database/redis/redis-questions-02.md @@ -14,9 +14,19 @@ head: ## Redis 事务 +### 什么是 Redis 事务? + +你可以将 Redis 中的事务理解为 :**Redis 事务提供了一种将多个命令请求打包的功能。然后,再按顺序执行打包的所有命令,并且不会被中途打断。** + +Redis 事务实际开发中使用的非常少,功能比较鸡肋,不要将其和我们平时理解的关系型数据库的事务混淆了。 + +除了不满足原子性和持久性之外,事务中的每条命令都会与 Redis 服务器进行网络交互,这是比较浪费资源的行为。明明一次批量执行多个命令就可以了,这种操作实在是看不懂。 + +因此,Redis 事务是不建议在日常开发中使用的。 + ### 如何使用 Redis 事务? -Redis 可以通过 **`MULTI`,`EXEC`,`DISCARD` 和 `WATCH`** 等命令来实现事务(transaction)功能。 +Redis 可以通过 **`MULTI`,`EXEC`,`DISCARD` 和 `WATCH`** 等命令来实现事务(Transaction)功能。 ```bash > MULTI @@ -131,22 +141,36 @@ Redis 的事务和我们平时理解的关系型数据库的事务不同。我 3. **持久性(Durability):** 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。 4. **一致性(Consistency):** 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的; -Redis 事务在运行错误的情况下,除了执行过程中出现错误的命令外,其他命令都能正常执行。并且,Redis 事务是不支持回滚(roll back)操作的。因此,Redis 事务其实是不满足原子性的(而且不满足持久性)。 +Redis 事务在运行错误的情况下,除了执行过程中出现错误的命令外,其他命令都能正常执行。并且,Redis 事务是不支持回滚(roll back)操作的。因此,Redis 事务其实是不满足原子性的。 Redis 官网也解释了自己为啥不支持回滚。简单来说就是 Redis 开发者们觉得没必要支持回滚,这样更简单便捷并且性能更好。Redis 开发者觉得即使命令执行错误也应该在开发过程中就被发现而不是生产过程中。 ![Redis 为什么不支持回滚](https://oss.javaguide.cn/github/javaguide/database/redis/redis-rollback.png) -你可以将 Redis 中的事务就理解为 :**Redis 事务提供了一种将多个命令请求打包的功能。然后,再按顺序执行打包的所有命令,并且不会被中途打断。** - -除了不满足原子性之外,事务中的每条命令都会与 Redis 服务器进行网络交互,这是比较浪费资源的行为。明明一次批量执行多个命令就可以了,这种操作实在是看不懂。 - -因此,Redis 事务是不建议在日常开发中使用的。 - **相关 issue** : -- [issue452: 关于 Redis 事务不满足原子性的问题](https://github.com/Snailclimb/JavaGuide/issues/452) 。 -- [Issue491:关于 redis 没有事务回滚?](https://github.com/Snailclimb/JavaGuide/issues/491) +- [issue#452: 关于 Redis 事务不满足原子性的问题](https://github.com/Snailclimb/JavaGuide/issues/452) 。 +- [Issue#491:关于 Redis 没有事务回滚?](https://github.com/Snailclimb/JavaGuide/issues/491) + +### Redis 事务支持持久性吗? + +Redis 不同于 Memcached 的很重要一点就是,Redis 支持持久化,而且支持 3 种持久化方式: + +- 快照(snapshotting,RDB) +- 只追加文件(append-only file, AOF) +- RDB 和 AOF 的混合持久化(Redis 4.0 新增) + +与 RDB 持久化相比,AOF 持久化的实时性更好。在 Redis 的配置文件中存在三种不同的 AOF 持久化方式( `fsync`策略),它们分别是: + +```bash +appendfsync always #每次有数据修改发生时都会调用fsync函数同步AOF文件,fsync完成后线程返回,这样会严重降低Redis的速度 +appendfsync everysec #每秒钟调用fsync函数同步一次AOF文件 +appendfsync no #让操作系统决定何时进行同步,一般为30秒一次 +``` + +AOF 持久化的`fsync`策略为 no 、everysec 时都会存在数据丢失的情况 。always 下可以基本是可以满足持久性要求的,但性能太差,实际开发过程中不会使用。 + +因此,Redis 事务的持久性也是没办法保证的。 ### 如何解决 Redis 事务的缺陷? @@ -160,7 +184,7 @@ Redis 从 2.6 版本开始支持执行 Lua 脚本,它的功能和事务非常 另外,Redis 7.0 新增了 [Redis functions](https://redis.io/docs/manual/programmability/functions-intro/) 特性,你可以将 Redis functions 看作是比 Lua 更强大的脚本。 -## Redis 性能优化 +## Redis 性能优化(重要) ### 使用批量操作减少网络传输 @@ -173,7 +197,9 @@ Redis 从 2.6 版本开始支持执行 Lua 脚本,它的功能和事务非常 其中,第 1 步和第 4 步耗费时间之和称为 **Round Trip Time (RTT,往返时间)** ,也就是数据在网络上传输的时间。 -**使用批量操作可以减少网络传输次数,进而有效减小网络开销,大幅减少 RTT。** +使用批量操作可以减少网络传输次数,进而有效减小网络开销,大幅减少 RTT。 + +另外,除了能减少 RTT 之外,发送一次命令的 socket I/O 成本也比较高(涉及上下文切换,存在`read()`和`write()`系统调用),批量操作还可以减少 socket I/O 成本。这个在官方对 pipeline 的介绍中有提到:https://redis.io/docs/manual/pipelining/ 。 #### 原生批量操作命令 @@ -206,19 +232,31 @@ Redis 中有一些原生支持批量操作的命令,比如: 原生批量操作命令和 pipeline 的是有区别的,使用的时候需要注意: -- 原生批量操作命令是原子操作,pipeline 是非原子操作; -- pipeline 可以打包不同的命令,原生批量操作命令不可以; +- 原生批量操作命令是原子操作,pipeline 是非原子操作。 +- pipeline 可以打包不同的命令,原生批量操作命令不可以。 - 原生批量操作命令是 Redis 服务端支持实现的,而 pipeline 需要服务端和客户端的共同实现。 +顺带补充一下 pipeline 和 Redis 事务的对比: + +- 事务是原子操作,pipeline 是非原子操作。两个不同的事务不会同时运行,而 pipeline 可以同时以交错方式执行。 +- Redis 事务中每个命令都需要发送到服务端,而 Pipeline 只需要发送一次,请求次数更少。 + +> 事务可以看作是一个原子操作,但其实并不满足原子性。当我们提到 Redis 中的原子操作时,主要指的是这个操作(比如事务、Lua 脚本)不会被其他操作(比如其他事务、Lua 脚本)打扰,并不能完全保证这个操作中的所有写命令要么都执行要么都不执行。这主要也是因为 Redis 是不支持回滚操作。 + +![](https://oss.javaguide.cn/github/javaguide/database/redis/redis-pipeline-vs-transaction.png) + 另外,pipeline 不适用于执行顺序有依赖关系的一批命令。就比如说,你需要将前一个命令的结果给后续的命令使用,pipeline 就没办法满足你的需求了。对于这种需求,我们可以使用 **Lua 脚本** 。 #### Lua 脚本 -Lua 脚本同样支持批量操作多条命令。一段 Lua 脚本可以视作一条命令执行,可以看作是原子操作。一段 Lua 脚本执行过程中不会有其他脚本或 Redis 命令同时执行,保证了操作不会被其他指令插入或打扰,这是 pipeline 所不具备的。 +Lua 脚本同样支持批量操作多条命令。一段 Lua 脚本可以视作一条命令执行,可以看作是 **原子操作** 。也就是说,一段 Lua 脚本执行过程中不会有其他脚本或 Redis 命令同时执行,保证了操作不会被其他指令插入或打扰,这是 pipeline 所不具备的。 并且,Lua 脚本中支持一些简单的逻辑处理比如使用命令读取值并在 Lua 脚本中进行处理,这同样是 pipeline 所不具备的。 -不过, Redis Cluster 下 Lua 脚本的原子操作也无法保证了,原因同样是无法保证所有的 key 都在同一个 **hash slot**(哈希槽)上。 +不过, Lua 脚本依然存在下面这些缺陷: + +- 如果 Lua 脚本运行时出错并中途结束,之后的操作不会进行,但是之前已经发生的写操作不会撤销,所以即使使用了 Lua 脚本,也不能实现类似数据库回滚的原子性。 +- Redis Cluster 下 Lua 脚本的原子操作也无法保证了,原因同样是无法保证所有的 key 都在同一个 **hash slot**(哈希槽)上。 ### 大量 key 集中过期问题 @@ -293,7 +331,7 @@ Biggest string found '"ballcat:oauth:refresh_auth:f6cdb384-9a9d-4f2f-af01-dc3f28 **参考答案** :[Redis 内存碎片详解](https://javaguide.cn/database/redis/redis-memory-fragmentation.html)。 -## Redis 生产问题 +## Redis 生产问题(重要) ### 缓存穿透 @@ -480,4 +518,5 @@ Cache Aside Pattern 中遇到写请求是这样的:更新 DB,然后直接删 - 《Redis 开发与运维》 - 《Redis 设计与实现》 -- Redis Transactions : https://redis.io/docs/manual/transactions/ 。 \ No newline at end of file +- Redis Transactions : https://redis.io/docs/manual/transactions/ +- What is Redis Pipeline:https://buildatscale.tech/what-is-redis-pipeline/ \ No newline at end of file