深入浅出web服务

来源:互联网 发布:财务金融知乎 编辑:程序博客网 时间:2024/04/30 17:12

对于没有做过web开发的人来说,web开发涉及到的名词似乎特别多,apache,nginx,cgi,php,http,cookie,session。这一大坨东西到底是什么,这里我们就从网络的层面去理清楚这些东西。

1. 什么是HTTP

对于web来说贯穿始终的东西就是HTTP,那么什么是HTTP?官方说法就是Hyper Text Transfer Protocol,从这个名字上面还判断,HTTP是一种协议,并且是一种应用层协议,其对应的传输层协议TCP。所以说到底,HTTP就是建立在TCP基础上的一种应用层协议。


所以简单点说,就是客户端发起连接,然互通过tcp发过来一个数据报,服务器处理以后再回复一个数据报,并关闭连接。这样一次http请求就结束了。所以最初的http模型是一次请求对应一次连接,也就是我们经常看到的,http无状态的特点。

1.1 数据报的格式

根据上面说的过程,就需要在服务器和客户端之间规定一种格式,双方都按照这种格式来解包,http规定的协议格式如下:


用任何一个抓包工具都能看到一个包的全貌,比如头部字段名会包括Accept, Accept-Encoding, Accept-language, cache-control, connection, cookie, host, user-agent等。

而服务器回复的数据报一定含有一个status code,包头包含cache-control, connection, content-encoding, content-type, date, pragma, server, setcookie, transfer-encoding等字段。

后面会挑几个有意思的字段进行说明。

1.2 HTTP之COOKIE

先说cookie。cookie是用来做什么的呢?我们知道http协议本身是说每一次请求都是无状态的,即两次请求之间没有任何逻辑上的关联,http server不知道第二次请求和第一次请求是否来自同一个client。但是作为一个web应用无状态是肯定不满足需求的,一个最典型的例子就是用户的登录态,我们不能要求每次用户想要获取一个页面的时候都重新登录,所以需要一些机制来记录这些状态,cookie和session是最基本的解决方案。

cookie是由浏览器来管理的,其一般保存在客户端内存中,所以生命周期为浏览器会话期间,关闭浏览器以后,cookie会自动消失。当然如果cookie设置了过期时间,也会由浏览器同步在磁盘当中。在每次http请求的过程当中,浏览器会按照一定的原则选择一部分cookie放在http包头当中发给web服务器。所以cookie过长导致的直接结果就是http包体过大,因此http协议对cookie的长度是有限制的。

如何修改cookie呢?我们经常能看到用js或者php来修改cookie的sample code。用js来修改cookie是比较直观的,因为cookie由浏览器来管理,js也是由浏览器来解析的。但是为什么php作为server side的script也能修改cookie呢?就是因为http回包中的set-cookie这个字段,通过这个字段可以告诉浏览器需要修改cookie的哪些字段。

既然提到cookie,就一起说一下session。session也是为了实现状态保存而设计的机制,只是它是存在服务器端的而已。session可以看做是服务器端的一个hash表,默认是以文件的形式存储的,这个hash表的key就是session id,session id会保存在cookie当中,所以每次服务器解开http包以后,根据cookie中的session id就可以在hash表中数据。那么问题就来了,如果用户在浏览器禁掉了cookie,是不是就找不到session了呢?当然不是,仅仅是禁掉cookie还有很多其他的方式可以将其拼在http包当中传回来呀,可以放在包头的其他字段里比如说get参数,也可以放在包体当中,例如post参数,这种事情是不能难倒程序员的

1.3 HTTP之长/短连接

在http1.0当中是没有connection这个字段的,因为在http1.0当中还是一次请求对应一次连接的,即在服务器发出相应以后会主动断开连接。这样会

而在http1.1版本中增加了connection这个字段,并且默认值是keep-alive。它还有一个值是close。keep-alive就是告诉对方这次请求的方式是长连接,即发送相应包以后不要断开连接,即使是错误响应也不要断开连接。

举个例子:

Request

  • connection: keep-alive表示这次请求过后请不要断开连接
  • connection: close表示这次请求后请断开连接

Response

  • connection: keep-alive这次请求以后我不会断开连接
  • connection: close 这次请求以后我会断开连接。

所以说到底request和response当中只要有一个close,就意味着这次请求以后连接会断开。当第一个request和response对都是keep-alive的时候,一个长连接就建立了,这个时候客户端就可以采用pipeline的方式向server来发包了,pipeline方式指的是client无需等待回应而持续性的发送请求,server会按照request的顺序来回复。

长连接带来了新的问题。

1.3.1 超时保护

如果连接建立以后一直处于inactive的状态怎么办?浪费了server一个fd和client的端口。所以需要有超时保护机制,例如在nginx当中可以配置其keepalive_timeout的值。http协议并没有规定server和client的超时时间,可以由开发者任意指定。

1.3.2 分包协议

在短连接模式的时候,由于每次server响应后直接关闭连接,所以client的短只需要判断EOF来判断response包是否结束。而对于keep alive模式,继续用这种方式会极大降低效率。所以引入了content-length和transfer-encoding两个字段。

1.4 HTTP之数据报结束符

当客户端请求一个服务器的静态资源时,服务器清楚响应的消息长度,所以可以用content-length字段告诉client响应数据的长度。

然而如果请求的是一个动态网页,服务器预先是不可能知道相应包的长度,所以可以才用transfer-encoding: trunked模式来传递数据,即一边产生数据一边发送。一次相应由多个trunk构成,最终由一个长度为0的trunk标记结束。每个trunk是一个数据块,在trunk头标记了当前数据块的长度。

2. 什么是Apache和Nginx

如果他们作为http server(当然还有其他的feature),比较简单地理解就是他们是对http协议的一种实现,例如nginx的HTTP模块基本就是按照HTTP协议的RFC文档,把各种情况cover一遍。简单点说,即解包->过滤->转包->过滤->拼包,下图是nginx的一个简要示意图。


3. 一般的web架构是怎样的


上图是一个常见的web架构,由反向代理服务器,http服务器组成,http服务器又分成nginx进程和php进程。

首先,暴露给用户的是一个反向代理服务器,反向代理的存在有几个作用,一是负载均衡,反向代理服务器收到数据包以后会按照一定的负载均衡算法转发到真正的业务服务器上面去,另一个作用是防止攻击,它会按照一定的规则过滤掉很多不合法的请求,从而降低业务机的负载,因为其只是简单地转发,没有真正的业务逻辑,所以即使黑客攻击到了这一层也没有太大的危害。同时反向代理服务器也可以缓存一些静态的资源,进一步降低业务机的负载。

nginx作为http服务器,在整个架构中主要负责hold连接,并不做请求的真正处理,在上图中被画成了一个方块,但其本身也是多进程的结构。


假如对同一台机器上面配置了8个nginx worker,每个worker配置的连接数是1024,那么这台机器hold连接的能力大概是8*1024。

nginx worker和php-fpm的通信方式是通过socket来通信的,所以说nginx和php-fpm可以部署在同一台机器上也可以部署在不同的机器上。

php-fpm是php的一个插件,现在已经集成到了php的核心代码中,是fast-cgi的一种实现。其进程结构和nginx基本类似,都是由一个master进程和多个worker进程构成的。fastcgi规定每过来一个请求,都从进程池里挑选一个进程,来加载并执行一段php脚本,脚本结束以后将进城归还给进程池。所以php-fpm说到底就是一个进程管理器,正如其名字所示(FastCGI Process Manager)。

php-fpm对于其worker进程数的配置由两种static和dynamic。若配置成static表示在fpm启动的时候由master直接fork出max_children的worker数,并且在运行当中这个数字是不变的。而dynamic则表示根据具体的请求动态的fork worker进程,最大值为max_children。那么,这个max_children该如何配置呢?如果worker数过少,那么php-fpm收到nginx的数据请求时发现进程池里面已经没有进程了,直接就会拒绝服务,导致此次http请求以502告终。如果max_children配置过多的话,会占用多余的系统资源,尤其是在static情况下。所以比较适中的办法就是将这个值先配得大一些,然后去观察active的进程数,最后选择一个合适的值。

我们可以看到在fastcgi模式下,一个进程是对应一个请求的,假如说在一台机器上我们配置了300个fastcgi进程,那么其能同时处理的最大请求数就是300个,是远远小于nginx的接入能力的。如果php有一些阻塞调用(如文件上传下载等),当前进程不能处理其他的请求,所以说php-fpm在在这套架构里是瓶颈,如何在此提高性能是一个值得探讨的问题。

当浏览器出现一个错误页或者白页的时候,有可能是任何一个环节出现问题。这就要慢慢的查了。


1 0
原创粉丝点击