高并发——缓存(三)

前言

目前磁盘 IO 和网络 IO 相对于内存 IO 的成百上千倍的性能劣势。

通过将高频使用的数据存在离 cpu 更近的位置,以减少数据传输时间,从而提高处理效率,这就是缓存的意义。

浏览器缓存

浏览器会缓存页面的元素,这样在重复访问网页时,就避开了要从互联网上下载数据(例如大图片)

缺点:

客户端缓存减少了的服务器请求,避免了文件重复加载,显著地提升了用户地方。但是当网站发生了更新的时候(如替换了 css、js 以及图片文件),浏览器本地仍保存着旧版本的文件,从而导致无法预料后果。

CDN 缓存

浏览器本地缓存失效后,浏览器会向 CDN 边缘节点发起请求。类似浏览器缓存,CDN 边缘节点也存在着一套缓存机制。

CDN 可以理解为分布在每个县城的火车票代售点,用户在浏览网站的时候,CDN 会选择一个离用户最近的 CDN 边缘节点来响应用户的请求。

缺点:CDN 的分流作用不仅减少了用户的访问延时,也减少的源站的负载。但其缺点也很明显:当网站更新时,如果 CDN 节点上数据没有及时更新,即便用户再浏览器使用 Ctrl +F5 的方式使浏览器端的缓存失效,也会因为 CDN 边缘节点没有同步最新数据而导致用户访问异常。

数据库缓存

数据库会缓存查询,所以同一条查询第二次就是要比第一次快。

分布式 缓存

(如 redis Memcache)选择把数据存在内存而非硬盘里。

本地缓存

编程实现(成员变量、局部变量、静态变量)、Guava Cache

高并发下缓存的常见问题

  1. 缓存一致性

当数据时效性要求很高时,需要保证缓存中的数据与数据库中的保持一致,而且需要保证缓存节点和副本中的数据也保持一致,不能出现差异现象。这就比较依赖缓存的过期和更新策略。

一般会在数据发生更改的时,主动更新缓存中的数据或者移除对应的缓存。

  1. 缓存穿透

缓存穿透是说收到了一个请求,但是该请求缓存里没有,只能去数据库里查询,然后放进缓存。这里面有两个风险,一个是同时有好多请求访问同一个数据,然后业务系统把这些请求全发到了数据库;第二个是有人恶意构造一个逻辑上不存在的数据,然后大量发送这个请求,这样每次请求都会被发送到数据库,可能导致数据挂掉。

怎么应对这种情况呢?对于恶意访问,一个思路是事先做校验,对恶意数据直接过滤掉,不要发到数据库层;第二个思路是缓存空结果,就是对查询不存在的数据仍然记录一条该数据不存在在缓存里,这样能有效的减少查询数据库的次数。

  1. 缓存击穿

缓存击穿其实是缓存穿透中,非恶意访问的情况。比如缓存中某热点数据过期失效,所有请求都被下放到数据库去请求更新缓存,数据库被压垮。

怎么防范这种问题呢?一个思路是全局锁,就是所有访问某个数据的请求都共享一个锁,获得锁的那个才有资格去访问数据库,其他线程必须等待。但是现在的业务都是分布式的,本地锁没法控制其他服务器也等待,所以要用到全局锁,比如用 redis 的 setnx 实现全局锁。

另一个思路是对即将过期的数据主动刷新,做法可以有很多,比如起一个线程轮询数据,比如把所有数据划分为不同的缓存区间,定期分区间刷新数据等等。这第二个思路又和我们接下来要讲的缓存雪崩有关系。

  1. 缓存雪崩

缓存雪崩是指比如我们给所有的数据设置了同样的过期时间,然后在某一个历史性时刻,整个缓存的数据全部过期了,然后瞬间所有的请求都被打到了数据库,数据库就崩了。

解决思路要么是分治,划分更小的缓存区间,按区间过期;要么是给每个 key 的过期时间加个随机值,避免同时过期,达到错峰刷新缓存的目的。

  1. 缓存无底洞

该问题由 facebook 的工作人员提出的, facebook 在 2010 年左右,memcached 节点就已经达 3000 个,缓存数千 G 内容。他们发现了一个问题—memcached 连接频率,效率下降了,于是加 memcached 节点,添加了后,发现因为连接频率导致的问题,仍然存在,并没有好转,称之为”无底洞现象”。

总结

缓存无底洞情况并不常见,在绝大多数公司根本不会遇到。

文章目录
  1. 1. 前言
  2. 2. 浏览器缓存
  3. 3. CDN 缓存
  4. 4. 数据库缓存
  5. 5. 分布式 缓存
  6. 6. 本地缓存
  7. 7. 高并发下缓存的常见问题
  8. 8. 总结
|