服务器apache/nginx
大概的了解服务器的原理和区别、配置。以及重要的计算机概念。
文章目录
前言
了解下计算机参见的基本概念。
请求运行流程
这里以http请求为例:
浏览器客户端发送请求,通过域名解析到达对应的服务器网卡后,会通过服务器内核处理,内核交给服务器进程处理,
服务器进程(线程)接受到请求, 根据请求的类型(.php .jpg .html)进行转发处理,如果是php后缀,交给php处理器处理,
一般是php-fpm管理的进程php-cgi。 php-cgi处理完后,返回给服务器进程->内核,服务器再返回给浏览器客户端。
这里发生了两次io。一个是客户端请求时的网络io,一个是服务器处理请求时的磁盘io。
线程和进程
线程和进程都是计算机运行的基本单位。单个线程和进程不能够有效的利用现在计算机的多核。所以出现了多线程和多进程。
每个线程进程运行时,都有自己的上下文环境,包括内存和os资源等。
对于网络的请求(一般都是http请求),并不是每个请求都会分配一个线程或者进程去处理,同一个线程会处理多个请求。
为什么会一个线程处理多个请求,这需要考虑线程的切换带来的开销,上下文变更。
对于web请求,真正的瓶颈是发生在网络io和磁盘io。(cpu处理请求并不慢)
io密集型和cpu密集型
web请求大部分是io密集型的请求。因为要查询数据库。
各种io模型
-
阻塞io
-
非阻塞io
-
io复用(select poll epoll)
-
信号驱动io
-
aio(asynchronize io 异步io)
前三种是属于同步io,后两种是异步io的。信号驱动io属于半异步。aio才是真正的全异步。window实现了该种方式。
异步/同步和阻塞/非阻塞
以下的讨论都是在有io的情况并且用户进程和内核交互的情况下。
可以说光光讨论这些概念并没什么用,要放到具体的环境中说。以下只是一种解释。
针对上面的各种io模型
同步io和异步io:除了aio,其他都是异步io,因为其他的模型在做io的时候都是阻塞的(除了信号io只有copy的时候是阻塞的)。
阻塞和非阻塞: 非阻塞io是指内核在做wait和copy的时候,用户进程可以去做其他的事。但是真正io的时候还是阻塞的。
tip: 这里确实很绕口,非阻塞io的io是阻塞的。同步io还可以是非阻塞io。所有epoll这些模型也不叫异步io,而是叫io多路复用。
所以总结下:同步和异步是针对io操作的时候来说的。阻塞和非阻塞是针对io操作的时候用户进程能否做其他的事。
另外io复用对于单个请求的优化是很小的,优势在于能够处理多个请求。
服务器进程向内核操作io需要经历wait和copy两个阶段。wait是内核wait将数据放到buffer中,copy是内核将buffer中的数据copy到服务器进程中。
select poll epoll模型
epoll相对比较高级的地方:避免了轮询。属于io复用异步io非阻塞的模型。(严格来说在copy阶段也属于阻塞的,所以也可以说是半同步io)
一、apache简介
老牌服务器,多模块的优势。核心模块之一是MPM(muilt process module),多重处理模块,用于操作操作系统的资源。
1、 mpm的三种模型
1.1 prefork :
一个请求对应一个进程,多进程,一个进程对应一个线程,使用select模型
1.2 work:
多进程,一个多进程对应多个线程,使用select模型
1.3 event :
类似work,解决了prefork和work在keep-live长连接情况下,线程占用资源不释放的缺点。事件驱动。类似于epoll驱动。
二、apache的线上参数配置手册
1. mpm参数配置示例:
目前项目中使用的是event,应对高并发场景比前两者会好。
具体的参数配置需要根据网站的并发数以及服务器的资源配置。
代码如下:
<IfModule mpm_worker_module>
StartServers 3 //初始化的进程数,缺省最大16,如果需要增大,需要设置ServerLimit 值
MinSpareThreads 75 // 3*25 进程数 * 每个子进程固定的线程数
MaxSpareThreads 250 //最小/最大空闲线程数量,是为了当请求进来的时候可以马上处理
ServerLimit 32 //子进程最大数量(不能开太大,多的话比较耗费资源)
ThreadsPerChild 25 //每个子进程固定的线程数(缺省最大64 ,最高20000)
MaxRequestWorkers 400
//MaxRequestWorkers 最大工作线程数量,当负载不够的情况下,系统会自动创建线程,从上面的配置理论上最大可以达到16*25=400,并发400.
如果不够的话,需要配置serverlimit , 一旦配置了,ThreadsPerChild * ServerLimit (默认的进程数16)需要大于等于MaxRequestWorkers,并且,MaxRequestWorkers的值需要是ThreadsPerChild 的整数倍。
MaxConnectionsPerChild 20000 //需要配置下,避免内存泄漏,指处理了这么多的请求后杀死进程
</IfModule>
更详细的参考这个链接:https://blog.51cto.com/xsboke/1914370
2、超时配置
2.1 KeepAliveTimeout:
适用长连接,多个连接的间隔时间,超过后就会重新建立http连接,负载高的时候会占用连接。
另提一点 :并不是所有的都需要开启keep-live,长连接对于访问静态资源,短时间内多次请求复用连接是有好处的,keep-live 解决了tcp三次握手四次脱手的开销。但是占用了资源。如果系统资源不够用的情况下,可以考虑关闭keep-live。
2.2 timeout:
单次http请求,发送数据的间隔超时时间。不管是客户端发给服务端还是服务端发给客户端,只要发送了数据就重新计时。
2.3 RequestReadTimeout:
:通过reqtimeout_module模块进行设置,防止慢速攻击
RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
参数解释: 设置从客户端接收请求头和主体的超时值,头至少20s,最多40s,按照每接收到到500字节增加一秒。主体为20s超时,也是500字节增加一秒。
2.4 ProxyTimeout :
代理超时时间
二、nginx简介
轻量级,为高性能而生,采用epoll的模型处理请求。多进程,每个work中只有一个线程。支持并发50000。消耗资源小。
一般用来对于静态的请求以及实现反向代理。
tip: 什么是反向代理:隐藏真正访问的对象,访问a,实际访问的是b.
三、nginx的配置调优
1、worker_processes :
默认是1,可以设置为cpu核心数。因为该参数是实际处理请求的进程数,所以设置恰当的值可以提高并发能力。
而cpu核心数 = cpu物理核数 * 超线程数。比如4核的双线程,那么逻辑cpu核心数 = 8;
查询逻辑cpu核数的命令:/proc/cpuinfo| grep "processor"| wc -l
上面的是常规的设置方法,但是专业的做法是根据实际情况设定。
cpu密集型的应用,则按照上面来。
io密集型即存在大量阻塞式进程时,可以配置稍多一些的worker进程数。
2、worker_rlimit_nofile :
进程可以打开的最大文件数,受限制于操作系统,默认为1024,可以通过ulimit -n 查看。现在绝大部分系统都是65535。
所以可以设置该参数的值为65535。
3、worker_connections:
单个进程的同时建立的最大外部连接数。
受两个因素限制,一个是2中设置的参数worker_rlimit_nofile,一个是内存。10w个连接占用的内存大约为50M左右,所以可以说这个参数是受worker_rlimit_nofile的限制的。
四、apache对应php的配置
1.配置apache处理php的方法,参见
https://blog.youkuaiyun.com/qq_27418931/article/details/105841470
五、nginx对应php的配置
1.
六、常见问题
1.apache的常见错误
1、proxy_fcgi:error (70007)The timeout specified has expired: [client 60.186.105.238:59267] AH01075: Error dispatching request to : (reading input brigade)
这个问题是最频繁的,也是最复杂的,造成的原因多种多样,可能是程序的问题(查看php错误日志、php-fpm日志),可能是超时的设置(apache和php的超时,造成超时的原因很多,比如程序的业务特点就是长时间执行但是超时参数不够,或者代码问题造成长时间运行,还有负载高的时候php-fpm进程数不够等造成)
2、Failed to read FastCGI header,(104)Connection reset by peer: [client 60.186.105.238:55312] AH01075: Error dispatching
request to
解决方案:目前先看apache的超时模块够不够使,另外php-fpm的子进程数处理不过来,在内存够用的情况下应该多加几个php-fpm进程来解决。修改php-fpm.conf配置文件
3、报错:[261]Connection reset by peer
apche和php进程进行数据交互时,任何一方超时,则会有一方关闭,这个时候再进行读写操作就会报这个错。