`
nanjingjiangbiao_T
  • 浏览: 2606990 次
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

缓存服务器设计与实现(二)

 
阅读更多
我们现在讨论算是最简单的情景,即服务器还没有文件缓存,第一个需要缓存的请求的处理过程。当然需要关注的情景有很多,一个一个来吧。

在缓存服务器设计与实现(一)中讨论的都是一些准备工作,我们接下来要关注从后端机器取回数据以后进行缓存的情景。首先来探讨一个问题,以nginx为例,它是在取后端数据之前就创建了缓存对象,那么从整个系统的角度来看,创建缓存对象的过程包括在内存中建立相应的控制结构,并且在磁盘上创建实体(文件的形式)。那么我们需要关注的是这两部分都有些什么成分?先看磁盘上的文件,它应该存什么。存储实际文件内容是必然的,这就够了吗?

我们知道作为一个http缓存系统,首先它是一个完整的http服务器。所以在响应一个客户端的请求时,必须先给出一个http响应头,然后才是内容。当nginx作为一个静态http服务器工作的时候,响应头是nginx自己构造的,想怎么搞都可以。但是当它作为一个缓存服务器使用时,响应头应该尽量跟被代理的后端服务器一致,甚至严格一致。那么此时,响应头神马的就不能自己杜撰了。从这个角度上来讲把响应头头跟文件内容同时缓存起来是合适,也是必要的。你可以尝试打开一个nginx缓存好的文件,就会发现在具体内容之前确实是保存着相应的响应头的。不过在文件的最开始(响应头之前)貌似还有一些东西,关于这些神秘的东西,随着我们的讨论,都会搞清楚的。其实几乎所有的http缓存服务器都是这么做的,即将http响应头和内容都缓存在文件中。

刚才我们关注的是缓存对象在磁盘上的内容组织,下面我们再看一下内存中的控制结构。

在nginx中每个文件都在内存中都有相应的控制结构,称为一个node。这个结构是在共享内存中申请和管理的,为什么用共享内存?nginx作为多进程模型,我们希望在worker A中缓存的文件对象,在worker B中相同请求到来时也能够hit该对象,要不然就太废了。当然互斥也是不可避免的。

在nginx具体实现中,这个node是结构体ngx_http_file_cache_node_t。关于这个结构中各个成员的说明,可以参考http://www.pagefault.info/?p=375,这里就不多说了。当一个node首次创建之后,需要放入到系统的缓存管理体系中,nginx用到的是红黑树,所有的node都被插入到树里面,然后还要放到lru队列中,作用就是在存储空间不够的时候,通过lru来删掉一些对象。我们的cache在lru方面跟nginx是一致的,但是所有node是通过hash表来管理的。

其实细节需要讨论的东西实在是太多。现在还是先转到重点上来,来看一下nginx如何将收到的后端数据写到本地磁盘文件里去。

核心思想是这样的,nginx首先会将数据写到一个临时文件中去,然后内容收完之后,再将这个临时文件rename到实际的目标文件。这是主要框架,至于如何管理临时文件,又该如何去实现,nginx有它的处理,我们自己实现一套也可以,这都是一些无关紧要的细节了。重点的问题其实是要维护我们的缓存系统中有关当前缓存文件的状态,缓存过程是OK的,该怎么处理,出现异常之后,又该如何处理。

先看当这个文件缓存ok的时候,该如何更新缓存信息,来声明文件已经缓存完毕,可供使用了。这里还是以nginx为例:
在文件获取完成之前,缓存对象的node节点结构中exists成员一直为0,当缓存正常结束时exists就会被置1。所以这个成员的含义就很明确了。这里注意的是,缓存对象的node节点信息位于共享内存中红黑树中,是唯一的。而每个request通过一个cache成员,来跟这个node发生联系。

现在有一个相同的请求过来,首先要做的事情就是查找是否有已经缓存的目标文件。如果文件存在,一般需要先将文件开始部分的一些控制和管理信息读取出来,通过分析这些信息来判断该文件是否是可用的,如未过期或者完好等等。如果可用,那么剩下的工作就是发送内容了,不过在实际发送之前,一般需要先将读取出来的响应头做一些header filter的处理等等,后面的文件内容一般直接发送就好了。

先做一个阶段性的总结吧。到目前为止,我们看到的过程包括:第一个请求到来->去后端取数据缓存;同样的请求到来->发现了刚刚创建的文件->文件可用->发送这个文件。从nginx实现上看,它的ngx_http_file_cache_node_t结构中有两个成员需要注意,一个是count,表示当前正在使用这个node的请求数,另一个成员uses记录了到目前为止,这个node被访问的次数,这个值是一直累加的。

如果一个文件过期了,此时当有请求再次访问到这个文件时,该如何处理呢?这里应该提一下跟cache相关的管理进程(后面会拿出篇幅来重点讨论他们),这其中有一个非常重要的后台程序,它跟普通的worker进程一样,是由master进程fork出来的。ps命令看到的进程title一般为:“nginx: cache manager process”,它的一个重要的作用就是监控过期,做lru等工作。我们把这个manager进程发现过期的情景称为主动发现,worker进程在处理请求时也会发现某个对象过期,这个称为被动发现。能做到这些,它的基础就在于管理缓存对象的控制结构及其信息是由master进程通过共享内存创建并初始化的,这样manager和worker在被fork之后,这些信息就是共享的了。manager进程在运作时,从lru队列的尾部开始,检查是否有文件过期。有过期的就删掉。至于为什么从lru队列的尾部检查,是因为在worker处理对象的时候,每次hit一个文件(一个正常的文件必然位于lru队列中),该文件就从队列中删掉,然后插到队列头部去,所以越靠近尾部的对象,越是较长时间没有被访问到的,LRU的思想也在于此。当然一直以来很多人都在批评这种处理,说它不科学不严谨。是的,这点没错。网上有很多更高级更严谨的lru理论及实现,但是在实际应用中我们不能死磕理论,往往需要结合系统复杂度,实现难易等各方面的考虑。我们自己的cache,包括squid,nginx都是用的这种最简单处理方式,而事实也表明:运行表现不错。

貌似扯远了。我们现在重点关注当worker进程发现了一个对象过期时,它会如何去处理。首先一个问题就是进程如何发现一个文件时过期的?其实在一个文件的开头部分,存放了一些有关文件的控制头信息,前面已经提过了。这个头信息中有相关的变量标记这个对象保鲜时间,所以只需要读出这个变量跟当前时间比较一下就可以了。
从系统的控制结构来看,有个名叫updating的变量此时会被置1。后续的处理就很显然,就是去后端取新文件了。注意此时这个文件相关的管理结构还未被从系统里释放,所以后续的请求还是会hit,不过后面的处理还是会发现过期,这样只要一个请求在更新完成之前,对于该文件的请求,都会去后端取文件(即透传)。前面我们分析过了,nginx会先用临时文件来保存数据,完整取完之后会rename到缓存目录下去。那么当文件过期,但此时有又同一并发请求,那么最后谁去rename呢?说得这里就不得不提另外一个rename,那就是针对一个文件的首次并发请求,各个请求都是独立取源,最后也会出现同时rename的情况。呵呵,看一篇文章吧:http://www.ibm.com/developerworks/cn/linux/l-cn-fsmeta/

上面讲到nginx会出现并发取源的情况,很多公司对这块进行了定制。最常提到的是所谓取源合并。顾名思义,就是合并回源的请求。这项功能,nginx在比较新的版本里面已经支持了,使用的指令时proxy_cache_lock。官方wiki给出的说明:

syntax: proxy_cache_lock on | off;
default: proxy_cache_lock off;
context: http, server, location
This directive appeared in version 1.1.12.
When enabled, only one request at a time will be allowed to populate a new cache element identified according to the proxy_cache_key directive by passing a request to a proxied server. Other requests of the same cache element will either wait for a response to appear in the cache, or the cache lock for this element to be released, up to the time set by the proxy_cache_lock_timeout directive.

另外一个地方就是当文件过期时,也会产生大量的并发回源量。这点nginx也做了处理,很多公司也对这块做了自己的定制。nginx通过指令proxy_cache_use_stale来控制在文件过期更新过程的回源请求量,让当一个请求在更新文件时,其他请求则暂时使用过期文件。具体配置为proxy_cache_use_stale updating;关于该指令的具体用法,大家可以去官网查阅。

还有一些机制,后面再接着讨论。
分享到:
评论

相关推荐

    web代理服务器缓存设计

    web代理服务器缓存技术设计方案,几种常用算法策略,原理实现。

    网络代理服务器的设计与实现

    本文首先介绍了代理服务器的工作原理和功能以及HTTP协议,从理论上和实践上论证了设计和实现代理服务器的可行性,然后重点在于分析和设计一个应用于局域网的代理服务器,其中详细讨论了安全机制、缓存技术以及管道流...

    Fikker设计与实现V3

    Fikker缓存加速服务器设计与实现,包含了详细的网络设计,缓存技术设计,容错处理,gzip 设计,防盗链设计,主机管理设计,转向设计等。采用 C 语言实现。 目录: 1. 系统说明 2. 全非阻塞(non-block)网络设计 ...

    基于Python实现的HTTP代理服务器设计.zip

    要求能缓存原服务器响应的对象,并能够通过修改请求报文(添加if-modified-since头行),向原服务器确认缓存对象是否是最新版本。(选作内容,加分项目,可以当堂完成或课下完成) (3)扩展HTTP代理服务器,支持如下...

    论文研究-一种新型流媒体代理服务器的设计与实现 .pdf

    一种新型流媒体代理服务器的设计与实现,刘玮哲,,本文结合CDN完全缓存和流媒体前缀缓存技术,设计和实现一种新型流媒体代理缓存服务器。该代理服务器处在网络边缘,对用户请求的节

    基于C++设计与实现HTTP代理服务器【100011743】

    设计并实现一个基本 HTTP 代理服务器。要求在指定端口(例如 8080)接收来自客户的 HTTP 请求并且根据其中的 URL 地址访问该地址所指向的 HTTP 服务器(原服务器),接收 HTTP 服务器的响应报文,并将响应报文转发给...

    基于SpringCloud的绿植养护软件的设计与实现.docx

    目录 第一章绪论 1.1研究背景 1.2研究现状 1.3论文创新点 1.4论文内容与结构 第二章系统需求分析 2.1系统业务需求 2.1.1用户模块 ...4.2. 2 Redis缓存数据库设计 4.3 EMQ服务器部署 4.4业务微服务实现 ......

    服务器概要设计说明.docx

    服务器概要设计说明全文共5页,当前为第1页。服务器概要设计说明全文共5页,当前为第1页。 服务器概要设计说明全文共5页,当前为第1页。 服务器概要设计说明全文共5页,当前为第1页。 目录 功能概述 2 网络通信层 3 ...

    基于HTTP代理服务器的实现的毕业设计,Socket编程技术,借助第三方库实现HTTP协议的解析和封装,使用多线程技术实现并发

    同时,代理服务器还能够实现Web缓存和内容过滤等功能,提高网络性能和安全性。 该代理服务器主要包括三个模块:请求处理模块、响应处理模块和管理模块。其中,请求处理模块用于拦截客户端请求,并将请求转发到真实...

    基于Android的天气预报应用系统设计与实现.zip

    界面采用了viewpager与fragment结合的方式进行设计,每个fragment对应一个城市页面,可以通过滑动进行翻页控制。且为防止多页面造成的卡顿,app会首先进行fragment的初始化缓存,使软件响应速度得到提升。详细介绍...

    <配置服务器概要设计>

    软件描述 配置服务器(Profile Server)管理企业即时通讯系统中的各种配置数据,这些配置数据均是对系统内...因此,配置服务器还负责与对等机的配置数据进行实时同步管理。配置服务器通过实现SPMP协议来实现上述管理。

    服务器硬件技术方案.docx

    服务器虚拟化建设方案 1)建设原则 在系统设计中我们遵循以下原则: ·系统设计的前瞻性: 充分考虑未来5-8年的业务发展的需要。 ·系统设计的先进性: 在经费和技术许可的范围内,引进、吸收和应用先进技术。在...

    服务器硬件组件-RAID控制器、PCI-E.pptx

    项目三 云计算服务器 服务器硬件组件-RAID控制器、PCI-E ...缓存(Cache)是RAID卡与外部总线数据交换的缓冲区,RAID卡先将数据储存在缓存中,再由缓存与外边部据总线做数据交互。极快的缓存存取速度和大缓存容量,大

    基于SSM框架的高并发电子商务平台设计与实现_吴倩.pdf

    为了解决电子商务平台中高并发带来的难题,改善用户体验,本文融入当前业界的主流技术Nginx负载均衡、Redis缓存和MySQL数据库的主从复制等,搭建了一个具有推荐功能的电商平台。该平台整体采用SSM框架;后端使用高性能...

    基于Web的客户关系管理系统的设计与实现 毕业论文

    进入21世纪,随着企业信息化的发展,CRM(Customer ...在.NET平台上设计实现一套CRM软件管理系统,代码逻辑呈三 层垂直结构,功能模块基本实现,并成功部署在IIS服务器上,可 以在客户端通过浏览器进行访问。

    计算机毕业设计-JAVA3D的网络三维技术的设计与实现(源代码+论文+说明)

    Java 3D的网络三维技术设计与实现,涉及到构建一个客户端-服务器架构,其中客户端使用Java 3D API来渲染和交互三维模型,而服务器端则负责处理三维数据的存储、场景的组织和网络通信。 在设计阶段,开发者需要规划...

    基于Java的在线购物系统的设计与实现1.rar

    基于Java的在线购物系统设计与实现如下: 系统架构: 客户端-服务器架构:采用客户端-服务器模式,其中服务器负责处理用户请求、管理商品信息和订单数据,而客户端提供用户界面和交互功能。 分层架构:将系统划分...

    基于SpringBoot的下沉市场交易平台的设计与实现.docx

    运用面向对象思想和面向服务设计思想完成系统的框架设计,研究以 Zookeeper 作为 Dubbo 服务的注册中心来实现远程服务的调用,并配合使用 Nginx 负载均衡来实现后台服务器的合理调度、研究利用 Mycat 数据库中间件...

    nedomi:HTTP媒体缓存服务器

    大多数高速缓存服务器不了解何时代理媒体文件。 考虑到大多数大型meda文件实际上并未从头到尾地被观看的事实,在存储媒体文件时,您可以获得性能和空间。 我们打算实现一种将所有这些因素都考虑在内的缓存算法,并...

    典型的休息服务器:Golang RESTful服务器实现的实用样板

    实用的Golang RESTful服务器实现。 该项目使用作为其构建工具。 应用 项目布局 环境变量配置 运行状况检查和调试API 正常关机 分层架构 依赖注入(使用@ctor批注) 有机酸 数据库事务 HTTP服务器 服务器端...

Global site tag (gtag.js) - Google Analytics