详解动静态缓存各种方式
在运维实践中,缓存的目的是提升访问性能,这是一种牺牲时间换取性能的技术。以前要获取数据时,直接去数据源获取即可。有了缓存后,想要获取数据,先去数据源获取,如果缓存中有,则直接返回;如果缓存中没有,则去后端数据源中取,并将取回的数据存放至缓存中,以方便下次请求访问。
缓存的类型主要分为前端缓存和后端缓存,而前端缓存的应用就是静态缓存,大家熟知的 CDN 就是前端静态缓存的典型代表。而后端缓存的应用又分为动态请求(如 ASP、PHP、JSP)缓存和数据库热点数据缓存。
静态缓存
静态缓存,一般是指 Web 类应用中,将 HTML、JS、CSS、图片、音视频等静态文件/资源通过磁盘/内存等缓存方式提高资源响应速度,减少服务器压力/资源开销的一项缓存技术。
静态缓存的实现技术主要有 Squid、Varnish、Nginx。Squid 是一个代理缓存服务器,它支持 FTP、Gopher、HTTPS 和 HTTP 协议。而 Varnish 也是一款代理缓存服务器,只不过它只支持 HTTP 代理缓存。相较于 Squid,Varnish 的功能虽然不多,但 Varnish 的精简,也是其最大的性能优势。Nginx 的静态缓存需要第三方模块来完成,只能满足基本缓存需求。不过 Nginx+Memcache 的组合,使其和 Squid、Varnish 都具备了专业的静态缓存功能。
浏览器缓存,也称为客户端缓存,是静态缓存中最常见、最直接的表现形式。在 Nginx 中设置 expires,并不是指把静态内容缓存在 Nginx 中,而是设置客户端浏览器缓存的时间。
服务器端的静态缓存技术主要分为磁盘缓存类和内存缓存类两大类。磁盘缓存,是指将静态资源文件通过磁盘进行缓存的技术。内存缓存,就是把静态文件缓存在服务器端的内存中。在这种缓存方式下,如若命中缓存的话,取内存中的缓存数据返回比取磁盘中的缓存数据返回性能要高很多。
小型应用中,Nginx 作为前端反向代理服务器,主业务域名解析绑定在前端代理服务器上,且静态资源也存放至代理服务器上。在 Nginx 七层通过 Rewrite 对请求做判断,如果是静态资源请求,直接请求本机的静态资源,也可进一步设置对应的静态缓存。如果是动态请求,则转发给后端服务器处理。这是常规动静分离最为成熟的解决方案。
中型应用中,静态资源一般会和应用代码一起部署。要实现静态加速,前端只需要加个 CDN,CDN 会针对客户端请求,进行回源并主动缓存静态资源。
大型应用中,主业务的域名会直接绑定在业务服务器的负载均衡 IP 上。静态资源会采用单独的 Web 服务器部署,并且会跟静态资源绑定独立的二级域名来做请求分流。用户在请求对应的页面(包含静态请求和动态请求)时,静态请求会被隐式重定向(不显示跳转后的 URL)引流到静态服务器上,所以对客户端而言是不可感知的。这里需要进行一定的代码改造。
动态缓存
动态缓存,用于缓存业务中的动态数据,如业务处理的临时数据、频繁对数据库访问查询的热点数据、用户 Session 数据、动态页面数据等,甚至频繁访问的静态页面数据也是通过动态缓存技术(Redis、Memcache)进行缓存的。
后端缓存的动态缓存,主要是指动态类数据的缓存,包括以下两个类型:
动态页面的缓存。例如,对.do、.jsp、.asp/.aspx、.PHP、.js(nodejs)等动态页面进行缓存。
对数据库频繁访问查询的热点数据内容进行缓存。
CDN 的技术手段是通过 DNS 智能解析+静态缓存来实现的,功能方面就是将内容提供商的静态资源数据以最快捷的方式分发到离用户尽可能近的地方与用户进行交互,以节省内容重复传输的时间。
动态缓存的实现技术普遍采用 Memcache、Redis。它们都是一款基于内存的 Key/Value 数据库。
Redis 采用的是单进程单线程模式,对 CPU 的利用不够理想。Memcached 采用的是单进程多线程模式,能充分利用多核 CPU。
Redis 不仅支持简单的 k/v 类型的数据,同时还提供 LIST、SET、HASH 等数据结构的存储。
Memcache 不支持持久化,Redis 支持 RDB/AOF 将内存数据保存在磁盘内。
Memcache 需要在代码层通过 HASH 算法进行分布式,而 Redis 自带主从、分片集群策略。
关于数据库缓存 1、提高性能,数据库缓存的数据基本上都是存储在内存中的,相比 I/O 读写的速度,数据访问能更快速返回。2、对于数据库的增、删、查、改,数据库缓存技术应用场景绝大部分针对的是“查”的场景。3、在绝大多数的应用中,缓存中的数据和数据库中的数据是不一致的。4、缓存为数据库分担了很多压力,同时也为应用提供了较高的访问速度。
在分布式架构中,负载均衡的引入会导致文件存储需要集中管理,并且会出现 Session 会话的问题。在 Session 会话保持的技术中,通过动态缓存相应技术(Redis/Memcache)来集中存储及管理 Session 是比较成熟的架构。
Session 是程序中用于和客户端请求进行会话保持的一种技术。PHP 会默认将 Session 数据存在本机磁盘文件上,而 Tomcat 会默认将 Session 数据存放至 JVM 分配的内存中。
基于源 IP 的会话保持,是指负载均衡识别客户端请求的源 IP 地址,将同一 IP 地址的请求转发到同一台后端服务器进行处理。若将客户端的请求绑定在后端某一台服务器上,不让请求轮询到其他服务器上,那么就不会出现 Session 会话的问题。
为了解决基于源 IP 会话保持所带来的后端流量不均衡的问题,出现了基于浏览器 Cookie 的会话保持,它很好地解决了该问题。哪怕再多人共用一个 IP 也不用担心,因为客户端是根据客户端请求的 Cookie 进行转发的。七层 SLB 的会话保持,就是基于 Cookie 的会话保持的。
七层 SLB Cookie 处理主要分为以下两种。
1)植入 Cookie:指客户端第一次访问时,负载均衡会在返回请求中植入 Cookie,下次客户端携带此 Cookie 访问,负载均衡会将请求定向转发给之前记录到的后端服务器上。
2)重写 Cookie:根据需要指定 HTTP/HTTPS 响应中插入 Cookie,在后端服务器上维护该 Cookie 的过期时间和生存时间。
Session 除了可以存放在本地内存中以外,当然也可以存放在本地磁盘文件上。存放在本地内存中的数据,服务器宕机、内存数据丢失,都会导致 Session 丢失,但可以通过 Redis/Memcache 等动态缓存技术将 Session 进行集中管理并共享。
Nginx 的动态页面缓存,主要通过 HTTP 反向代理(负载均衡)内置 Proxy 模块的 proxy_cache 实现。基本上可以实现所有动态页面的缓存,当然,静态页面也能缓存。Nginx 内置 Proxy 模板 proxy_cache 实现动静态缓存,缓存文件是存放在磁盘文件中的。在高并发访问的场景中,磁盘 I/O 可能是性能的瓶颈点。
Nginx 内置的 Memcached 模块 ngx_http_memcached_module,虽然实现了对 Memcached 的访问。但是数据的 put 存储,还要需要通过代码来操作。可以通过第三方模块 memc-nginx 和 srcache-nginx 构建高效透明的缓存机制。
PHP 的动态页面缓存是通过 FastCGI 自带的缓存实现的,而不需要通过 Nginx 反向代理来设置对应的缓存配置。FastCGI 也是将缓存文件存放在磁盘文件中的。在高并发访问的场景中,磁盘 I/O 也可能是性能的瓶颈点。
版权声明: 本文为 InfoQ 作者【穿过生命散发芬芳】的原创文章。
原文链接:【http://xie.infoq.cn/article/703f0183a0541c344851314e7】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论