apache相关补充
sendfile机制
1)不用sendfile的传统网络传输过程:
read(file, tmp_buf, len)
write(socket, tmp_buf, len)
2)硬盘 >> kernel buffer >> user buffer >> kernel socket buffer >> 协议栈
3)一般网络应用通过读硬盘数据,写数据到socket来完成网络传输, 底层执行过程:
1>系统调用 read() 产生一个上下文切换:从 user mode 切换到 kernel mode,然后 DMA 执行拷贝,把文件数据从硬盘读到一个 kernel buffer 里。
2>数据从 kernel buffer 拷贝到 user buffer,然后系统调用 read() 返回,这时又产生一个上下文切换:从kernel mode 切换到 user mode。
3>系统调用 write() 产生一个上下文切换:从 user mode 切换到 kernel mode, 然后把步骤2读到 user buffer 的数据拷贝到 kernel buffer(数据第2 次拷贝到kernel buffer),不过这次是个不同的 kernel buffer,这个 buffer和 socket相关联。
4>系统调用 write() 返回,产生一个上下文切换:从 kernel mode 切换到 user mode( 第4 次切换), 然后DMA从 kernel buffer 拷贝数据到协议栈(第4次拷贝)
上面4个步骤有4次上下文切换,有4次拷贝,如果能减少切换次数和拷贝次数将会有效提升性能
4)在kernel 2.0+ 版本中,系统调用 sendfile() 就是用来简化上面步骤提升性能的。sendfile() 不但能减少切换次数而且还能减少拷贝次数
5)用 sendfile() 来进行网络传输的过程:
sendfile(socket, file, len);
硬盘 >> kernel buffer (快速拷贝到kernel socket buffer)>> 协议栈
1>系统调用 sendfile() 过 通过 DMA 到 把硬盘数据拷贝到 kernel buffer被 ,然后数据被 kernel 直接拷贝到另外一个与 socket 相关的 kernel buffer有 。这里没有 user mode 和 kernel mode 之间的切换,在 kernel 中直接完成了从一个 buffer 到另一个 buffer的拷贝。
2>DMA把数据从 kernel buffer 直接拷贝给协议栈,没有切换,也不需要数据从 user mode 拷贝到 kernel mode ,因为数据就在kernel 里。
反响代理功能
1)启用反向代理
ProxyPass "/" "http://www.example.com/"
ProxyPassReverse "/" "http://www.example.com/"
2)特定URL反向代理
ProxyPass "/images" "http://www.example.com/"
ProxyPassReverse "/images" http://www.example.com/
3)示例:
<VirtualHost *>
ServerName www.magedu.com
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
</VirtualHost>
ARP
APR(Apache portable Run-time libraries ,Apache 可移植运行库) 主要为上层的应用程序提供一个可以跨越多操作系统平台使用的底层支持接口库。
在早期的Apache 版本中,应用程序本身必须能够处理各种具体操作系统平台的细节,并针对不同的平台调用不同的处理函数
随着Apache 的进一步开发,Apache 组织决定将这些通用的函数独立出来并发展成为一个新的项目。
这样,APR 的开发就从Apache 中独立出来,Apache仅仅是使用 APR 而已。
目前APR 主要还是由Apache 使用,由于APR 的较好的移植性,因此一些需要进行移植的C 程序也开始使用APR,开源项目比如用于服务器压力测试的Flood loader tester,该项目不仅仅适用于Apache ,http://httpd.apache.org/test/flood
CGI
CGI是为了保证web server传递过来的数据是标准格式的,方便CGI程序的编写者。
web server(比如说nginx)只是内容的分发者。
如果请求/index.html,那么web server会去文件系统中找到这个文件,发送给浏览器,这里分发的是静态数据。
如果请求的是/index.php,根据配置文件,nginx知道这个不是静态文件,需要去找PHP解析器来处理,那么他会把这个请求简单处理后交给PHP解析器。
Nginx会传哪些数据给PHP解析器呢?url要有吧,查询字符串也得有吧,POST数据也要有,HTTP header不能少吧。
CGI就是规定要传哪些数据、以什么样的格式传递给后方处理这个请求的协议。
当web server收到/index.php这个请求后,会启动对应的CGI程序,这里就是PHP的解析器。
接下来PHP解析器会解析php.ini文件,初始化执行环境,然后处理请求,再以规定CGI规定的格式返回处理后的结果,退出进程,web server再把结果返回给浏览器。
CGI程序的性能问题在哪呢?
"PHP解析器会解析php.ini文件,初始化执行环境",就是这个初始化执行环境,标准的CGI对每个请求都会执行这些步骤,所以处理每个时间的时间会比较长。
FastCGI
Fastcgi是用来提高CGI程序性能的。
首先,Fastcgi会先启一个master,解析配置文件,初始化执行环境,然后再启动多个worker。
当请求过来时,master会传递给一个worker,然后立即可以接受下一个请求,这样就避免了重复的劳动,效率自然是高。
而且当worker不够用时,master可以根据配置预先启动几个worker等着,当然空闲worker太多时,也会停掉一些,这样就提高了性能,也节约了资源。
这就是fastcgi的对进程的管理。
php-fpm
是一个实现了Fastcgi的程序,被PHP官方收了。
PHP的解释器是php-cgi,php-cgi只是个CGI程序,他自己本身只能解析请求,返回结果,不会进程管理。
所以就出现了一些能够调度php-cgi进程的程序,比如说由lighthttpd分离出来的spawn-fcgi,php-fpm也是用来调度php-cgi进程的程序。
总结
fastcgi是一个协议,php-fpm实现了这个协议。
修改了php.ini配置文件后,没办法平滑重启,所以就诞生了php-fpm。
修改php.ini之后,php-cgi进程的确是没办法平滑重启的。
php-fpm对此的处理机制是新的worker用新的配置,已经存在的worker处理完手上的活就可以停止了,通过这种机制来平滑过度。
Fastcgi是CGI的升级版,一种语言无关的协议,用来沟通程序(如PHP, Python, Java)和Web服务器(Apache2, Nginx), 理论上任何语言编写的程序都可以通过Fastcgi来提供Web服务。
Fastcgi的特点是会在一个进程中依次完成多个请求,以达到提高效率的目的,大多数Fastcgi实现都会维护一个进程池。
而PHP-fpm就是针对于PHP的,Fastcgi的一种实现,他负责管理一个进程池,来处理来自Web服务器的请求。
目前,PHP-fpm是内置于PHP的。
但是PHP-fpm仅仅是个“PHP Fastcgi 进程管理器”, 它仍会调用PHP解释器本身来处理请求,PHP解释器(在Windows下)就是php-cgi.exe.