目录
5.3 Write Behind Caching Pattern(异步缓存写入)
一、高并发系统三大利器
保护高并发系统的三大利器:限流、熔断降级、缓存。
限流是指在面临瞬时巨大流量访问系统时(商品秒杀等)为了保证系统的可用性的一个限制手段。
熔断降级一般一起使用,是为了在某些大流量业务场景(双11双12等)下保证核心业务可用的解决方案。(降级是主动的,熔断是被动的。熔断是指当上游服务调用下游服务出现不可用时,暂时切断请求,防止系统雪崩;降级是指某些情况下保证核心业务,将边缘业务服务暂时关闭。)
缓存大多是为了缓解数据库的查询压力,对某些热点数据和核心业务数据添加缓存层进行访问,高并发系统常使用Redis作为缓存层。(做数据冗余,以空间换时间,提高系统可用性)
在之前的文章里讲到了限流(高并发系统三大利器之限流),这次谈一谈缓存。
缓存原指CPU上的一种高速存储器,它先于内存与CPU交换数据,速度很快,现在泛指存储在计算机上的原始数据的复制集,便于快速访问。
二、缓存的使用场景
2.1 减轻DB压力
在并发量大的系统中,除了对DB进行分库分表和读写分离外,需要添加缓存层减轻DB的压力,因为一旦DB挂掉,可能会导致整个系统雪崩。通常采取的方案是用户的请求先到缓存,缓存命中则返回,如果未命中,则从DB中读取并回填缓存。
2.2 提高系统响应
在缓存的这一层通常使用Redis对DB的数据进行冗余。DB的数据大部分都是存储在磁盘上,而磁盘的读写相对内存是比较慢的,Redis将数据直接放在内存,并且Redis天然支持高并发(qps到达11万/S读请求 8万写/S),所以缓存层使用Redis是最常见的方案。
2.3 session分离
Http协议是无状态的,为了维持客户端与服务端的状态,Tomcat等会使用sessionId来区分客户端,这个信息是存放在服务端的,当然客户端也可以使用Cookie来记录用户身份。在选择Session的时候,假如服务是集群模式则需要每个节点复制session的信息,这时可以选择使用Redis存放Session信息,每个服务器节点从Redis读取会话信息。
现在主流的解决方案是JWT令牌,除了保持会话,同时解决了用户认证和鉴权
2.4 分布式锁
一般情况下的锁指的是单机器上的多线程竞争时为了保证共享数据安全采用的一种手段。在不同机器节点上的不同线程则需要分布式锁来保证线程之间的同步状态,Redis中的setnx则可以实现分布式锁。
Redis中的setnx直接使用可能会出现死锁、无法续期、无法重入等问题,可以使用Redission框架实现分布式锁,其内部封装了许多lua脚本保证事务性。(Zookeeper也可以实现分布式锁的的功能)
三、缓存的分类
3.1 客户端缓存
客户端包括移动APP端,浏览器端。
APP端:可以把数据图片等缓存到本地数据库SQlite中
浏览器:浏览器可以将页面的整个资源进行缓存,还有一些数据可以缓存再Cookie、LocalStorage、SessionStorage等。
3.2 网络端缓存
Web代理(比如Nginx)将html等静态资源做一层缓存,只有动态请求才真正发送到服务端。
CDN(Content Delivery Network,内容分发网络)也是为了使用户就近访问,提高响应而将用户的访问指向距离最近的工作正常的缓存服务器上,由缓存服务器直接响应用户请求。
3.3 服务端缓存
数据库缓存:在访问DB时,先根据查询SQL语句到缓存中查找结果,如果命中则返回。
在MySQL中输入 show variables like "%cache%" 可以查看缓存相关参数
本地缓存:应用内部借助GuavaCache、EhCache、OSCache(操作系统页缓存)等具有缓存功能的应用框架根据需要缓存相应的业务数据。
分布式缓存:在分布式集群架构中,本地缓存无法保证数据的一致性,多个应用部署在不同的机器节点,此时需要分布式缓存。Redis、Memcached、EVCache(AWS)、Tair(阿里 、美团)等都是常见的分布式缓存中间件,特点是高性能高并发高扩展。
四、缓存的优势和代价
4.1 优势
- 提升用户体验(缓存响应快)
- 减轻服务端压力(减少DB访问)
- 提升系统整体性能(响应时间、延迟时间、吞吐量等的提升)
4.2 代价
- 额外的硬件支出
- 高并发缓存失效问题(缓存穿透、缓存雪崩、缓存击穿)
- 缓存同步问题(数据库和缓存、缓存主从等无法实时一致)
- 缓存竞争(多客户端对同一key操作)