Apache 目前一共有三种稳定的 MPM 模式。它们分别是 prefork/worker 和 event,它们同时也代表 Apache 的演变和发展。今天杜老师就聊下 worker 模式!
worker 模式和 prefork 模式相比较,worker 模式使用了多进程和多线程的混合模式,worker 模式也同样会先预派生一些子进程,然后每一个子进程创建一些线程,同时包括一个监听线程,每个请求过来会被分配到一个线程来服务。线程比起进程会更轻量,因为线程是通过共享父进程内存空间,因此,内存的占用会减少一些,在高并发场景下会比 prefork 有更多可用的线程,表现会更优秀一些。另外,如果一个线程出现问题也会导致同一进程下的线程出现问题,如果是多个线程出现了问题,也只是影响 Apache 的一部分,而不是全部的。由于用到多进程多线程,需要考虑到线程的安全,在使用 keep-alive 长连接的时候,某个线程会一直被占用,即使中间没有请求,需要等待到超时才会被释放。
Apache 总是试图维持一个备用或空闲的服务线程池。这样,客户端无须等待新线程或者新进程的建立即可得到处理。在 Unix 中为了能够绑定 80 端口,父进程一般都是以 root 的身份启动,随后,Apache 会以较低权限的用户建立子进程和线程。User 和 Group 指令用于配置 Apache 子进程的权限。虽然子进程必须对其提供内容拥有读权限,但应该尽可能给予它较少的特权。另外,除非使用了 suEXEC ,否则,这些指令配置的权限将被 CGI 脚本继承。
在编译安装 Apache 的过程中,加入参数–with-mpm=worker 即进行编译安装。
也可以使用–enable-mpms-shared=all,这样在编译的时候会在 modules 目录下自动编译出三个 MPM 文件的 so,然后通过修改 httpd.conf 配置文件更改 MPM 即可。
优点:占据更少内存,高并发下表现优秀。
缺点:必须考虑线程安全问题,因为多个子线程是共享父进程内存地址的。如使用 keep-alive 的长连接方式,也许中间几乎没有请求,这时就会发生阻塞,线程会被挂起,需要一直等待到超时才会被释放。如果线程过多,被这样的占据,也会导致高并发场景下的无服务线程可用。
配置 | 说明 |
---|---|
StartServers 3 | 服务启动时初始进程数,默认是 3 |
MinSpareThreads 75 | 最小空闲子进程数,默认是 75 |
MaxSpareThreads 250 | 最大空闲子进程数,默认是 250 |
ThreadsPerChild 25 | 每个子进程产生的线程数量,默认是 25 |
MaxRequestWorkers 400 | 限定同一时间内客户端最大接入请求数量,默认是 400 |
MaxConnectionsPerChild 0 | 每个子进程在其生命周期内允许最大请求数量,如果请求总数已经达到这个数值,子进程将结束,如果设置为 0,子进程将永远不会结束。如该值设置为非 0 值,可以防止运行 PHP 导致的内存泄露 |