WEB请求处理 学习笔记

1. WEB 服务器

按功能分类,Web Server可以分为:

  • HTTP Server
    • Apache
    • Nginx
    • ...
  • Application Server
    • Tomcat
    • Jetty
    • ...

1.1 HTTP Server

HTTP Server 运行在服务器之上,绑定服务器的IP地址并监听某一个TCP端口来接收并处理HTTP请求,这样客户端就能够通过HTTP协议来获取服务器上的网页(HTML格式)、文档(PDF格式)、音频(MP4格式)、视频(MOV格式)等等资源。

一个HTTP Server关心的是HTTP协议层面的传输和访问控制,所以在Apache/Nginx上你可以看到代理、负载均衡等功能。

  • 客户端通过HTTP Server访问服务器上存储的静态资源(HTML文件、图片文件等等)。
  • 通过CGI/Servlet技术,也可以将处理过的动态内容通过HTTP Server分发,但是一个HTTP Server始终只是把服务器上的文件如实的通过HTTP协议传输给客户端。

关于 Apache 与 Nginx 的对比,参见 LAMP 性能优化。

1.2 Application Server

Application Server 是一个应用执行的服务器。

  • 它首先需要支持开发语言的 Runtime(对于 Tomcat 来说,就是 Java),保证应用能够在应用服务器上正常运行。
  • 其次,需要支持应用相关的规范,例如类库、安全方面的特性。
  • 与HTTP Server相比,Application Server能够动态的生成资源并返回到客户端。

对于 Tomcat 来说,就是需要提供 JSP/Sevlet 运行需要的标准类库、Interface 等。为了方便,应用服务器往往也会集成 HTTP Server 的功能,但是不如专业的 HTTP Server 那么强大,所以 Application Server 往往是运行在 HTTP Server 的背后,执行应用,将动态的内容转化为静态的内容之后,通过 HTTP Server 分发到客户端。

Tomcat 运行在 JVM 之上,它和HTTP服务器一样,绑定IP地址并监听TCP端口,同时还包含以下指责:

  • 管理 Servlet 程序的生命周期;
  • 将 URL 映射到指定的 Servlet 进行处理;
  • 与 Servlet 程序合作处理 HTTP 请求:根据HTTP请求生成 HttpServletRequest 对象并传递给 Servlet 进行处理,将 Servlet 中的 HttpServletResponse 对象生成的内容返回给浏览器;

所以 Tomcat 属于是一个 Application Server,更准确的来说,是一个Servlet/JSP 应用的容器。

Apache 与 Tomcat 整合使用:
虽然 Tomcat 也可以认为是HTTP服务器,但通常它仍然会和 Apache/Nginx 配合在一起使用:

  • 动静态资源分离:运用 Nginx 的反向代理功能分发请求:
    • 所有动态资源的请求交给 Tomcat;
    • 静态资源的请求(例如图片、视频、CSS、JavaScript文件等)则直接由
      Nginx 返回到浏览器,这样能大大减轻 Tomcat 的压力;
  • 负载均衡:当业务压力增大时,可能一个 Tomcat 的实例不足以处理,那么这时可以启动多个 Tomcat 实例进行水平扩展,而 Nginx 的负载均衡功能可以把请求通过算法分发到各个不同的实例进行处理;

2. 什么是CGI

CGI 全称是 通用网关接口 (Common Gateway Interface),是 HTTP 服务器与外部应用程序进行“交谈”的一种工具,其程序须运行在网络服务器上,是一种根据请求信息动态产生响应内容的接口协议。
CGI 可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。如 PHP,Perl,TCL 等。

通过CGI,HTTP Server可以将根据请求启动不同的外部程序,并将请求内容转发给该程序,在程序执行结束后,将执行结果作为回应返回给客户端。
所以,CGI的定义是:外部应用程序与HTTP 服务器之间的接口协议。

CGI程序通过标准输入(STDIN)和标准输出(STDOUT)来进行输入输出。
HTTP服务器和CGI接口另外设置了一些环境变量,用来向CGI程序传递一些重要的参数,例如:

  • QUERY_STRING
  • SERVER_NAME 等等

具体参见 CGI 环境变量

每当客户请求CGI的时候,HTTP服务器就请求操作系统生成一个新的CGI解释器进程(如php-cgi.exe),CGI的一个进程则处理完一个请求后退出,下一个请求来时再创建新进程。当然,这样在访问量很少没有并发的情况也行。可是当访问量增大,并发存在,这种方式就不适合了。于是就有了FastCGI。

3. 什么是FastCGI

FastCGI 像是一个常驻(long-live)型的CGI,它可以一直执行着,只要激活后,不会每次都要花费时间去 fork 一次。
FastCGI 是语言无关的、可伸缩架构的 CGI 开放扩展,其主要行为是将 CGI 解释器进程保持在内存中并因此获得较高的性能。

FastCGI工作原理:

  • HTTP Server启动时载入FastCGI进程管理器(例如Apache Module);
  • FastCGI进程管理器自身初始化,启动多个CGI解释器进程(可见多个php-cgi)并等待来自HTTP Server的连接;
  • 当客户端请求到达HTTP Server时,FastCGI进程管理器选择并连接到一个CGI解释器。HTTP Server将CGI环境变量和标准输入发送到FastCGI子进程php-cgi;
  • FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回HTTP Server。

4. 什么是PHP-CGI

PHP-CGI 是 PHP 自带的 FastCGI 管理器。PHP-CGI的不足:

  • PHP-CGI变更php.ini配置后,需重启PHP-CGI才能让新的php-ini生效,不可以平滑重启;

5. 什么是PHP-FPM

PHP-FPM 是一个 PHP FastCGI 管理器,是只用于 PHP 的,使用 PHP-FPM 来控制 PHP-CGI 的 FastCGI 进程,它负责管理一个进程池,来处理来自Web服务器的请求。
PHP-FPM提供了更好的PHP进程管理方式,可以有效控制内存和进程、可以平滑重载PHP配置,比Spawn-FCGI具有更多优点,所以被PHP官方收录了。在PHP 5.3.3中可以直接使用PHP-FPM了。
Apache+PHP配合使用,会在Apache配置下面一段:
LoadModule php5_module C:/php/php5apache2_2.dll

当 PHP 需要在 Apache 服务器下运行时,一般来说,它可以模块的形式集成,此时模块的作用是接收 Apache 传递过来的 PHP 文件请求,并处理这些请求,然后将处理后的结果返回给 Apache。

6. 什么是Servlet

与CGI不同的是,Servlet对每个请求都是单独启动一个线程,而不是进程。
Servlet和JSP两者分工协作:

  • Servlet侧重于解决运算和业务逻辑问题
  • JSP则侧重于解决展示问题

Servlet 的框架是由两个 Java 包组成的:

  • javax.servlet:定义了所有的 Servlet 类都必须实现或者扩展的通用接口和类
  • javax.servlet.http:定义了采用 HTTP 协议通信的 HttpServlet 类。

Servlet的 框架的核心是 javax.servlet.Servlet 接口,所有的 Servlet 都必须实现这个接口。在 Servlet 接口中定义了5个方法,其中 3 个方法代表了Servlet的生命周期:

  • init(ServletConfig)方法:负责初始化 Servlet 对象,在 Servlet 的生命周期中,该方法执行一次;该方法执行在单线程的环境下,因此开发者不用考虑线程安全的问题;
  • service(ServletRequest req, ServletResponse res) 方法:负责响应客户的请求;为了提高效率,Servlet 规范要求一个 Servlet 实例必须能够同时服务于多个客户端请求,即 service() 方法运行在多线程的环境下,Servlet 开发者必须保证该方法的线程安全性;
  • destroy() 方法:当 Servlet 对象退出生命周期时,负责释放占用的资源;

一个 Servlet 的配置:


    
    action
    
    org.apache.struts.action.ActionServlet
    
        
        config
        
        /WEB-INF/struts-config.xml
    
    
        detail
        2
    
    
        debug
        2
    
    
    2



    action
    
    *.do

创建 Servlet 对象的时机:

  • 默认情况下,在 Servlet 容器(例如 Tomcat)启动后:客户首次向 Servlet 发出请求,Servlet 容器会判断内存中是否存在指定的 Servlet 对象,如果没有则创建它,然后根据客户的请求创建 HttpRequest、HttpResponse 对象,从而调用 Servlet 对象的 service 方法;
  • Servlet 容器启动时:当 web.xml 文件中如果 元素中指定了 子元素时,Servlet 容器在启动 web 服务器时,将按照顺序创建并初始化Servlet对象;
  • Servlet 的类文件被更新后,重新创建Servlet;

销毁 Servlet 对象的时机:
Servlet 容器停止或者重新启动:Servlet 容器调用 Servlet 对象的 destroy 方法来释放资源。

描述一下Tomcat与Servlet是如何工作的:

WEB请求处理 学习笔记_第1张图片
Servlet 工作原理时序图

CGI与Servlet比较:

  • 对比一:当用户浏览器发出一个Http/CGI的请求,或者说调用一个CGI程序的时候,服务器端就要新启用一个进程(而且是每次都要调用),调用CGI程序越多(特别是访问量高的时候),就要消耗系统越多的处理时间。
    每次调用 Servlet 时并不是新启用一个进程,而是在一个Web服务器的进程中共享和分离线程。
  • 对比二:传统的CGI程序,不具备平台无关性特征,系统环境发生变化,CGI程序就要瘫痪,而Servlet具备Java的平台无关性,在系统开发过程中保持了系统的可扩展性、高效性。

7. Tomcat工作原理

两个核心组件:连接器(Connector)和容器(Container)。

  • Connector组件是负责生成请求对象和响应对象的,Tomcat默认的是HttpConnector,负责根据收到的 Http 请求报文生成 Request 对象和 Response对象,并把这两个对象传递给 Container,然后根据 Response 中的内容生成相应的 HTTP 报文。
  • Container 是容器的父接口,所有子容器都必须实现这个接口,简单来说就是服务器部署的项目是运行在 Container 中的。Container 里面的项目获取到Connector 传递过来对应的的 Request 对象和 Response 对象进行相应的操作。

Tomcat要为一个Servlet的请求提供服务,需要做三件事:

  • 创建一个 request 对象并填充那些有可能被所引用的 Servlet 使用的信息,如参数,头部、查询字符串等。
    一个 request 对象就是 javax.servlet.ServletRequestjavax.servlet.http.ServletRequest 接口的一个实例。
  • 创建一个 response 对象,所引用的 Servlet 使用它来给客户端发送响应。一个response 对象是 javax.servlet.ServletResponsejavax.servlet.http.ServletResponse 接口的一个实例。
  • 调用 Servlet 的 service 方法,并传入 request 和 response 对象。这里Servlet 会从 request 对象取值,给 response 写值。
  • 根据 Servlet 返回的 response 生成相应的 HTTP 响应报文

Connector 分为以下几类:

  • Http Connector,基于 HTTP 协议,负责建立 HTTP 连接。它又分为BIO Http Connector与NIO Http Connector两种,后者提供非阻塞 IO 与长连接 Comet 支持。
  • AJP Connector,基于 AJP 协议,AJP 是专门设计用来为 Tomcat 与 Http 服务器之间通信专门定制的协议,能提供较高的通信速度和效率。如与Apache服务器集成时,采用这个协议。
  • APR HTTP Connector,用C实现,通过JNI调用的。主要提升对静态资源(如HTML、图片、CSS、JS等)的访问性能。

7.1. Apache HTTP Server 与 Tomcat 的三种连接方式

7.1.1 AJP

Tomcat提供了专门的 JK 插件(即常见的 mod_jk)来负责 Tomcat 和 HTTP 服务器的通信。
JK 安装在对方的 HTTP 服务器上之后,当 HTTP 服务器接收到客户请求时,它会通过 JK 过滤 URL。
JK 根据预先配置好的 URL 映射信息,决定是否把请求转发给 Tomcat 处理。
而 JK 是通过 AJP 协议(Apache JServer Protocol)实现 Apache 与 Tomcat 之间通讯的。

AJP 协议是为 Tomcat 与 HTTP 服务器之间通信而定制的协议,能够提供较高的通信速度和效率。
大致来说,是由于以下两个原因,导致 Tomcat 与 HTTP 服务器整合时,采用 AJP 协议通信的效率要高于HTTP 协议:

  • AJP 采用长连接,保持了 Tomcat 与 HTTP 服务器的通信,减少了建立 TCP 连接的开销
  • AJP 采用一定的协议格式,减少了传递报文的数据大小,节省了带宽

使用步骤:

  • 安装 JK,tomcat-connectors-1.2.40-src.tar.gz
  • 配置 Tomcat:
    • 关闭HTTP协议,注释server.xml中的
    • 开启AJP协议,保持server.xml中的
  • 配置 Apache:
    • 修改 /app/apache/conf/httpd.conf
开启虚拟主机:取消注释Include conf/extra/httpd-vhosts.conf
添加JK配置:增加一行Include conf/extra/httpd-jk.conf
  • 创建 /app/apache/conf/extra/httpd-jk.conf
LoadModule jk_module modules/mod_jk.so
JkWorkersFile conf/workers.properties
JkLogFile logs/mod_jk.log
JkLogLevel info
  • 创建 /app/apache/conf/workers.properties
worker.list=tomcat
worker.tomcat.type=ajp13
worker.tomcat.host=192.168.0.103
worker.tomcat.port=8009
  • 修改 /app/apache/conf/extra/httpd-vhosts.conf,增加以下内容:
 JkMount   /*      tomcat
 JkUnMount /*.html tomcat
 JkUnMount /*.jpg  tomcat
 JkUnMount /*.css  tomcat
 JkUnMount /css/*  tomcat
 JkUnMount /js/*   tomcat
 JkUnMount /lib/*  tomcat

7.1.2 http_proxy

这是利用 Apache 自带的 mod_proxy 模块使用代理技术来连接 Tomcat。
http_proxy 模式是基于 HTTP 协议的代理,因此它要求 Tomcat 必须提供 HTTP 服务,也就是说必须启用 Tomcat 的 HTTP Connector。一个最简单的配置如下:

ProxyPass /images !
ProxyPass /css !
ProxyPass /js !
ProxyPass / http://localhost:8080/

在这个配置中,我们把所有 http://localhost 的请求代理到 http://localhost:8080/ ,这也就是 Tomcat 的访问地址,除了 images、css、js 几个目录除外。我们同样可以利用 mod_proxy 来做负载均衡,再看看下面这个配置:

ProxyPass /images !
ProxyPass /css ! 
ProxyPass /js !
 
ProxyPass / balancer://example/

BalancerMember http://server1:8080/
BalancerMember http://server2:8080/
BalancerMember http://server3:8080/

7.1.3 ajp_proxy

ajp_proxy 连接方式其实跟 http_proxy 方式一样,都是由 mod_proxy 所提供的功能。配置也是一样,只需要把 http:// 换成 ajp:// ,同时连接的是 Tomcat 的 AJP Connector 所在的端口。上面例子的配置可以改为:

ProxyPass /images !
ProxyPass /css ! 
ProxyPass /js !
 
ProxyPass / balancer://example/

BalancerMember ajp://server1:8080/
BalancerMember ajp://server2:8080/
BalancerMember ajp://server3:8080/

采用 proxy 的连接方式,需要在 Apache 上加载所需的模块,mod_proxy 相关的模块有 mod_proxy.so、mod_proxy_connect.so、mod_proxy_http.so、mod_proxy_ftp.so、mod_proxy_ajp.so

7.3. 什么是 Catalina

Catalina 就是 Tomcat 服务器使用的 Apache 实现的 Servlet 容器的 名字。

7.2. Tomcat 日志

Tomcat 日志信息分为两类:

  • 运行中的日志,它主要记录运行的一些信息,尤其是一些异常错误日志信息。
  • 访问日志信息,它记录的访问的时间,IP,访问的资料等相关信息。

7.2.1 访问日志

启用访问日志,默认 tomcat 不记录访问日志,如下方法可以使 tomcat 记录访问日志
编辑${catalina}/conf/server.xml 文件:


通过对示例中 pattern 项的修改,可以改变日志输出的内容。
该项值可以为: common 与 combined ,这两个预先设置好的格式对应的日志输出内容如下:

  • common 的值: %h %l %u %t %r %s %b
  • combined 的值: %h %l %u %t %r %s %b %{Referer}i %{User-Agent}i

pattern 也可以根据需要自由组合 , 例如 pattern="%h %l"
对 于各 fields 字段的含义请参照: http://tomcat.apache.org/tomcat-6.0-doc/config/valve.html 中的 Access Log Valve 项。

7.2.2 运行日志

Tomcat日志分为5类:catalina 、localhost 、manager 、admin 、host-manager
日志的级别分为7种:SEVERE (highest value) > WARNING > INFO > CONFIG > FINE > FINER > FINEST (lowest value)

设定日志级别,修改 conf/logging.properties 中的内容,设定某类日志的级别,示例:

  • 设置 catalina 日志的级别为: FINE
    catalina.org.apache.juli.FileHandler.level = FINE
  • 禁用 catalina 日志的输出:
    catalina.org.apache.juli.FileHandler.level = OFF
  • 输出 catalina 所有的日志消息均输出:
    catalina.org.apache.juli.FileHandler.level = ALL

Tomcat下相关的运行日志文件:

  • Cataline引擎的日志文件,文件名:catalina.日期.log

  • 控制台输出的日志,文件名:catalina.out
    除了 System.out 以外,当异常抛出或者是说异常处理的 e.printstrack(),也都采用的是 out 输出。

  • Tomcat 内部代码丢出的日志,文件名:localhost.日期.log
    JSP 页面内部错误的异常,org.apache.jasper.runtime.HttpJspBase.service类丢出的,日志信息就在该文件。

  • Tomcat下默认manager应用日志,文件名:manager.日期.log

  • 应用程序通过log4j.properties:${catalina.base}/logs/probe.log重定向过来的日志


引用:
WEB请求处理三:Servlet容器请求处理
Tomcat与Apache整合
Apache HTTP Server 与 Tomcat 的三种连接方式介绍
日志系统&access日志&相关日志文件
Tomcat日志设定

你可能感兴趣的:(WEB请求处理 学习笔记)