1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-16 18:10:13 +08:00

[docs improve]redis部分图片重新绘制

This commit is contained in:
guide 2022-08-21 20:53:45 +08:00
parent 26e92a4e79
commit 8f72d69440
31 changed files with 53 additions and 56 deletions

View File

@ -12,105 +12,106 @@ tag:
但是搞懂3种常见的缓存读写策略对于实际工作中使用缓存以及面试中被问到缓存都是非常有帮助的 但是搞懂3种常见的缓存读写策略对于实际工作中使用缓存以及面试中被问到缓存都是非常有帮助的
下面我会简单介绍一下自己对于这 3 种缓存读写策略的理解。 **下面介绍到的三种模式各有优劣,不存在最佳模式,根据具体的业务场景选择适合自己的缓存读写模式。**
另外,**这3 种缓存读写策略各有优劣,不存在最佳,需要我们根据具体的业务场景选择更适合的。**
*个人能力有限。如果文章有任何需要补充/完善/修改的地方,欢迎在评论区指出,共同进步!——爱你们的 Guide 哥*
### Cache Aside Pattern旁路缓存模式 ### Cache Aside Pattern旁路缓存模式
**Cache Aside Pattern 是我们平时使用比较多的一个缓存读写模式,比较适合读请求比较多的场景。** **Cache Aside Pattern 是我们平时使用比较多的一个缓存读写模式,比较适合读请求比较多的场景。**
Cache Aside Pattern 中服务端需要同时维系 DB 和 cache并且是以 DB 的结果为准。 Cache Aside Pattern 中服务端需要同时维系 db 和 cache并且是以 db 的结果为准。
下面我们来看一下这个策略模式下的缓存读写步骤。 下面我们来看一下这个策略模式下的缓存读写步骤。
**写** **写**
- 先更新 DB - 先更新 db
- 然后直接删除 cache 。 - 然后直接删除 cache 。
简单画了一张图帮助大家理解写的步骤。 简单画了一张图帮助大家理解写的步骤。
![](https://img-blog.csdnimg.cn/img_convert/5687fe759a1dac9ed9554d27e3a23b6d.png) ![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/cache-aside-write.png)
**读** : **读** :
- 从 cache 中读取数据,读取到就直接返回 - 从 cache 中读取数据,读取到就直接返回
- cache中读取不到的话,就从 DB 中读取数据返回 - cache 中读取不到的话,就从 db 中读取数据返回
- 再把数据放到 cache 中。 - 再把数据放到 cache 中。
简单画了一张图帮助大家理解读的步骤。 简单画了一张图帮助大家理解读的步骤。
![](https://img-blog.csdnimg.cn/img_convert/a8c18b5f5b1aed03234bcbbd8c173a87.png) ![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/cache-aside-read.png)
你仅仅了解了上面这些内容的话是远远不够的,我们还要搞懂其中的原理。 你仅仅了解了上面这些内容的话是远远不够的,我们还要搞懂其中的原理。
比如说面试官很可能会追问:“**在写数据的过程中,可以先删除 cache ,后更新 DB 么?**” 比如说面试官很可能会追问:“**在写数据的过程中,可以先删除 cache ,后更新 db 么?**”
**答案:** 那肯定是不行的!因为这样可能会造成**数据库DB和缓存Cache数据不一致**的问题。为什么呢比如说请求1 先写数据A请求2随后读数据A的话就很有可能产生数据不一致性的问题。这个过程可以简单描述为 **答案:** 那肯定是不行的!因为这样可能会造成 **数据库db和缓存Cache数据不一致**的问题。
> 请求1先把cache中的A数据删除 -> 请求2从DB中读取数据->请求1再把DB中的A数据更新 举例:请求 1 先写数据 A请求 2 随后读数据 A 的话,就很有可能产生数据不一致性的问题
当你这样回答之后,面试官可能会紧接着就追问:“**在写数据的过程中先更新DB后删除cache就没有问题了么**” 这个过程可以简单描述为:
**答案:** 理论上来说还是可能会出现数据不一致性的问题,不过概率非常小,因为缓存的写入速度是比数据库的写入速度快很多! > 请求 1 先把 cache 中的 A 数据删除 -> 请求 2 从 db 中读取数据->请求 1 再把 db 中的 A 数据更新
比如请求1先读数据 A请求2随后写数据A并且数据A不在缓存中的话也有可能产生数据不一致性的问题。这个过程可以简单描述为 当你这样回答之后,面试官可能会紧接着就追问:“**在写数据的过程中,先更新 db后删除 cache 就没有问题了么?**”
> 请求1从DB读数据A->请求2写更新数据 A 到数据库并把删除cache中的A数据->请求1将数据A写入cache。 **答案:** 理论上来说还是可能会出现数据不一致性的问题,不过概率非常小,因为缓存的写入速度是比数据库的写入速度快很多。
举例:请求 1 先读数据 A请求 2 随后写数据 A并且数据 A 在请求 1 请求之前不在缓存中的话,也有可能产生数据不一致性的问题。
这个过程可以简单描述为:
> 请求 1 从 db 读数据 A-> 请求 2 更新 db 中的数据 A此时缓存中无数据 A ,故不用执行删除缓存操作 -> 请求 1 将数据 A 写入 cache
现在我们再来分析一下 **Cache Aside Pattern 的缺陷** 现在我们再来分析一下 **Cache Aside Pattern 的缺陷**
**缺陷1首次请求数据一定不在 cache 的问题** **缺陷 1首次请求数据一定不在 cache 的问题**
解决办法可以将热点数据可以提前放入cache 中。 解决办法:可以将热点数据可以提前放入 cache 中。
**缺陷2写操作比较频繁的话导致cache中的数据会被频繁被删除这样会影响缓存命中率 。** **缺陷 2写操作比较频繁的话导致 cache 中的数据会被频繁被删除,这样会影响缓存命中率 。**
解决办法: 解决办法:
- 数据库和缓存数据强一致场景 :更新DB的时候同样更新cache不过我们需要加一个锁/分布式锁来保证更新cache的时候不存在线程安全问题。 - 数据库和缓存数据强一致场景 :更新 db 的时候同样更新 cache不过我们需要加一个锁/分布式锁来保证更新 cache 的时候不存在线程安全问题。
- 可以短暂地允许数据库和缓存数据不一致的场景 :更新DB的时候同样更新cache但是给缓存加一个比较短的过期时间这样的话就可以保证即使数据不一致的话影响也比较小。 - 可以短暂地允许数据库和缓存数据不一致的场景 :更新 db 的时候同样更新 cache但是给缓存加一个比较短的过期时间这样的话就可以保证即使数据不一致的话影响也比较小。
### Read/Write Through Pattern读写穿透 ### Read/Write Through Pattern读写穿透
Read/Write Through Pattern 中服务端把 cache 视为主要数据存储从中读取数据并将数据写入其中。cache 服务负责将此数据读取和写入 DB,从而减轻了应用程序的职责。 Read/Write Through Pattern 中服务端把 cache 视为主要数据存储从中读取数据并将数据写入其中。cache 服务负责将此数据读取和写入 db,从而减轻了应用程序的职责。
这种缓存读写策略小伙伴们应该也发现了在平时在开发过程中非常少见。抛去性能方面的影响,大概率是因为我们经常使用的分布式缓存 Redis 并没有提供 cache 将数据写入DB的功能。 这种缓存读写策略小伙伴们应该也发现了在平时在开发过程中非常少见。抛去性能方面的影响,大概率是因为我们经常使用的分布式缓存 Redis 并没有提供 cache 将数据写入 db 的功能。
**写Write Through** **写Write Through**
- 先查 cachecache 中不存在,直接更新 DB - 先查 cachecache 中不存在,直接更新 db
- cache 中存在,则先更新 cache然后 cache 服务自己更新 DB**同步更新 cache 和 DB**)。 - cache 中存在,则先更新 cache然后 cache 服务自己更新 db**同步更新 cache 和 db**)。
简单画了一张图帮助大家理解写的步骤。 简单画了一张图帮助大家理解写的步骤。
![](https://img-blog.csdnimg.cn/20210201100340808.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0MzM3Mjcy,size_16,color_FFFFFF,t_70) ![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/write-through.png)
**读(Read Through)** **读(Read Through)**
- 从 cache 中读取数据,读取到就直接返回 。 - 从 cache 中读取数据,读取到就直接返回 。
- 读取不到的话,先从 DB 加载,写入到 cache 后返回响应。 - 读取不到的话,先从 db 加载,写入到 cache 后返回响应。
简单画了一张图帮助大家理解读的步骤。 简单画了一张图帮助大家理解读的步骤。
![](https://img-blog.csdnimg.cn/img_convert/9ada757c78614934aca11306f334638d.png) ![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/read-through.png)
Read-Through Pattern 实际只是在 Cache-Aside Pattern 之上进行了封装。在 Cache-Aside Pattern 下,发生读请求的时候,如果 cache 中不存在对应的数据,是由客户端自己负责把数据写入 cache而 Read-Through Pattern 则是 cache 服务自己来写入缓存的,这对客户端是透明的。 Read-Through Pattern 实际只是在 Cache-Aside Pattern 之上进行了封装。在 Cache-Aside Pattern 下,发生读请求的时候,如果 cache 中不存在对应的数据,是由客户端自己负责把数据写入 cache而 Read Through Pattern 则是 cache 服务自己来写入缓存的,这对客户端是透明的。
和 Cache Aside Pattern 一样, Read-Through Pattern 也有首次请求数据一定不再 cache 的问题,对于热点数据可以提前放入缓存中。 和 Cache Aside Pattern 一样, Read-Through Pattern 也有首次请求数据一定不再 cache 的问题,对于热点数据可以提前放入缓存中。
### Write Behind Pattern异步缓存写入 ### Write Behind Pattern异步缓存写入
Write Behind Pattern 和 Read/Write Through Pattern 很相似,两者都是由 cache 服务来负责 cache 和 DB 的读写。 Write Behind Pattern 和 Read/Write Through Pattern 很相似,两者都是由 cache 服务来负责 cache 和 db 的读写。
但是,两个又有很大的不同:**Read/Write Through 是同步更新 cache 和 DB而 Write Behind Caching 则是只更新缓存,不直接更新 DB而是改为异步批量的方式来更新 DB。** 但是,两个又有很大的不同:**Read/Write Through 是同步更新 cache 和 db而 Write Behind 则是只更新缓存,不直接更新 db而是改为异步批量的方式来更新 db。**
很明显,这种方式对数据一致性带来了更大的挑战,比如cache数据可能还没异步更新DB的话cache服务可能就就挂掉了。 很明显,这种方式对数据一致性带来了更大的挑战,比如 cache 数据可能还没异步更新 db 的话cache 服务可能就就挂掉了。
这种策略在我们平时开发过程中也非常非常少见但是不代表它的应用场景少比如消息队列中消息的异步写入磁盘、MySQL 的 InnoDB Buffer Pool 机制都用到了这种策略。 这种策略在我们平时开发过程中也非常非常少见但是不代表它的应用场景少比如消息队列中消息的异步写入磁盘、MySQL 的 Innodb Buffer Pool 机制都用到了这种策略。
Write Behind Pattern 下 DB 的写性能非常高,非常适合一些数据经常变化又对数据一致性要求没那么高的场景,比如浏览量、点赞量。 Write Behind Pattern 下 db 的写性能非常高,非常适合一些数据经常变化又对数据一致性要求没那么高的场景,比如浏览量、点赞量。

View File

@ -0,0 +1 @@
<mxfile host="Electron" modified="2021-12-30T08:24:33.950Z" agent="5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.4.5 Chrome/83.0.4103.122 Electron/9.1.0 Safari/537.36" etag="Lm2Jg2WpdHU34XBpseqz" version="13.4.5" type="device"><diagram id="q0Jyj2iPy4cPDLKcUkni" name="Page-1">7VdNc9owEP01OtLBNhj5aBOSTmbaaSeHpL10hC1sTWSLCvHVX9+VvQb8QZs0bWlmOhyQ3sq7631vF0G8ab670WyZvVMJl8QdJjviXRHXdZyhD18W2VdIEEwqINUiwUNH4E584wgOEV2LhK8aB41S0ohlE4xVUfDYNDCmtdo2jy2UbEZdspR3gLuYyS56LxKTVSh1J0f8LRdpVkd2/KCy5Kw+jG+yyliitieQNyPeVCtlqlW+m3Jpi1fXpXru+oz1kJjmhXnKA/l7Z//5y+2nj/cmH6zmi83jgz9ALxsm1/jCxPUl+ItWS1bYrM0eS+F/XdtUo4UqzGBVEhXCAYcugezoaIdVar8pmY1JeEWA8BklNCT04BuSrNxXJ7E+h0iuVusi4TZvB8zbTBh+t2SxtW5BZoBlJpdotvmgbhxq90LKqZJKl768hHG6iO0LGa0e+YnFjymfL6ylZmZoN4/cxBn6TiVbrdCAleLa8N1ZCpwDsdARXOXc6D0cwQfcCWoBm8H1cL89Ssup9ZKdyMpHjKGa04PrI+GwQM6fwb/7e/i/HPmviOzg0mR7/8n+W2R740uTPXrlZF+MupFzaeomPdS1SsmLJLS3G9jFthwi/vGPIt8J84A2u/5k6/dmjLurHZaz3Oz7il5lwJPObalVZshSrXXMf6bMLh0n5R73VLvGNJfMiE0zjT4KMMIHJSDBA9ujYYvtNotV+vjU6XWq7Yi2HI1ajgzTKTcdR6UiDq/96yKhXZFAY1Kf0HHdodCqExK6hM7sggaETjpCgr4xrcZrTNNCFbw1ehFiUqSF1R8IgAMe2S4UcHMO0ZCLJLFheju9OQvacm00f93vTr8mX9T8HRafeiNz/1TzB/28AqNTMhuRaFpOXkCuSQSL6xIJb9mG3di/SvUsnusnjXj/zOW9DAUSmpZDfliKCkNVYSCDwCPh+B8UlNWMZHMuIxY/piXeDn4iNx/3J9eHqPyUPg3MGmVjD7wzI/FF8vOC1rWh77eH9sjPeb78YHv8s1lNoeNfdm/2HQ==</diagram></mxfile>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -1 +0,0 @@
<mxfile host="Electron" modified="2020-07-27T06:27:52.340Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.4.5 Chrome/83.0.4103.122 Electron/9.1.0 Safari/537.36" etag="dsqbsLB26jrO3YkREjOb" version="13.4.5" type="device"><diagram id="tTBfL0GptSJyUtbD2ZoE" name="Page-1">7VlNc5swFPw1PiaDENjmmNjpx6Gdjt1J2lNHAzKoEYgRcmzn11cYyRgJT1w3DnScU3grIaHd5b2HM4CTdP2Rozz5wiJMB64TrQdwOnBdEEAo/5TIpkICx6mAmJNITaqBOXnGCtTTliTCRWOiYIwKkjfBkGUZDkUDQ5yzVXPagtHmrjmKsQXMQ0Rt9IFEIqnQsTuq8U+YxIneGQyDaiRFerI6SZGgiK32IHg3gBPOmKiu0vUE05I8zUt134cDo7sH4zgTx9wwu/+V/H4g/myezsD35/vZ56/ulVrlCdGlOrB6WLHRDHC2zCJcLgIG8HaVEIHnOQrL0ZXUXGKJSKkaLh6xCBMVLFgmlKJgJGO1F+YCrw8eAuyokZ7CLMWCb+QUdcOVp9hUdnKhile1OL62WLInzEhhSPkh3i1dUyYvFGt/waBrMbi9BD3lUfPm2bwFLbT556INttPWc/sB035d0+i10wj7TaM77hmNw5fTIM6im7KeyCikqChI2ORMHp1vfsjA0cHPMrh2fR1P1/uj042KjiAbR1aRMqiWVRHxGIuXUr0tSSNxHqacY4oEeWo+RpsOaodvjMgHrPM2gKbk4+YaBVvyEKvb9suYuZLpHdcwRUWEtdDWF7tzn26V0f9ula4s4A0N4cbOtX+aB3zfWupNPaCb01cxAXjPF0cofGq68AJjIT8wXXdusxzRY/fbLJ0VDbPbOj1j2PXnrVOG/Z3A82WRWFaQXZUwujHB2SOeMMq4RDKW4VJLQqkBIUrirHSQVA9L/Lbs0Yj8lL1RAymJonKb1vavbhCP9M0/dYA+OFDF95zltTjLLPav1gECu5PmOcvf5aloD7qWx7fkoRf8+siiYggEuhbI/oSil/v+2Pp0/gLZ3y18u20/BTqDJp5O8VoSp2tJxvYrgxcXpIjV351PERnWv7RXPV39/wp49wc=</diagram></mxfile>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1 @@
<mxfile host="Electron" modified="2022-08-21T12:40:37.540Z" agent="5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.4.5 Chrome/83.0.4103.122 Electron/9.1.0 Safari/537.36" etag="lr4caBKy7jjWoYtJBxep" version="13.4.5" type="device"><diagram id="9BE8MdjfxC0TaVaDFPY0" name="Page-1">7Vrbcuo2FP0aPSbjq2w9YnDSezPNQ9unjmILcGIsakSAfn0lWcYXiQROIJwMzJk5sbZu9l57SUsbAXc4W9+XeD79laYkB46VroE7Ao5j2xbkf4RlU1kQCirDpMxS1agxPGb/EWW0lHWZpWTRacgozVk27xoTWhQkYR0bLku66jYb07w76xxPiGZ4THCuW//MUjatvwuipuIHkk2m9dTQ96qaGa5bq09ZTHFKVy2TGwN3WFLKqqfZekhy4b3aMVW/ux212zcrScH26UAWz8U/Nw9/4FFK2f08uik3P9+oUV5xvlRfrF6WbWoXlHRZpEQMYgM3Wk0zRh7nOBG1Kw46t03ZLFfVKV5Mt23V2KRkZL3zpe2tK3gQETojrNzwJnWHUHlPxY/tqfKqhUbt4WkLCM9SRqwiYLIdu/ERf1BuOsBlju6y2AcDH/DQjiEIY/EsLCNQB3vLm9wVrOuyBSvpCxnSnJbcUtCCt4zGWZ73TDjPJgUvJtx1hNsj4diMh+pAVcyyNBXTGDFqULT6MI1pwRTzHOs4sDlWDzaowxYaUHNOBpqlIUFSznRVpCWb0gktcB431p7Pmja/UDpXvnsmjG2U8/CS0S603Fvl5i/VXxb+FoVbvy6O1u3K0UaVWojYcIuIeOG38eDfR5dlQt5whKsWUVxOCHujXWDGtyQ5Ztlr9z2OjparUWxBkxfCbB3EPOdbwa6gb0HRd2mbYMBxU0zCcaKxkdfAJCRP4yOtZsjv0GJLkzYtfJ0WwcloYfDoRdLC+wq08HbQQt+zvzYt3LPTwuDR09PihOHtfzBsVdcHmvGZt7h5vV3edXuAVHRSvRpMBmWJN61mc9FgsXse1+vO4wV+e7h329fv1YRE9QZNgGx98u0x4+8g529fnJx9KecZFPinkhNqjtY9XKQDcfhrxHNH8PbOKw+YcUFdSItjuVuH1gc+Z6dGfp+bultbbvMNCri2fZCajotuu4uq1ydntWho5NxjKDfcj+fHopbjXlVKoz72UCnhOVVKoPHzRz7O79wkT8UeQAMQhyAKwOBOWcIRiAOAPDAIxQP/P4xEVTQA4Z2G/UEJiT5xe2voeExgYlxD0wA9WUc6DmsbpUHg2KbzMDzVIhrqi2gMAYIgDEDsgSgCEZSWQD4g+eAJTEIOjqzixSgWFoQEYqdFaezsQAk+QR8eByWIvjeU0Ptb3Vmzcwj20jyOwWPQ4DHvZOqgThx3ItuTK0nUiuxq2fHksmPJgN4Vx5eRsENhd4s3Jexs24DkyTJ2tn7aveo8TZzZlqbO/L4621fomcba80R3LKVn66coyUwbRCPFXs5brh64dIhkuj2yQegcwudv3ZdMJzBipz4JTPsSgoGLj7QvoaCfNfR1brqfuS/ZhjOYASZuiQCKWyLvomBChiX0c2HSpbhU3ncSlNZPVXx3RBIU8ZuVd1kwucHZYTKJcU6iUPCoYhNHygjc5cDk+eeGyfF0/XGRWQgVXu9mIeyPZp0/Bpd/heswuOBZ4YJXuA6D66w/RTr6zZYrXG/CddacrGOQGA7MmfJNB0j475LWFTcL6bUBb2DD+bqp5E8T+VdkBLkOGUqhMpR3oHyRtBWnsztpGfyEX/G9uMdXT/lUNt0DcWTgBwchPiOhXupez7yXvP13mxR1R/7t1euq3t9nribHTySPcPIykfb+5K1YDFW5paEi+U+OyXhg0EINunghLJnWhfoq4ZGyP9tjfn10Md2yM2U+7cPFFi82dx6rvEFzddSN/wc=</diagram></mxfile>

View File

@ -0,0 +1 @@
<mxfile host="Electron" modified="2022-08-21T12:47:30.896Z" agent="5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.4.5 Chrome/83.0.4103.122 Electron/9.1.0 Safari/537.36" etag="ZRkvMtSIqMZPTfHNopgk" version="13.4.5" type="device"><diagram id="tTBfL0GptSJyUtbD2ZoE" name="Page-1">7VlNc9owFPw1HJPBlg32MYE07aGdDnSS5tRR7YetRrY8sgiQX18Zy9iWYEIpXy05Ya3kJ2l3rfc0dNAgmd9znMWfWQi0Y3fDeQcNO7Zt+QjJnwJZlIjv90sg4iRUg2pgTF5BgV2FTkkIeWugYIwKkrXBgKUpBKKFYc7ZrD1swmh71gxHYADjAFMTfSShiEvUs/s1/hFIFFczWz2/7ElwNVjtJI9xyGYNCN110IAzJsqnZD4AWpBX8VK+92FD72phHFKxzQujhx/xr0fijsbJyPr2+jD69MW+UlFeMJ2qDavFikXFAGfTNIQiiNVBt7OYCBhnOCh6Z1JzicUioao7fwYRFPvuysaEpUIpavVl21xxNT1wAfMGpHZwDywBwRdyiOq9chSbyk42Uu1ZLY7bVVjcEKavMKz8EK1C15TJB8XaHzBoGwwuH60D8jghlA4YZXwZGIUYvElQvCQ4e4ZGTy/w4OfkL5mvmHZMpv01RLuHIhqtJ/qQhj0u0VWvbvFTE++sJx79b8Tb3pkR33v7cIY0vCmynGwFFOc5CdosSzb44rtiedl4KhrXtlu1h/Nm73ChWrsd5ALzCMTb+QbCVtY1JWkd55sp50CxIC/tXL1OBzXDV0bkiutsYiFdcq8dI2dTHoB6rZlc9Ui6d2zNFCUzRqClL1b73t0q/X/OKmdiAaenCed1r93dPOC6RqijeqAqmfdiAuv9vNhC4V2PC8fXArm+7rpDm2WLyv/MzHImJjCuILufGGb+OfaRYd5eeDbNY8MKsoQSWv3WKsVSloJWtykIUxKlhYOknCDx26IgI/KCfaM6EhKGxTRrC8a6pNzdN9tXgK61IYs3nOWscZae7PdWAVpm7c0zlr3LU9Lun1oe15CHXvDnI5OKJpB1aoHMKxS93O/H1OfkH5B5b+HLac9TIF2TlmB7EMipzvtKn+6p9fHM7wcmlyqPUfkdTh7ZrP8ZKKu9+v8VdPcb</diagram></mxfile>

View File

@ -1 +0,0 @@
<mxfile host="Electron" modified="2020-12-19T10:09:54.115Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.4.5 Chrome/83.0.4103.122 Electron/9.1.0 Safari/537.36" etag="ouO_wanaVWn605JgN_9b" version="13.4.5" type="device"><diagram id="3s-LqK6m4lkifnhmqHE2" name="Page-1">7Vpbc+o2EP41ekzHl/j2iAmk02nmdA6dpn3qCFsYTWSLY0Qg/fWVbMnYluE4B4jTQh4Se6WVVt+32pU2BvY43T3mcLV8ojEiwDLiHbAfgGWZluPzP0LyVkoCwygFSY5j2WkvmOF/kBSqbhsco3WjI6OUMLxqCiOaZShiDRnMc7ptdltQ0px1BROkCWYRJLr0GcdsWUp9y9vLf0Y4WaqZTTcoW1KoOsuVrJcwptuayJ4Ae5xTysqndDdGRICncCn1pgdaK8NylLE+Ck/Pf/xthHPraf7NePliLeLZ1+c7OcorJBu5YGkse1MI5HSTxUgMYgI73C4xQ7MVjETrlnPOZUuWEtm8wISMKaF5oWsvFgsrirh8zXL6gmotsTt3HVe0KFiEekRTzLs/GPw5IXC9ls/SSpQztDu4fLMClXsjoili+RvvIhVs5VHSEX3fKd+3e1pNxdWyRqkrZVB6UlINvQebP0i834G9db3YW0Njb2vYx5BBDX++ZNYEuQlmRjN0BHlIcJJxWcRxQrwxFChiHlxGsiHFcSzm6qR2T75RTaxiUME3zZgMmFbQIq1O5jkIvG8RqN5rBLod/NmX4u9e4y8TVN3468dflYWH4s+5mtjnGJ8t77jXi/3gece75Z13EWi3845OYFfcUjyfnT//lndO4W/wvBNcTexzg8+Wd9Ql4BrBHzzxmPpN/5Z5jjDoWZ/sxmPq5YJb6nkHgYOnHlOvOfxfw5/vf7rcoxcMrgb84XOPftu/5Z4jDAbtcunguUcvGdxyzzsIHD736HUHjTyUxSPxDzNBgIBGANKIeC38mgjbXIJ2mP0pe4vnvwSiPzny7WEnAS5e3hpoo1j7L1wLa24q3eQROrbIbk5qmDsdmCtZjghk+LVpRhcRcobfKOYGHiw1BSrjqCFK86XWns4eA7VqGQzmCWLaQIVfVMs+wVX0Esd/zFWGcgG/vevbzPV1gXYG/3AX6FElublAF3Nu+9Lxo1GgXUDQBrqwC6h1NFzAJUV2t/bK7reN+HwhBJN7EPrAD8DEAf4U+GPxwNcQmGASgMAG4QRMfDAywcivqdVdSgmF59ytC9cZ8Q62vdrVNdyknJDP8wACp3N4UnadClNlfymM8esJk8pB5vnpY3DrCluU9PSTlBSd9RBVv7IcOi/Vdrptn+f8ZPt+w/s9Vz8/OeZHHqAsvXz2PZcSFN5JNoQ/ELRgh/1hvYJZH68yne7twPcf3w5jsQt49uD37ckUhGMQjGYZxGRMcDrnnWEqSM7m61XTFcvZj3toKRXmnGDnBTCrBQQHjMYFFHzhngxFoVetu/z9iNlyM6/w+QW+wkfxkdkPwcGlJSK99/HF92e9vNDOxEKJ8hExEzsrEK8EzhEJYfSSFGO3AwxXrl3VjOKn0qJ5jPIOjSlMMREzPMIcpjSLlRkSGENS/aUyxTNKPiOcJb/TlTwiSMGvwgsakpAyRtOm7KsMA2eKQZ6qWakM7OhlFKsrBt1fLAbpFeDbsazXscw0vnep6nsuMw1v2LO5pVeRs41Q+9jAM2R1RefgcuUV/rr/QrfkcP+dsz35Fw==</diagram></mxfile>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@ -172,7 +172,7 @@ Redis 中的 List 其实就是链表数据结构的实现。我在 [线性数据
我专门画了一个图方便大家理解 `RPUSH` , `LPOP` , `lpush` , `RPOP` 命令: 我专门画了一个图方便大家理解 `RPUSH` , `LPOP` , `lpush` , `RPOP` 命令:
![redis list](./images/redis-all/redis-list.png) ![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/redis-list.png)
**通过 `LRANGE` 查看对应下标范围的列表元素** **通过 `LRANGE` 查看对应下标范围的列表元素**

View File

@ -24,7 +24,7 @@ Redis 提供了多种数据类型来支持不同的业务场景。Redis 还支
你可以自己本机安装 Redis 或者通过 Redis 官网提供的[在线 Redis 环境](https://try.redis.io/)来实际体验 Redis。 你可以自己本机安装 Redis 或者通过 Redis 官网提供的[在线 Redis 环境](https://try.redis.io/)来实际体验 Redis。
![try-redis](./images/redis-all/try-redis.png) ![try-redis](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/try.redis.io.png)
### 分布式缓存常见的技术选型方案有哪些? ### 分布式缓存常见的技术选型方案有哪些?
@ -61,7 +61,7 @@ Memcached 是分布式缓存最开始兴起的那会,比较常用的。后来
作为暖男一号,我给大家画了一个草图。 作为暖男一号,我给大家画了一个草图。
![正常缓存处理流程](./images/redis-all/cache-process.png) ![正常缓存处理流程](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/normal-cache-process.png)
简单来说就是: 简单来说就是:
@ -76,7 +76,7 @@ _简单来说使用缓存主要是为了提升用户体验以及应对更多
下面我们主要从“高性能”和“高并发”这两点来看待这个问题。 下面我们主要从“高性能”和“高并发”这两点来看待这个问题。
![](./images/redis-all/使用缓存之后.png) ![使用缓存之后](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/after-using-the-cache.png)
**高性能** **高性能**
@ -247,15 +247,13 @@ Redis 通过**IO 多路复用程序** 来监听来自客户端的大量连接(
- 文件事件分派器(将 socket 关联到相应的事件处理器) - 文件事件分派器(将 socket 关联到相应的事件处理器)
- 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器) - 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)
![](./images/redis-all/redis事件处理器.png) ![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/redis-event-handler.png)
<p style="text-align:right; font-size:14px; color:gray">《Redis设计与实现12章》</p>
### Redis6.0 之前为什么不使用多线程? ### Redis6.0 之前为什么不使用多线程?
虽然说 Redis 是单线程模型,但是,实际上,**Redis 在 4.0 之后的版本中就已经加入了对多线程的支持。** 虽然说 Redis 是单线程模型,但是,实际上,**Redis 在 4.0 之后的版本中就已经加入了对多线程的支持。**
![redis4.0 more thread](./images/redis-all/redis4.0-more-thread.png) ![redis4.0 more thread](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/redis4.0-more-thread.png)
不过Redis 4.0 增加的多线程主要是针对一些大键值对的删除操作的命令,使用这些命令就会使用主处理之外的其他线程来“异步处理”。 不过Redis 4.0 增加的多线程主要是针对一些大键值对的删除操作的命令,使用这些命令就会使用主处理之外的其他线程来“异步处理”。
@ -323,7 +321,7 @@ OK
Redis 通过一个叫做过期字典(可以看作是 hash 表)来保存数据过期的时间。过期字典的键指向 Redis 数据库中的某个 key(键),过期字典的值是一个 long long 类型的整数,这个整数保存了 key 所指向的数据库键的过期时间(毫秒精度的 UNIX 时间戳)。 Redis 通过一个叫做过期字典(可以看作是 hash 表)来保存数据过期的时间。过期字典的键指向 Redis 数据库中的某个 key(键),过期字典的值是一个 long long 类型的整数,这个整数保存了 key 所指向的数据库键的过期时间(毫秒精度的 UNIX 时间戳)。
![redis过期字典](./images/redis-all/redis过期时间.png) ![redis过期字典](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/redis-expired-dictionary.png)
过期字典是存储在 redisDb 这个结构里的: 过期字典是存储在 redisDb 这个结构里的:
@ -435,7 +433,7 @@ Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通
官方文档地址https://redis.io/topics/persistence 官方文档地址https://redis.io/topics/persistence
![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/booksimage-20210807145107290.png) ![](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/redis4.0-persitence.png)
## 参考 ## 参考

View File

@ -67,7 +67,7 @@ ERR EXEC without MULTI
Redis 官网相关介绍 [https://redis.io/topics/transactions](https://redis.io/topics/transactions) 如下: Redis 官网相关介绍 [https://redis.io/topics/transactions](https://redis.io/topics/transactions) 如下:
![redis事务](./images/redis-all/redis事务.png) ![Redis 事务](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/redis-transactions.png)
### Redis 支持原子性吗? ### Redis 支持原子性吗?
@ -82,7 +82,7 @@ Redis 事务在运行错误的情况下,除了执行过程中出现错误的
Redis 官网也解释了自己为啥不支持回滚。简单来说就是 Redis 开发者们觉得没必要支持回滚这样更简单便捷并且性能更好。Redis 开发者觉得即使命令执行错误也应该在开发过程中就被发现而不是生产过程中。 Redis 官网也解释了自己为啥不支持回滚。简单来说就是 Redis 开发者们觉得没必要支持回滚这样更简单便捷并且性能更好。Redis 开发者觉得即使命令执行错误也应该在开发过程中就被发现而不是生产过程中。
![redis roll back](./images/redis-all/redis-rollBack.png) ![Redis 为什么不支持回滚](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/redis-rollback.png)
你可以将 Redis 中的事务就理解为 **Redis 事务提供了一种将多个命令请求打包的功能。然后,再按顺序执行打包的所有命令,并且不会被中途打断。** 你可以将 Redis 中的事务就理解为 **Redis 事务提供了一种将多个命令请求打包的功能。然后,再按顺序执行打包的所有命令,并且不会被中途打断。**
@ -185,7 +185,7 @@ Biggest string found '"ballcat:oauth:refresh_auth:f6cdb384-9a9d-4f2f-af01-dc3f28
如下图所示,用户的请求最终都要跑到数据库中查询一遍。 如下图所示,用户的请求最终都要跑到数据库中查询一遍。
![缓存穿透情况](https://img-blog.csdnimg.cn/6358650a9bf742838441d636430c90b9.png) ![缓存穿透情况](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/redis-cache-penetration.png)
#### 有哪些解决办法? #### 有哪些解决办法?
@ -228,7 +228,7 @@ public Object getObjectInclNullById(Integer id) {
加入布隆过滤器之后的缓存处理流程图如下。 加入布隆过滤器之后的缓存处理流程图如下。
![](./images/redis-all/加入布隆过滤器后的缓存处理流程.png) ![加入布隆过滤器之后的缓存处理流程图](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/database/redis/redis-cache-penetration-bloom-filter.png)
但是,需要注意的是布隆过滤器可能会存在误判的情况。总结来说就是: **布隆过滤器说某个元素存在,小概率会误判。布隆过滤器说某个元素不在,那么这个元素一定不在。** 但是,需要注意的是布隆过滤器可能会存在误判的情况。总结来说就是: **布隆过滤器说某个元素存在,小概率会误判。布隆过滤器说某个元素不在,那么这个元素一定不在。**