目录

缓存分类与选择

缓存分类

在分布式环境下,为了提高系统的性能,常常会引入不同类型的缓存存储系统(算法优化所带来的的效果可能远远不如缓存带来的优化效果)。缓存已经是一个老生常谈的技术了, memcache、redis、squid、varnish、web cache、 CDN等等技术五花八门,缓存的好处自然不必多说,但是缓存都适用于什么场景呢。接下来从一次完整的请求开始来分别介绍。

客户端缓存

首先是客户端的缓存,包括app客户端和浏览器。这是离请求发起最接近的一方,如果数据在这个环节被缓存住,连网络请求都免掉了,相当于直接在本地取数据,那性能也必然不在话下,一般常见的缓存技术包括cookie,localstorage,sessionstorage,本地文件或者本地数据库等,当然也包括http头相关设置,比如cache-control,last-modified等参数。本地缓存的一个缺点就是刷新机制不会特别友好,所以一般缓存对数据实时性要求不高的,或者和客户端有关的数据

cdn

如果客户端没有命中缓存,那接下来就要发起一次网络请求,根据网络环境,一般大型站点都会配置CDN,CDN会找一个最合适的服务节点接管网络请求,CDN技术不在这里详细讲,CDN节点都会在本地缓存静态文件数据,一旦命中直接返回,不会穿透去请求应用服务器。并且CDN会通过在不同的网络,策略性地通过部署边缘服务器和应用大量的技术和算法,把用户的请求指定到最佳响应节点上。所以会减少非常多的网络开销和响应延迟。有条件的公司自己搭建CDN,没条件的也可以购买商用的。一般CDN缓存静态文件。

负载均衡服务器缓存

如果没有部署CDN或者CDN没有命中,请求最终才会落入应用服务器,现在的http服务器都会添加一层反向代理,例如nginx,在这一层同样会添加缓存层,代表技术是squid,varnish,当然nginx作为http服务器而言也支持静态文件访问和本地缓存技术,当然也可以使用远程缓存,如redis,memcache,这里缓存的内容一般为静态文件或者由服务器已经生成好的动态页面,在返回用户之前缓存。

应用缓存

如果前面的缓存机制全部失效,请求才会落入真正的服务器节点。服务端的缓存主要分两种,一种是应用程序自身实现的本地缓存,一种是借助分布式缓存例如memcache,redis。也有既可以实现本地又可以用于分布式缓存的框架如Cacheonix,EHCache等。

本地缓存

其中本地缓存又可以分为两种:本地磁盘缓存(又称文件缓存)(现在一般都采用读写性能比较优异的SSD来做存储)和本地内存缓存。在系统中,为了提高缓存存储系统的性能以及热点数据的命中率,一般在本地磁盘缓存中也会引入内存缓存用于存储经常访问的数据。有时为了减少客户端对服务器的请求,也会在客户端上使用缓存,当然这是要考虑安全问题的。

分布式缓存

一般机器的内存都不会特别大,所以本地缓存的数据有限,一般缓存命中率特别高访问量又特别大的数据,而分布式缓存刚好避免了本地缓存的这一缺点,理论上分布式缓存的大小是无上限的。但是比本地缓存又多了一次网络请求。这里缓存的数据不一定是某一次请求用到的完整数据,这里使用缓存的设计可以使用多种数据结构,并且可以根据业务场景自行组织需要缓存的数据。一般是一类的数据结合。请求可能只使用一部分缓存数据即可。

数据库缓存

如果应用缓存没有命中,这个时候请求的数据一般会落到相关数据库了,数据库作为一个应用程序,又是io密集型操作,自然少不了缓存的使用,常见的数据库MySQL,PosgreSQL都有自身定制的查询缓存,并且可以做到强一致。当然代价也更高昂,一般这里的缓存不会单独设计,都是使用数据库自身的配置。

操作系统缓存

如果数据库缓存也没有命中呢,不要担心,操作系统在磁盘io层面还有一级缓存,记不记得在free命令下,有个cache和buffer,这两个分别是写入和读取使用的缓存空间。当然这是操作系统为了提高性能采用的方式,对于我们来讲,可优化空间的非常渺茫。在往后的话不同厂家的磁盘也会有一定的缓存,这里有点超纲就不多说了。

buffer 与 cache 区别

A buffer is something that has yet to be “written” to disk. A cache is something that has been “read” from the disk and stored for later use.

buffers 就是存放要输出到disk(块设备)的数据,缓冲满了一次写,提高io性能(内存 -> 磁盘) cached 就是存放从disk上读出的数据,常用的缓存起来,减少io(磁盘 -> 内存)

buffer 和 cache,两者都是RAM中的数据。简单来说,buffer是即将要被写入磁盘的,cache是被从磁盘中读出来的

1) buffer 缓冲

buffer是用于存储速度不同步的设备或优先级不同的设备之间传输数据的区域。 缓冲(buffers)是根据磁盘的读写设计的,把分散的写操作集中进行,减少磁盘碎片和硬盘的反复寻道,从而提高系统性能。

2) cache 缓存

cache经常被用在磁盘的I/O请求上,如果有多个进程都要访问某个文件,于是该文件便被做成cache以方便下次被访问,这样可提供系统性能。

缓存(cached)是把读取过的数据保存起来,重新读取时若命中(找到需要的数据)就不要去读硬盘了,若没有命中就读硬盘。其中的数据会根据读取频率进行组织,把最频繁读取的内容放在最容易找到的位置,把不再读的内容不断往后排,直至从中删除。

选择

到这里,基本上一次完整的请求就结束了,在哪个环节可以使用缓存并且适用的场景也介绍完了。到底哪一款更适合你呢,下面举一个例子:

使用本地内存缓存的快还是使用redis缓存的好?

Redis早已家喻户晓,其性能自不必多说。

但是总有些时候,我们想把性能再提升一点,想着redis是个远程服务,性能也许不够,于是想用本地缓存试试!想法是不错的。那么就让我们来比较下二者的差别吧!

  • 读写速度,不考虑并发问题,本地缓存自然是最快的。但是如果本地缓存不加锁,那应用并发了咋办呢?所以,我们以加锁方式再比较一次。
  • 各位开发同学水平差别大,使用本地缓存极有可能导致严重的线程安全问题,并发考虑严重。
  • 本地缓存无法用于重复点击,重复点击会分发请求到多台服务器,而用本地缓存只能防止本机重复点击,redis则可以防止,但是时间间隔也需要在redis的读写差之外。
  • 场景使用,同一数据,从数据库取出来,放到redis只要一次,而放到本地缓存,则需要n(集群的节点个数)次
  • redis内存可以无限扩充,而本地扩大堆内存代价是很大的而且有瓶颈。
  • 本地缓存需要自己实现过期功能,实现不好可能导致极其严重的后果,而redis经过大量的流量验证非常安全。
  • 本地缓存无法提供丰富的数据结构,redis可以。
  • redis可以写磁盘,持久化,本地缓存不可以或者说很麻烦要考虑的东西太多。
  • 加本地缓存后,代码复杂度急剧上升,后面进来的开发很难一下领会原有开发想法。间接提升维护成本。

是求快还是求稳,举两个实际应用的小例子,使用本地缓存用于生成分布式ID,使用redis用于缓存用户信息。

参考

https://blog.csdn.net/cywosp/article/details/23970017

https://zhuanlan.zhihu.com/p/40222159