单节点系统
第四章 单系统高并发优化
第一节 缓存优化
4.1.1 了解内存缓存
-
什么是缓存
硬件 客户端缓存 服务端缓存在计算中,缓存是一个高速数据存储层,其中存储了数据子集,且通常是短暂性存储,这样日后再次请求此数据时,速度要比访问数据的主存储位置快。通过缓存,可以高效地重用之前检索或计算的数据。
-
缓存使用的场景:
高并发查询/写入 热点数据 大对象初始化……
-
使用缓存的好处
提升应用程序性能 降低数据库成本 减少后端负载 可预测的性能 消除数据库热点 提高读取吞吐量(IOPS)
-
缓存的常用类型
- 内存缓存(进程内缓存) 性能最好
- 分布式缓存
- 组合缓存(多级缓存)
-
缓存的特点
- 设置存活时间(过期策略)
缓存通常设置有效期,过期后应当失效,常见的过期策略有:定时、定期、惰性失效 - 空间占用有限(淘汰策略)
缓存占用有空间上限,超过上限需淘汰部分缓存数据,常见的淘汰策略有:FIFO LRU LFU - 支持并发更新
缓存需要支持并发的读取写入
- 设置存活时间(过期策略)
-
缓存使用时的常见问题-总结
-
缓存穿透
请求数据中不存在的数据,导致每次都无法从缓存中命中,继而访问到数据库 -
缓存击穿
缓存失效的同时大量相同请求穿过缓存访问到数据库 -
缓存雪崩
大量缓存同时失效,导致大量请求穿过缓存访问到数据库
-
-
常用内存缓存实现方式
-
Java容器 基于JDK自带的Map容器类:HashMap、ConcurrentHashMap
-
Guava Cache Google提供的Java增强工具包Guava的一个模块,社区活跃
-
Ehcache 重量级的内存缓存,支持二级缓存,Hibernate中默认的缓存框架
-
Caffeine 基于Guava API开发的高性能内存缓存,Spring5默认的内存缓存框架
-
4.1.2 实现简单的内存缓存
基于Java容器类
- 看代码
- 基于ConcurrentHashMap实现并发读写
- 基于定时器实现缓存的定时、定期清除
- 基于队列实现缓存的FIFO淘汰
4.1.3 常见开源内存缓存工具介绍
-
一、 Guava Cache 简介
Google Guava Cache 是一种非常优秀的本地缓存解决方案,提供了基于容量,时间和引用的缓存回收方式。基于容量的方式内部实现采用LRU算法,基于引用回收很好的利用了Java虚拟机的垃圾回收机制。
Guava Cache 与 ConcurrentMap 很相似,但也不完全一样。最基本的区别是ConcurrentMap会一直保存所有添加的元素,知道显式地移除。Guava Cache 为了限制内存占用,通常都设定为自动回收元素。 -
适用场景
愿意消耗一些内存空间来提升速度
预料到某些键会被多次查询、
缓存中存放的数据总量不会超出内存容量
Guava Cache 是运行在JVM的本地缓存,并不能把数据存放到外部服务器上。如果有这样的要求,因尝试Memcached或Redis这类分布式缓存。 -
看代码
-
Guava Cache 加载
-
-
07:27截图
-
加载方式1- CacheLoader
-
加载方式2- Callable
-
-
Guava Cache 缓存回收
-
11:21
-
Guava Cache 显式清除
- Cache.invalidate(key)
-
Guava Cache 统计
- CacheBuilder.recordStats()
-
二、 Ehcache
-
三、 Caffeine
4.1.4 Caffeine实现原理-源码分析
- 淘汰策略 tinyLFU
-
淘汰算法
- 常用缓存淘汰算法
- 缓存淘汰算法的作用是在有限的资源内,尽可能识别出哪些数据在短时间会被重复利用,从而提高缓存的命中率。常用有LRU、LFU、FIFO等。
- LRU(Least Recently Used)算法认为最近访问过的数据将来被访问的几率也更高。
- LFU(Least Frequently Used)算法根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”。
- 常用缓存淘汰算法
- Caffeine内部接口关系
- load put invalidate 操作的原子性
- 缓存过期策略解析
4.1.5 应对缓存同步,穿透,击穿,雪崩
-
数据实时同步
增量 主动 强一致性
-
数据准实时同步
增量 被动 准一致性
-
任务调度更新
实时性要求不高
-
binlog日志订阅
4.1.6 内存框架设计与实现
- 看代码
主要是: 注解 + AOP
Spring的EL表达式
SpelExpressionParser
4.1.7 编写内存缓存框架的核心模块
- 07/30
第二节 线程安全问题
- 08/030507
第三节 J.U.C并发编程包详解
4.3.1 Lock接口
void lock();获取锁
Condition newCondition();
ReentrantLock 可重入锁
CAS (Compare-and-Swap),即比较并替换,是一种实现并发算法时常用到的技术,Java并发包中的很多类都使用了CAS技术。
4.3.2 AQS
ReadWriteLock
概念:维护一对关联锁,一个只用于读操作,一个只用于写操作;
读锁可以由多个读线程同时持有,写锁是排他的。同一时间,两把锁不能被不同线程持有。
适用场景:适合读取操作多于写入操作的场景,改进互斥锁的性能;
比如:集合的并发线程安全性改造、缓存组件。
锁降级:指的是写锁降级为读锁。持有写锁的同时,再获取读锁,随后释放写锁的过程。
写锁是线程独占,读锁是共享,所以写->读是降级。(读->写,是不能实现的)