2.2 Apache层次结构
整个Apache可以被划分为四个大的层次:可移植运行库层(APR)、Apache核心功能层(Apache CORE)、Apache可选功能层(Apache Optional Module)及Apache第三方支持库。图2-3描述了Apache中的层次关系。
图2-3 Apache的体系结构
从图2-3中可以看出,加上操作系统层,整个Apache可以被分隔为五层,各层次的功能如下。
2.2.1 操作系统支持层
Apache 归根结底是建立在操作系统的普通的应用程序上的,因此,很多时候必须使用操作系统本身提供的底层功能,比如进程和线程、进程和线程间的通信、网络套接字通信、文件操作等。离开了操作系统,Apache就失去了存在的根基。对Apache而言,目前它能够支持五大操作系统:Unix、OS/2、Window、MacOS及Netware。Unix又可以细分为不同的版本,比如HP-UX、Solaris、Linux等,Window则从Window 9X系列到最近的Window Server 2003,甚至Window CE。不过最早的Apache版本,比如1.3以前的,只运行于Unix平台上。
2.2.2 可移植运行库层
早期的Apache设计者并没有把跨平台作为Apache的设计目标之一,那时候Apache只能运行于Unix家族的操作系统中,也许Apache设计者认为服务器应用最好的归宿还是Unix系列的操作系统。不过从Apache 2.0开始,Apache就开始尝试移植到其他的操作系统中,包括Window、OS/2及Netware等。不同的操作系统提供的底层API是不同的,甚至存在着很大的差异。对于Apache设计者而言,除了考虑WWW和服务器功能的实现之外,还必须考虑不同操作系统的API细节问题。显然,合理的做法就是将不同操作系统的底层细节封装起来形成操作系统API的适配并将其隐藏起来。
因此,从Apache 2.0开始,Apache就将专门封装不同操作系统API的任务独立出来形成一个新的项目APR,全称为Apache可移植运行库(Apache Portable Runtime,APR)。APR 的任务就是屏蔽底层的操作系统 API 细节,对于所有的操作系统,提供一个完全相同的函数接口。这样,Apache开发者就不必顾虑操作系统细节,而只要开发上层功能即可。
比如对于进程创建,APR函数抽象可以用图2-4描述。
图2-4 APR函数抽象
不同的操作系统提供的创建进程的 API 是不同的,Unix 下通用的是 fork(),Windows下则是CreateProcess(),OS/2、Netware及BeOS中的API也迥然不同。APR将所有的创建细节封装起来,提供了统一的对外接口apr_proc_create()。这样,APR的使用者如果要创建进程,则只须调用apr_proc_create(),不管它将要运行于哪个操作系统平台。
APR 的独立带来的另一个潜在的益处就是它将最终形成一个独立的可移植运行库。因此,实际上任何应用程序如果要考虑跨平台,都可以使用它作为底层的支持。
APR中也使用了一些第三方的开源库,比如支持正则表达式的PCRE库、支持XML解析的expat库等。
关于APR的更多实现细节我们会在本系列的第3卷中做非常深入的分析,如果想进一步了解,请参考第3卷,本处不再赘述。
2.2.3 核心功能层
对于Apache而言,其最核心的功能则位于第三层,我们称之为核心功能层。这层主要包括两大部分:Apache核心程序和Apache核心模块。
Apache的核心程序主要用于实现Apache作为HTTP服务器的基本功能,这些基本功能包括:
■ 启动和停止Apache。
■ 处理配置文件(config.c)。
■ 接受和处理HTTP连接。
■ 读取HTTP请求并对该请求进行处理。
■ 处理HTTP协议。
核心层的另外一个重要组成部分就是核心模块。Apache 中大部分模块都是可选择的,这意味着对于Apache而言是可有可无的。这些模块的缺失至多影响Apache功能的完整性,并不影响运行,比如mod_ssl、mod_alias等。但是有两个模块则是必需的,即mod_core和mod_so。前者负责处理配置文件中的大部分配置指令,并根据这些指令运行 Apache,而后者则负责动态加载其余的模块,缺少了该模块,其余的模块就无法使用。这两个模块都必须静态编译。
对于Apache而言,另外一个重要的模块就是MPM,即多进程处理模块。尽管MPM也是属于可选择的,但是它通常负责处理Apache中的并发模型,或者是Prefork,或者是线程池(ThreadPool),或者是 Worker 模型等。大多数情况下,它们总是会被加载,因此我们也将其视为核心的模块。
Apache核心(第三层)主要有以下两个作用。
1. 基本的HTTP服务功能
Apache 核心必须提供最基本的资源处理,或者通过文件描述符,或者通过内存段等来提供;维护多进程运行模型;在配置好的虚拟主机上侦听TCP/IP套接字;将接收到的客户端请求传递给特定的处理进程,处理HTTP协议状态,提供基本的读入和写入缓冲区等。另外,核心部分还提供一些通用的功能,比如URL及MIME头部解析,DSO模块加载等。
2. Apache Module API
Apache最基本的核心功能由Apache核心完成,除此之外,核心无法提供的功能则全部由模块提供。为了允许这些模块能够完全控制Apache的处理,Apache核心必须提供对应的API。在Apache中,这些API是指每个模块中包含一系列的函数(核心在处理HTTP请求的时候用来将消息传递给模块),以及一系列的以“apr”开始的函数,这些API我们将在第3卷中深入讨论和分析。每一个请求都会被划分为多个不同的阶段去处理,Apache中称之为“挂钩”。每个模块如果要对某个阶段进行必要的处理,则它只要实现该挂钩即可。在每一阶段,模块可以通过返回OK或DECLINE来表示是否要完成该步骤的任务。
更多Apache模块的API,可以参考第3卷。
2.2.4 可选功能层
可选功能层通常指Apache模块。如前所述,除了mod_core和mod_so模块之外,其余的模块都属于可选模块,在必要的时候可以被 mod_so 模块加载到 Apache 中,而在不需要的时候也可以从Apache中卸载。比如,如果需要Apache服务器支持安全套接字层(Secure Socket Layer,SSL),那么毫无疑问,我们必须将mod_ssl模块加载到核心中。目前Apache中的大部分代码都是使用 C 语言编写的,如果你要支持使用 Perl 编写的模块,那么你就必须将mod_perl模块也加载到服务器中。
目前,Apache 中的模块很多,Apache 能够支持的完整的注册过的模块信息可以在http://modules.apache.org上查看。人们利用这个Web站点注册Apache模块,就可以让他们追踪自己的模块开发过程,也可以让其他用户找到感兴趣的模块。当然,并不是所有的模块都会注册。如果你需要的模块在注册表中查找不到,那么唯一的方法就是你自己进行编写。事实上,Apache模块的编写是扩展Apache功能的重要手段。本卷中我们将深入Apache的模块体系结构,并亲手编写自己的模块。
2.2.5 第三方支持库
在Apache的一些模块中会使用到第三方的开发库,比如mod_ssl就使用了OpenSSL, mod_perl则使用了Perl开发库。这些第三方支持库虽然被Apache使用,但严格来说它们并不属于Apache的一部分。因此我们不再讨论。
在Apache的五层体系结构中,我们最感兴趣的就是第二、三、四层。事实上,这三层的每一层正好对应本书系列的每一卷。本书的第3卷致力于分析第二层APR的实现细节;本卷则致力于分析第三层Apache的核心;第2卷则致力于分析Apache中其余的重要模块,当然并不是所有的模块都会分析。
2.2.6 Apache工具包
除了上面五个主要的层次之外,Apache中还包括一些辅助的开发工具包,包括Shell脚本和源代码。比如为了方便Apache服务器管理员进行管理工作,Apache中还提供了一些小工具用来处理密码文件,以及从日志文件中生成统计信息等。