@@ -20,35 +20,33 @@ head:
2020
2121## 缓存的基本思想
2222
23- 很多同学只知道缓存可以提高系统性能以及减少请求相应时间 ,但是,不太清楚缓存的本质思想是什么。
23+ 很多同学只知道缓存可以提高系统性能以及减少请求 ** 响应时间 ** (Response Time) ,但是,不太清楚缓存的本质思想是什么。
2424
2525缓存的基本思想其实很简单,就是我们非常熟悉的 ** 空间换时间** 这一经典性能优化策略的运用。所谓空间换时间,也就是用更多的存储空间来存储一些可能重复使用或计算的数据,从而减少数据的重新获取或计算的时间。
2626
2727说到空间换时间,除了缓存之外,你还能想到什么其他的例子吗?这里再列举几个常见的:
2828
29- - 索引 :索引是一种将数据库表中的某些列或字段按照一定的排序规则组织成一个单独的数据结构,需要额外占用空间 ,但可以大大提高检索效率,降低数据排序成本。
30- - 数据库表字段冗余:将经常联合查询的数据冗余存储在同一张表中,以减少对多张表的关联查询,进而提升查询性能,减轻数据库压力。
31- - CDN(内容分发网络):将静态资源分发到多个不同的地方以实现就近访问 ,进而加快静态资源的访问速度,减轻服务器以及带宽的负担 。
29+ - ** 索引 ** :索引是一种将数据库表中的某些列或字段按照一定的排序规则组织成一个单独的数据结构,虽然需要额外占用空间 ,但可以大大提高检索效率,降低数据排序成本。
30+ - ** 数据库表字段冗余** :将经常联合查询的数据冗余存储在同一张表中,以减少对多张表的关联查询,进而提升查询性能,减轻数据库压力。
31+ - ** CDN(内容分发网络)** :将静态资源分发到多个边缘节点以实现就近访问 ,进而加快静态资源的访问速度,减轻源站服务器以及带宽的负担 。
3232
3333编程需要要学会归纳总结,将自己学到的东西串联起来!假如你在面试的时候,能聊到这些,面试官一定会对你有一个好印象的。
3434
3535不要把缓存想的太高大上,虽然,它的确对系统的性能提升的性价比非常高。当我们在学习并应用缓存的时候,你会发现缓存的思想实际在 CPU、操作系统或者其他很多地方都被大量用到。
3636
37- 比如,CPU Cache 缓存的是内存数据用于解决 CPU 处理速度和内存不匹配的问题,内存缓存的是硬盘数据用于解决硬盘访问速度过慢的问题 。
37+ 比如,** CPU Cache** 缓存的是内存数据,用于解决 ** CPU** 处理速度与内存访问速度不匹配的问题;内存缓存的是硬盘数据,用于解决硬盘 ** I/O ** 速度过慢的问题 。
3838
3939![ CPU 缓存模型示意图] ( https://oss.javaguide.cn/github/javaguide/java/concurrent/cpu-cache.png )
4040
41- 再比如,为了提高虚拟地址到物理地址的转换速度,操作系统在页表方案基础之上引入了转址旁路缓存( Translation Lookasjde Buffer,TLB,也被称为快表) 。
41+ 再比如,为了提高虚拟地址到物理地址的转换速度,操作系统在页表方案基础之上引入了 ** 转址旁路缓存 ** ( Translation Lookaside Buffer,** TLB** ,也被称为快表) 。
4242
4343![ 加入 TLB 之后的地址翻译] ( https://oss.javaguide.cn/github/javaguide/cs-basics/operating-system/physical-virtual-address-translation-mmu.png )
4444
45- 再拿我们日常使用的软件来说,一般都会对你访问过的一些图片或者文件进行缓存,这样你下次再访问的时候加载速度就很快了 。
45+ 拿日常使用的浏览器来说,它会对访问过的图片或静态文件进行缓存(浏览器缓存),这样下次访问相同页面时加载速度会显著提升 。
4646
4747![ ] ( https://oss.javaguide.cn/github/javaguide/database/redis/chrome-clear-cache.png )
4848
49- 我们日常开发过程中用到的缓存,其中的数据通常存储于内存中,因此访问速度非常快。为了避免内存中的数据在重启或者宕机之后丢失,很多缓存中间件会利用磁盘做持久化。也就是说,缓存相比较于我们常用的关系型数据库(比如 MySQL)来说访问速度要快非常多。为了避免用户请求数据库中的数据速度过于缓慢,我们可以在数据库之上增加一层缓存。
50-
51- 除了能够提高访问速度之外,缓存支持的并发量也要更大,有了缓存之后,数据库的压力也会随之变小。
49+ 我们日常开发中用到的缓存,其中的数据通常存储于 ** RAM** (内存)中,访问速度极快。为了避免内存数据在重启或宕机后丢失,许多缓存中间件(如 ** Redis** )提供了磁盘持久化机制。相比于关系型数据库(如 ** MySQL** ),缓存的访问速度和并发支持量都要高出几个数量级。在数据库之上增加一层缓存,是保护底层存储、提升系统吞吐量的核心手段。
5250
5351## 缓存的分类
5452
6664
6765![ 本地缓存示意图] ( https://oss.javaguide.cn/github/javaguide/database/redis/local-cache.png )
6866
67+ ** 注意:** 在集群模式下使用本地缓存,必须考虑** 负载均衡策略** 。如果 Nginx 使用默认的** 轮询(Round-Robin)** ,同一个用户的请求会随机落在不同机器,导致本地缓存命中率极低。解决方案如下:
68+
69+ 1 . ** 网关层** :使用一致性哈希或 Sticky Session,保证同一用户的请求固定打到同一台机器。
70+ 2 . ** 应用层** :仅将本地缓存用于** “全局几乎不变”** 的数据(如配置字典),而非用户维度数据。
71+
6972#### 本地缓存的方案有哪些?
7073
7174** 1、JDK 自带的 ` HashMap ` 和 ` ConcurrentHashMap ` 了。**
@@ -85,14 +88,17 @@ head:
8588使用 ` Caffeine ` 创建本地缓存的代码示例,用到了建造者模式:
8689
8790``` java
88- Caffeine . newBuilder()
89- // 设置最后一次写入或访问后经过固定时间过期
90- .expireAfterWrite(60 , TimeUnit . DAYS )
91- // 初始的缓存空间大小
92- .initialCapacity(100 )
93- // 缓存的最大条数
94- .maximumSize(500 )
95- .build();
91+ // 使用 Caffeine 创建本地缓存示例
92+ Cache<String , String > cache = Caffeine . newBuilder()
93+ // 设置写入后 60 天过期
94+ .expireAfterWrite(60 , TimeUnit . DAYS )
95+ // 初始容量
96+ .initialCapacity(100 )
97+ // 最大条数限制
98+ .maximumSize(500 )
99+ // 开启统计功能
100+ .recordStats()
101+ .build();
96102```
97103
98104#### 本地缓存有什么痛点?
@@ -170,8 +176,6 @@ Memcached 是分布式缓存最开始兴起的那会,比较常用的。后来
170176- [ J2Cache] ( https://gitee.com/ld/J2Cache ) :基于本地内存和 Redis 的两级 Java 缓存框架。
171177- [ JetCache] ( https://github.com/alibaba/jetcache ) :阿里开源的缓存框架,支持多级缓存、分布式缓存自动刷新、 TTL 等功能。
172178
173- 如果你想要在自己的项目中实践多级缓存的话,还可以参考借鉴一下 [ Redis+Caffeine 两级缓存,让访问速度纵享丝滑] ( https://mp.weixin.qq.com/s/_ysKYrzyRGebtotGyzQUIw ) 这篇文章。
174-
175179#### 多级缓存一致性如何保证?
176180
177181在多级缓存系统中,保证强一致性成本太高,业界的几个提供多级缓存功能的缓存框架基本都是最终一致性保证。例如,可以使用 Redis 的发布/订阅机制、Redis Stream 或者消息队列来确保当一个实例的本地缓存发生变化时,其他实例能够及时更新其本地缓存,以保持缓存一致性。
0 commit comments