本文目录一览:
- 1、phpstudyapache哪个强
- 2、apache-httpd的三种模式
- 3、PHP工程师都要学习什么?就业方向如何?
- 4、linux php5 安装event扩展
- 5、thinkphp中event文件夹是什么意思
- 6、几种常见的PHP超时处理方法
phpstudyapache哪个强
Linux、 Apache、MySQL 和 PHP(或 Perl)是许多 Web 应用程序的 LAMP 架构的基础。有很多基于 LAMP 组件的开源软件包可用于解决各种各样的问题。随着应用程序负载的增加,底层基础设施的瓶颈也会越来越明显,其表现形式就是响应用户请求的速度变慢。
上一篇文章 展示了调优 Linux 系统的方法,还介绍了 LAMP 和性能度量的基础知识。本文重点关注 Web 服务器组件:Apache 和 PHP。
调优 Apache
Apache 是一种高度可配置的软件。它具有大量特性,但每一种都代价高昂。从某种程度上来说,调优 Apache 来说就是以恰当的方式分配资源,还涉及到将配置简化为仅包含必要内容。
配置 MPM
Apache 是模块化的,因为可以轻松添加和移除特性。在 Apache 的核心,多处理模块(Multi-Processing Module,MPM)提供了这种模块化功能性 —— 管理网络连接、调度请求。MPM 使您能够使用线程,甚至能够将 Apache 迁移到另外一个操作系统。-eventmpmphp
每次只能有一个 MPM 是活动的,必须使用 --with-mpm=(worker|prefork|event) 静态编译。
每个请求使用一个进程的传统模型称为 prefork。较新的线程化模型称为 worker,它使用多个进程,每个进程又有多个线程,这样就能以较低的开销获得更好的性能。最新的 event MPM 是一种实验性的模型,为不同的任务使用单独的线程池。要确定当前使用的是哪种 MPM,可执行 httpd -l。-eventmpmphp
选择使用何种 MPM 取决于许多因素。在 event MPM 脱离实验状态之前,不应考虑这种模型,而是在使用线程和不使用线程之间作出选择。表面上看来,如果所有底层模块(包括 PHP 使用的所有库)都是线程安全的,线程要优于分叉(forking)。而 Prefork 是较为安全的选择;如果选择了 worker,则应该谨慎测试。性能收益还取决于您的发布版所附带的库及硬件。-eventmpmphp
无论选择了哪种 MPM,都必须恰当地配置它。一般而言,配置 MPM 包括告知 Apache 怎样去控制有多少 worker 正在运行,它们是线程还是进程。prefork MPM 的重要配置选项如清单 1 所示。-eventmpmphp
清单 1. prefork MPM 的配置
StartServers 50
MinSpareServers 15
MaxSpareServers 30
MaxClients 225
MaxRequestsPerChild 4000
prefork 模型会为每个请求创建一个新进程。多余的进程保持空闲,以处理传入的请求,这缩短了启动延迟。只要 Web 服务器出现,预先完成的配置就会立即启动 50 个进程,并尽力保持 10 到 20 个空闲服务器运行。进程数的硬性限制由 MaxClients 指定。尽管一个进程能够处理许多相继的请求,Apache 还是会取消连接数超过 4,000 以后的进程,这降低了内存泄漏的风险。-eventmpmphp
配置线程化 MPM 与之类似,不同之处只是必须确定使用多少线程和进程。Apache 文档解释了所有必要的参数和计算。
要经过几次尝试和出错之后才能选好要使用的值。最重要的值是 MaxClients。目标在于允许足够多的 workder 进程或线程运行,同时又不会导致服务器进行过度的交换。如果传入的请求超出处理能力,那么至少满足此值的那些请求会得到服务,其他请求被阻塞。-eventmpmphp
如果 MaxClients 过高,那么所有客户机都将体验到糟糕的服务,因为 Web 服务器会试图换出一个进程,以使另一个进程能够运行。而设得过低意味着可能会不必要地拒绝服务。查看高负载下运行的进程数量和所有 Apache 进程所导致的内存占用情况对设置这个值很有帮助。如果 MaxClients 的值超过 256,必须将 ServerLimit 也设为同样的数值,请仔细阅读 MPM 的文档,了解相关信息。-eventmpmphp
apache-httpd的三种模式
apache httpd-2.4
新增模块;
mod_proxy_fcgi(可提供 fcgi 代理)
mod_ratelimit(限制用户带宽)
mod_request(请求模块,对请求做过滤)
mod_remoteip(匹配客户端的 IP 地址)
对于基于 IP 的访问控制做了修改,不再支持 allow,deny,order 机制,而是统一使用 require进行
还新增以下几条新特性;
1、MPM 支持在运行时装载;不过要开启这种特性,在编译安装要启用这三种功能;
--enable-mpms-shared=all --with-mpm=event
2、支持 event
3、支持异步读写
4、在每个模块及每个目录上指定日志级别
5、增强版的表达式分析器
6、每请求配置:If, Elseif
7、毫秒级别的 keepalive timeout
8、基于 FQDN 的虚拟主机不再需要 NameVirtualHost 指令
9、支持使用自定义变量
安装时HTTPd 可以添加许多模块
相关模块解析:
--enable-so:支持动态共享模块(即打开 DSO 支持)
--enable-rewrite:支持 url 重写
--enable-ssl:支持 ssl
--with-ssl=/usr/local/openssl:指定 ssl 安装位置
--enable-cgi:启用 cgi
--enable-cgid:MPM 使用的是 event 或 worker 要启用 cgid
--enable-modules=most:明确指明要静态编译到 httpd 二进制文件的模块,MODULE-LIST为
空格分隔的模块名列表、all 或者 most,all 表示包含所有模块,most 表示包含大部分常用模
块
--enable-mpms-shared=all:启用 MPM 所有支持的模式,这样 event、worker、prefork 就会以
模块化的方式安装,要用哪个就在 httpd.conf 里配置就好了。
--with-mpm=event:指定启用的 mpm 模式,默认使用 enevt 模式,在 apache 的早期版本 2.0
默认 prefork,2.2 版本是 worker,2.4 版本是 event.
--with-pcre=/usr/local/pcre:支持 pcre
--with-z=/usr/local/zlib:使用 zlib 压缩库
--with-apr=/usr/local/apr:指定 apr 的安装路径
--with-apr-util=/usr/local/apr-util:指定 apr-util 的安装路径
--enable-expires:激活彧通过配置文件控制 HTTP 的“Expires:”和“Cache-Control:”头内容,即
对网站图片、js、css 等内容,提供客户端浏览器缓存的设置。这个是 apache 调优的一个重
要选项之一。
--enable-deflate:提供对内容的压缩传输编码支持,一般是 html、js、css 等内容的站点。使
用此参数会打打提高传输速度,提升访问者访问的体验。在生产环境中,这是 apache 调优
的一个重要选项之一。
Apache 的优化配置:
apache 所运行的硬件环境都是对性能影响最大的因素,即使不能对硬件进行升级,也最好
给 apache 一个单独的主机以免受到其他应用的干扰。各个硬件指标中,对性能影响最大的
是内存,对于静态内容(图片、javascript 文件、css 文件等),它决定了 apache 可以缓存多
少内容,它缓存的内容越多,在硬盘上读取内容的机会就越少,大内存可以极大提高静态站
点的速度;对动态高负载站点来说,每个请求保存的时间更多一些,apache 的 mpm 模块会
为每个请求派生出相应的进程或线程分别处理,而进程或线程的数量与内存的消耗近似成正
比,因此增大内存对提高动态站点的负载和运行速度也极为有利
其次是硬盘的速度,静态站点尤为突出,apache 不断的在读取文件并发送给相应的请求,
硬盘的读写是极其频繁的;动态站点也要不断的加载 web 程序(php 等),一个请求甚至要读
取十几个文件才能处理完成,因此尽可能的提高硬盘速度和质量对提高 apache 的性能是有
积极意义的。
最后是 cpu 和网络,cpu 影响的是 web 程序执行速度,网络影响流量大小。
apache 的工作模式:
Apache HTTP 服务器被设计为一个强大的、灵活的能够在多种平台以及不同环境下工作的服
务器。这种模块化的设计就叫做“多进程处理模块”(Multi-Processing Module,MPM),也叫
做工作模式。
Prefork 模式(一个非线程型的):
其主要工作方式是:当 Apache 服务器启动后,mpm_prefork 模块会预先创建多个子进程(默
认为 5 个),每个子进程只有一个线程,当接收到客户端的请求后,mpm_prefork 模块再将
请求转交给子进程处理,并且每个子进程同时只能用于处理单个请求。如果当前的请求数将
超过预先创建的子进程数时,mpm_prefork 模块就会创建新的子进程来处理额外的请求。
Apache 总是试图保持一些备用的或者是空闲的子进程用于迎接即将到来的请求。这样客户
端的请求就不需要在接收后等候子进程的产生。
由于在 mpm_prefork 模块中,每个请求对应一个子进程,因此其占用的系统资源相对其他
两种模块而言较多。不过 mpm_prefork 模块的优点在于它的每个子进程都会独立处理对应
的单个请求,这样,如果其中一个请求出现问题就不会影响到其他请求。Prefork 在效率上
要比 Worker 要高,但是内存使用大得多不擅长处理高并发的场景。
Apache 在 prefork 工作模式下影响性能的重要参数说明
# prefork MPM
IfModule mpm_prefork_module
StartServers 5
#apache 启动时候默认开始的子进程数
MinSpareServers 5
#最小的闲置子进程数
MaxSpareServers 10
#最大的闲置子进程数
MaxRequestWorkers 250
#MaxRequestWorkers 设 置 了 允 许 同 时 的 最 大 接 入 请 求 数 量 。 任 何 超 过MaxRequestWorkers 限制的请求将进入等候队列,在 apache2.3.1 以前的版本-eventmpmphp
MaxRequestWorkers 被称为 MaxClients,旧的名字仍旧被支持。
MaxConnectionsPerChild 500
#设置的是每个子进程可处理的请求数。每个子进程在处理了“MaxConnectionsPerChild”
个请求后将自动销毁。0 意味着无限,即子进程永不销毁。虽然缺省设为 0 可以使每个
子进程处理更多的请求,但如果设成非零值也有两点重要的好处:1、可防止意外的内
存泄漏。2、在服务器负载下降的时侯会自动减少子进程数。因此,可根据服务器的负
载来调整这个值。在 Apache2.3.9 之前称之为 MaxRequestsPerChild。
/IfModule
注 1:MaxRequestWorkers 是这些指令中最为重要的一个,设定的是 Apache 可以同时处理
的请求,是对 Apache 性能影响最大的参数。如果请求总数已达到这个值(可通过 ps -ef|grep
http|wc -l 来确认),那么后面的请求就要排队,直到某个已处理请求完毕。这就是系统资源
还剩下很多而 HTTP 访问却很慢的主要原因。虽然理论上这个值越大,可以处理的请求就越
多,建议将初始值设为(以 Mb 为单位的最大物理内存/2),然后根据负载情况进行动态调整。
比如一台 4G 内存的机器,那么初始值就是 4000/2=2000。
注 2:prefork 控制进程在最初建立“StartServers”个子进程后,为了满足 MinSpareServers 设
置的需要创建一个进程,等待一秒钟,继续创建两 个,再等待一秒钟,继续创建四个……如
此按指数级增加创建的进程数,最多达到每秒 32 个,直到满足 MinSpareServers 设置的值为
止。这种模式 可以不必在请求到来时再产生新的进程,从而减小了系统开销以增加性能。
MaxSpareServers 设置了最大的空闲进程数,如果空闲进程数大于这个 值,Apache 会自动 kill
掉一些多余进程。这个值不要设得过大,但如果设的值比 MinSpareServers 小,Apache 会自
动把其调整为 MinSpareServers+1。如果站点负载较大,可考虑同时加大 MinSpareServers 和
MaxSpareServers。
注 3:ServerLimit 和 MaxClients(MaxRequestWorkers)有什么区别呢?
是因为在 apache1 时代,控制最大进程数只有 MaxClients 这个参数,并且这个参数最大值为
256,并且是写死了的,试图设置为超过 256 是无效的,这是由于 apache1 时代的服务器硬
件限制的。但是 apache2 时代由于服务器硬件的升级,硬件已经不再是限制,所以使用
ServerLimit 这个参数来控制最大进程数,ServerLimit 值=MaxClient 值才有效。ServerLimit
要放在 MaxClients 之前,值要不小于 MaxClients。
注 4:查看 Apache 加载的模块
[root@www ~]#apachectl -t -D DUMP_MODULES
或
[root@www ~]# apachectl -M
或
[root@www ~]# apachectl –l (小写 L,只显示静态模块)
如何查看 Apache 的工作模式呢?可以使用 httpd -V 命令查看,另外使用 httpd -l 也可以查
看到
注 5:如何修改 prefork 参数和启用 prefork 模式
1.[root@www ~]# vi /usr/local/http-2.4.23/conf/extra/httpd-mpm.conf
2.[root@www ~]# vi /usr/local/http-2.4.23/conf/httpd.conf
LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
Include conf/extra/httpd-mpm.conf
3 重启httpd
Worker 模式(多线程多进程):
和 prefork 模式相比,worker 使用了多进程和多线程的混合模式,worker 模式也同样会先预
派生一些子进程,然后每个子进程创建一些线程,同时包括一个监听线程,每个请求过来会
被分配到一个线程来服务。线程比起进程会更轻量,因为线程是通过共享父进程的内存空间,
因此,内存的占用会减少一些,在高并发的场景下会比 prefork 有更多可用的线程,表现会
更优秀一些;另外,如果一个线程出现了问题也会导致同一进程下的线程出现问题,如果是
多个线程出现问题,也只是影响 Apache 的一部分,而不是全部。由于用到多进程多线程,
需要考虑到线程的安全了,在使用 keep-alive 长连接的时候,某个线程会一直被占用,即使
中间没有请求,需要等待到超时才会被释放(该问题在 prefork 模式下也存在)
总的来说,prefork 方式速度要稍高于 worker,然而它需要的 cpu 和 memory 资源也稍多于
woker。
Apache 在 worker 工作模式下影响性能的重要参数说明
# worker MPM
IfModule mpm_worker_module
StartServers 3
#apache 启动时候默认开始的子进程数
MinSpareThreads 75
#最小空闲数量的工作线程
MaxSpareThreads 250
#最大空闲数量的工作线程
ThreadsPerChild 25
#每个子进程产生的线程数量
MaxRequestWorkers 400
#与 prefork 模式相同
MaxConnectionsPerChild 0
#与 prefork 模式相同
/IfModule
注 1:Worker 由主控制进程生成“StartServers”个子进程,每个子进程中包含固定的
ThreadsPerChild 线程数,各个线程独立地处理请求。同样, 为了不在请求到来时再生成线
程,MinSpareThreads 和 MaxSpareThreads 设置了最少和最多的空闲线程数;
而 MaxRequestWorkers 设置了同时连入的 clients 最大总数。如果现有子进程中的线程总数不
能满足负载,控制进程将派生新的子进程
MinSpareThreads 和 MaxSpareThreads 的最大缺省值分别是 75 和 250。这两个参数对 Apache
的性能影响并不大,可以按照实际情况相应调节 。
注 2:ThreadsPerChild 是 worker MPM 中与性能相关最密切的指令。ThreadsPerChild 的最大
缺省值是 64,如果负载较大,64 也是不够的。这时要显式使用 ThreadLimit 指令,它的最大
缺省值是 20000。
注 3:Worker 模式下所能同时处理的请求总数是由子进程总数乘以 ThreadsPerChild 值决定
的,应该大于等于 MaxRequestWorkers。如果负载很大,现有的子进程数不能满足时,控制
进程会派生新的子进程。默认最大的子进程总数是 16,加大时 也需要显式声明 ServerLimit
(系统配置的最大进程数量,最大值是20000)。需要注意的是,如果显式声明了 ServerLimit,
那么它乘以 ThreadsPerChild的值必须大于等于MaxRequestWorkers,而且MaxRequestWorkers
必须是 ThreadsPerChild 的整数倍,否则 Apache 将会自动调节到一个相应值。
注 4:进程与线程的区别
线程是指进程内的一个执行单元,也是进程内的可调度实体.
与进程的区别:
(1)地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程
有自己独立的地址空间;
(2)资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
(3)线程是处理器调度的基本单位,但进程不是.
(4)二者均可并发执行.
进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对
应用的并发性。
进程和线程的区别在于:
简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程
序的运行效率。
Event 模式:
这是 Apache 最新的工作模式,是 worker 模式的变种,它把服务进程从连接中分离出来,一
worker 模式不同的是在于它解决了 keep-alive 长连接的时候占用线程资源被浪费的问题,在
event 工作模式中,会有一些专门的线程用来管理这些 keep-alive 类型的线程,当有真实请
求过来的时候,将请求传递给服务器的线程,执行完毕后,又允许它释放。这增强了在高并
发场景下的请求处理。event 模式不能很好的支持 https 的访问(HTTP 认证相关的问题)。
PHP工程师都要学习什么?就业方向如何?
PHP工程师就业方向有:
编写一定量的PHP代码,学习会使用一些框架。
拓展熟悉Mysql、Web服务器Apache/Nginx,Linux和HTTP协议。搞清楚它们之间的通信模式。
学习“设计模式”,写出优美的代码结构,减少累赘和代码重复,在代码后期维护会带来极大的好处。可以适当去看看框架的PHP源码,里面往往有大量设计模式的应用思想。学习对PHP原生语法的深入了解,了解各种PHP拓展在PHP中扮演的作用,PHP优化。-eventmpmphp
进一步搞清楚PHP和数据库、存储、Web服务器的通信原理(prefork/worker/event MPM,PHP-fpm),阅读PHP内核资料,深入学习Linux原理层。
深入底层路线:深入看下PHP源码(C语言),学习编写PHP拓展。或者走架构师道路,搞清楚Web系统架构(负载均衡、集群部署、容灾保护等),PHP在中间如何将它们连接在一起的。
PHP可以做的工作:
一、服务端脚本
服务器脚本运行模式需要具备3个条件:PHP解析器(CGI或者服务器模块)、Web服务器、Web浏览器。
具体执行流程:首先运行Web服务器,然后安装并配置PHP,最后可以用Web浏览器访问PHP程序的输出,即浏览服务端的PHP页面(或数据输出)。
二、命令行脚本
通过命令行模式运行PHP脚本,这种模式下不需要服务器的支持或者依赖浏览器的触发,在命令行脚本模式下仅需要PHP解析器来执行。通常这种方法被用在Windows和Linux平台下做日常运行脚本使用,如某些守护程序等。当然这些脚本也可以用来处理简单的文本。-eventmpmphp
三、编写客户端的GUI应用程序
对于基于窗口式的应用程序来说,PHP或许不是一种最好的语言,但是如果您非常精通PHP,并且希望在您的客户端应用程序中使用PHP的一些高级特性,您可以利用PHP-GTK来编写这些程序。用这种方法,您还可以编写跨平台的应用程序。PHP-GTK是PHP的一个扩展,在通常发布的PHP包中并不包含它。-eventmpmphp
PHP的就业前景是很不错的。
linux php5 安装event扩展
你好,如果php安装没问题的话,我记得安装这些扩展要用到 phpize 吧
在memcache安装文件目录
/usr/bin/phpize 你改变目录就改变
./configure --with-php-config=/usr/bin/php-config
安装
如果文件位置有变动,你自己慢慢找你的安装目录吧
thinkphp中event文件夹是什么意思
不知你在哪个目录下看到的,如果是在lib目录下的话,event就是分层的意思 给控制器分层
几种常见的PHP超时处理方法
【Web服务器超时处理】
[ Apache ]
一般在性能很高的情况下,缺省所有超时配置都是30秒,但是在上传文件,或者网络速度很慢的情况下,那么可能触发超时操作。
目前apachefastcgiphp-fpm模式下有三个超时设置:
fastcgi超时设置:
修改的fastcgi连接配置,类似如下:
复制代码 代码如下:
IfModulemod_fastcgi.c
FastCgiExternalServer/home/forum/apache/apache_php/cgi-bin/php-cgi-socket/home/forum/php5/etc/php-fpm.sock -eventmpmphp
ScriptAlias/fcgi-bin/"/home/forum/apache/apache_php/cgi-bin/"
AddHandlerphp-fastcgi.php
Actionphp-fastcgi/fcgi-bin/php-cgi
AddTypeapplication/x-
/IfModule
缺省配置是30s,如果需要定制自己的配置,需要修改配置,比如修改为100秒:(修改后重启apache):
复制代码 代码如下:
IfModulemod_fastcgi.c
FastCgiExternalServer/home/forum/apache/apache_php/cgi-bin/php-cgi-socket/home/forum/php5/etc/php-fpm.sock-idle-timeout100 -eventmpmphp
ScriptAlias/fcgi-bin/"/home/forum/apache/apache_php/cgi-bin/"
AddHandlerphp-fastcgi.php
Actionphp-fastcgi/fcgi-bin/php-cgi
AddTypeapplication/x-
/IfModule
如果超时会返回500错误,断开跟后端php服务的连接,同时记录一条apache错误日志:
[ThuJan2718:30:152011][error][client10.81.41.110]FastCGI:commwithserver"/home/forum/apache/apache_php/cgi-bin/php-cgi"aborted:idletimeout(30sec) -eventmpmphp
[ThuJan2718:30:152011][error][client10.81.41.110]FastCGI:incompleteheaders(0bytes)receivedfromserver"/home/forum/apache/apache_php/cgi-bin/php-cgi" -eventmpmphp
其他fastcgi配置参数说明:
复制代码 代码如下:
IdleTimeout发呆时限
ProcessLifeTime一个进程的最长生命周期,过期之后无条件kill
MaxProcessCount最大进程个数
DefaultMinClassProcessCount每个程序启动的最小进程个数
DefaultMaxClassProcessCount每个程序启动的最大进程个数
IPCConnectTimeout程序响应超时时间
IPCCommTimeout与程序通讯的最长时间,上面的错误有可能就是这个值设置过小造成的
MaxRequestsPerProcess每个进程最多完成处理个数,达成后自杀
[ Lighttpd ]
配置:lig
Lighttpd配置中,关于超时的参数有如下几个(篇幅考虑,只写读超时,写超时参数同理):
主要涉及选项:
server.max-keep-alive-idle=5
server.max-read-idle=60
server.read-timeout=0
server.max-connection-idle=360
复制代码 代码如下:
#每次keep-alive的最大请求数,默认值是16
server.max-keep-alive-requests=100
#keep-alive的最长等待时间,单位是秒,默认值是5
server.max-keep-alive-idle=1200
#lighttpd的work子进程数,默认值是0,单进程运行
server.max-worker=2
#限制用户在发送请求的过程中,最大的中间停顿时间(单位是秒),
#如果用户在发送请求的过程中(没发完请求),中间停顿的时间太长,lighttpd会主动断开连接
#默认值是60(秒)
server.max-read-idle=1200
#限制用户在接收应答的过程中,最大的中间停顿时间(单位是秒),
#如果用户在接收应答的过程中(没接完),中间停顿的时间太长,lighttpd会主动断开连接
#默认值是360(秒)
server.max-write-idle=12000
#读客户端请求的超时限制,单位是秒,配为0表示不作限制
#设置小于max-read-idle时,read-timeout生效
server.read-timeout=0
#写应答页面给客户端的超时限制,单位是秒,配为0表示不作限制
#设置小于max-write-idle时,write-timeout生效
server.write-timeout=0
#请求的处理时间上限,如果用了mod_proxy_core,那就是和后端的交互时间限制,单位是秒
server.max-connection-idle=1200
说明:
对于一个keep-alive连接上的连续请求,发送第一个请求内容的最大间隔由参数max-read-idle决定,从第二个请求起,发送请求内容的最大间隔由参数max-keep-alive-idle决定。请求间的间隔超时也由max-keep-alive-idle决定。发送请求内容的总时间超时由参数read-timeout决定。Lighttpd与后端交互数据的超时由max-connection-idle决定。 -eventmpmphp
延伸阅读:
[ Nginx ]
配置:nf
复制代码 代码如下:
http{
#Fastcgi:(针对后端的fastcgi生效,fastcgi不属于proxy模式)
fastcgi_connect_timeout5;#连接超时
fastcgi_send_timeout10; #写超时
fastcgi_read_timeout10;#读取超时
#Proxy:(针对proxy/upstreams的生效)
proxy_connect_timeout15s;#连接超时
proxy_read_timeout24s;#读超时
proxy_send_timeout10s; #写超时
}
说明:
Nginx 的超时设置倒是非常清晰容易理解,上面超时针对不同工作模式,但是因为超时带来的问题是非常多的。
延伸阅读:
ml
ml
ml
【PHP本身超时处理】
[ PHP-fpm ]
配置:nf
复制代码 代码如下:
?xmlversion="1.0"?
configuration
//...
Setsthelimitonthenumberofsimultaneousrequeststhatwillbeserved.
EquivalenttoApacheMaxClientsdirective.
EquivalenttoPHP_FCGI_CHILDRENenvironmentinoriginalphp.fcgi
Usedwithanypm_style.
#php-cgi的进程数量
valuename="max_children"128/value
Thetimeout(inseconds)forservingasinglerequestafterwhichtheworkerprocesswillbeterminated
Shouldbeusedwhen'max_execution_time'inioptiondoesnotstopscriptexecutionforsomereason
'0s'means'off'
#php-fpm 请求执行超时时间,0s为永不超时,否则设置一个 Ns 为超时的秒数
valuename="request_terminate_timeout"0s/value
Thetimeout(inseconds)forservingofsinglerequestafterwhichaphpbacktracewillbedumpedtoslow.logfile
'0s'means'off'
valuename="request_slowlog_timeout"0s/value
/configuration
说明:
在php.ini中,有一个参数max_execution_time可以设置PHP脚本的最大执行时间,但是,在php-cgi(php-fpm)中,该参数不会起效。真正能够控制PHP脚本最大执行时:
valuename="request_terminate_timeout"0s/value
就是说如果是使用mod_php5.so的模式运行max_execution_time是会生效的,但是如果是php-fpm模式中运行时不生效的。
延伸阅读:
[ PHP ]
配置:php.ini
选项:
max_execution_time=30
或者在代码里设置:
ini_set("max_execution_time",30);
set_time_limit(30);
说明:
对当前会话生效,比如设置0一直不超时,但是如果php的safe_mode打开了,这些设置都会不生效。
效果一样,但是具体内容需要参考php-fpm部分内容,如果php-fpm中设置了request_terminate_timeout的话,那么max_execution_time就不生效。
【后端接口访问超时】
【HTTP访问】
一般我们访问HTTP方式很多,主要是:curl,socket,file_get_contents()等方法。
如果碰到对方服务器一直没有响应的时候,我们就悲剧了,很容易把整个服务器搞死,所以在访问http的时候也需要考虑超时的问题。
[ CURL 访问HTTP]
CURL 是我们常用的一种比较靠谱的访问HTTP协议接口的lib库,性能高,还有一些并发支持的功能等。
CURL:
curl_setopt($ch,opt)可以设置一些超时的设置,主要包括:
*(重要)CURLOPT_TIMEOUT设置cURL允许执行的最长秒数。
*(重要)CURLOPT_TIMEOUT_MS设置cURL允许执行的最长毫秒数。(在cURL7.16.2中被加入。从PHP5.2.3起可使用。)
CURLOPT_CONNECTTIMEOUT在发起连接前等待的时间,如果设置为0,则无限等待。
CURLOPT_CONNECTTIMEOUT_MS尝试连接等待的时间,以毫秒为单位。如果设置为0,则无限等待。在cURL7.16.2中被加入。从PHP5.2.3开始可用。
CURLOPT_DNS_CACHE_TIMEOUT设置在内存中保存DNS信息的时间,默认为120秒。
curl普通秒级超时:
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_TIMEOUT,60);//只需要设置一个秒的数量就可以
curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
curl_setopt($ch,CURLOPT_USERAGENT,$defined_vars['HTTP_USER_AGENT']);
curl普通秒级超时使用:
curl_setopt($ch,CURLOPT_TIMEOUT,60);
curl如果需要进行毫秒超时,需要增加:
curl_easy_setopt(curl,CURLOPT_NOSIGNAL,1L);
或者是:
curl_setopt($ch,CURLOPT_NOSIGNAL,true);是可以支持毫秒级别超时设置的
curl一个毫秒级超时的例子:
复制代码 代码如下:
?php
if(!isset($_GET['foo'])){
//Client
$ch=curl_init('');
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_NOSIGNAL,1);//注意,毫秒超时一定要设置这个
curl_setopt($ch,CURLOPT_TIMEOUT_MS,200);//超时毫秒,cURL7.16.2中被加入。从PHP5.2.3起可使用
$data=curl_exec($ch);
$curl_errno=curl_errno($ch);
$curl_error=curl_error($ch);
curl_close($ch);
if($curl_errno0){
echo"cURLError($curl_errno):$curl_errorn";
}else{
echo"Datareceived:$datan";
}
}else{
//Server
sleep(10);
echo"Done.";
}
?
其他一些技巧:
1. 按照经验总结是:cURL版本=libcurl/7.21.0版本,毫秒级超时是一定生效的,切记。
2. curl_multi的毫秒级超时也有问题。。单次访问是支持ms级超时的,curl_multi并行调多个会不准
[流处理方式访问HTTP]
除了curl,我们还经常自己使用fsockopen、或者是file操作函数来进行HTTP协议的处理,所以,我们对这块的超时处理也是必须的。
一般连接超时可以直接设置,但是流读取超时需要单独处理。
自己写代码处理:
复制代码 代码如下:
$tmCurrent=gettimeofday();
$intUSGone=($tmCurrent['sec']-$tmStart['sec'])*1000000
+($tmCurrent['usec']-$tmStart['usec']);
if($intUSGone$this-_intReadTimeoutUS){
returnfalse;
}
或者使用内置流处理函数stream_set_timeout()和stream_get_meta_data()处理:
复制代码 代码如下:
?php
//Timeoutinseconds
$timeout=5;
$fp=fsockopen("",80,$errno,$errstr,$timeout);
if($fp){
fwrite($fp,"GET/HTTP/1.0rn");
fwrite($fp,"Host:rn");
fwrite($fp,"Connection:Closernrn");
stream_set_blocking($fp,true);//重要,设置为非阻塞模式
stream_set_timeout($fp,$timeout);//设置超时
$info=stream_get_meta_data($fp);
while((!feof($fp))(!$info['timed_out'])){
$data.=fgets($fp,4096);
$info=stream_get_meta_data($fp);
ob_flush;
flush();
}
if($info['timed_out']){
echo"ConnectionTimedOut!";
}else{
echo$data;
}
}
file_get_contents超时:
复制代码 代码如下:
?php
$timeout=array(
'http'=array(
'timeout'=5//设置一个超时时间,单位为秒
)
);
$ctx=stream_context_create($timeout);
$text=file_get_contents("",0,$ctx);
?
fopen超时:
复制代码 代码如下:
?php
$timeout=array(
'http'=array(
'timeout'=5//设置一个超时时间,单位为秒
)
);
$ctx=stream_context_create($timeout);
if($fp=fopen("","r",false,$ctx)){
while($c=fread($fp,8192)){
echo$c;
}
fclose($fp);
}
?
【MySQL】
php中的mysql客户端都没有设置超时的选项,mysqli和mysql都没有,但是libmysql是提供超时选项的,只是我们在php中隐藏了而已。
那么如何在PHP中使用这个操作捏,就需要我们自己定义一些MySQL操作常量,主要涉及的常量有:
MYSQL_OPT_READ_TIMEOUT=11;
MYSQL_OPT_WRITE_TIMEOUT=12;
这两个,定义以后,可以使用options设置相应的值。
不过有个注意点,mysql内部实现:
1.超时设置单位为秒,最少配置1秒
2.但mysql底层的read会重试两次,所以实际会是3秒
重试两次+ 自身一次=3倍超时时间,那么就是说最少超时时间是3秒,不会低于这个值,对于大部分应用来说可以接受,但是对于小部分应用需要优化。
查看一个设置访问mysql超时的php实例:
复制代码 代码如下:
?php
//自己定义读写超时常量
if(!defined('MYSQL_OPT_READ_TIMEOUT')){
define('MYSQL_OPT_READ_TIMEOUT',11);
}
if(!defined('MYSQL_OPT_WRITE_TIMEOUT')){
define('MYSQL_OPT_WRITE_TIMEOUT',12);
}
//设置超时
$mysqli=mysqli_init();
$mysqli-options(MYSQL_OPT_READ_TIMEOUT,3);
$mysqli-options(MYSQL_OPT_WRITE_TIMEOUT,1);
//连接数据库
$mysqli-real_connect("localhost","root","root","test");
if(mysqli_connect_errno()){
printf("Connectfailed:%s/n",mysqli_connect_error());
exit();
}
//执行查询sleep1秒不超时
printf("Hostinformation:%s/n",$mysqli-host_info);
if(!($res=$mysqli-query('selectsleep(1)'))){
echo"query1error:".$mysqli-error."/n";
}else{
echo"Query1:querysuccess/n";
}
//执行查询sleep9秒会超时
if(!($res=$mysqli-query('selectsleep(9)'))){
echo"query2error:".$mysqli-error."/n";
}else{
echo"Query2:querysuccess/n";
}
$mysqli-close();
echo"closemysqlconnection/n";
?
延伸阅读:
【Memcached】
[PHP扩展]
php_memcache客户端:
连接超时:boolMemcache::connect(string$host[,int$port[,int$timeout]])
在get和set的时候,都没有明确的超时设置参数。
libmemcached客户端:在php接口没有明显的超时参数。
说明:所以说,在PHP中访问Memcached是存在很多问题的,需要自己hack部分操作,或者是参考网上补丁。
[CC++访问Memcached]
客户端:libmemcached客户端
说明:memcache超时配置可以配置小点,比如5,10个毫秒已经够用了,超过这个时间还不如从数据库查询。
下面是一个连接和读取set数据的超时的C++示例:
复制代码 代码如下:
//创建连接超时(连接到Memcached)
memcached_st*MemCacheProxy::_create_handle()
{
memcached_st*mmc=NULL;
memcached_return_tprc;
if(_mpool!=NULL){//getfrompool
mmc=memcached_pool_pop(_mpool,false,prc);
if(mmc==NULL){
__LOG_WARNING__("MemCacheProxy","gethandlefrompoolerror[%d]",(int)prc);
}
returnmmc;
}
memcached_st*handle=memcached_create(NULL);
if(handle==NULL){
__LOG_WARNING__("MemCacheProxy","create_handleerror");
returnNULL;
}
//设置连接/读取超时
memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_HASH,MEMCACHED_HASH_DEFAULT);
memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_NO_BLOCK,_noblock);//参数MEMCACHED_BEHAVIOR_NO_BLOCK为1使超时配置生效,不设置超时会不生效,关键时候会悲剧的,容易引起雪崩 -eventmpmphp
memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT,_connect_timeout);//连接超时
memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_RCV_TIMEOUT,_read_timeout);//读超时
memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_SND_TIMEOUT,_send_timeout);//写超时
memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_POLL_TIMEOUT,_poll_timeout);
//设置一致hash
//memcached_behavior_set_distribution(handle,MEMCACHED_DISTRIBUTION_CONSISTENT);
memcached_behavior_set(handle,MEMCACHED_BEHAVIOR_DISTRIBUTION,MEMCACHED_DISTRIBUTION_CONSISTENT);
memcached_returnrc;
for(uinti=0;i_server_count;i++){
rc=memcached_server_add(handle,_ips[i],_ports[i]);
if(MEMCACHED_SUCCESS!=rc){
__LOG_WARNING__("MemCacheProxy","addserver[%s:%d]failed.",_ips[i],_ports[i]);
}
}
_mpool=memcached_pool_create(handle,_min_connect,_max_connect);
if(_mpool==NULL){
__LOG_WARNING__("MemCacheProxy","create_poolerror");
returnNULL;
}
mmc=memcached_pool_pop(_mpool,false,prc);
if(mmc==NULL){
__LOG_WARNING__("MyMemCacheProxy","gethandlefrompoolerror[%d]",(int)prc);
}
//__LOG_DEBUG__("MemCacheProxy","gethandle[%p]",handle);
returnmmc;
}
//设置一个key超时(set一个数据到memcached)
boolMemCacheProxy::_add(memcached_st*handle,unsignedint*key,constchar*value,intlen,unsignedinttimeout)-eventmpmphp
{
memcached_returnrc;
chartmp[1024];
snprintf(tmp,sizeof(tmp),"%u#%u",key[0],key[1]);
//有个timeout值
rc=memcached_set(handle,tmp,strlen(tmp),(char*)value,len,timeout,0);
if(MEMCACHED_SUCCESS!=rc){
returnfalse;
}
returntrue;
}
//Memcache读取数据超时(没有设置)
libmemcahed源码中接口定义:
LIBMEMCACHED_APIchar*memcached_get(memcached_st*ptr,constchar*key,size_tkey_length,size_t*value_length,uint32_t*flags,memcached_return_t*error);-eventmpmphp
LIBMEMCACHED_APImemcached_return_tmemcached_mget(memcached_st*ptr,constchar*const*keys,constsize_t*key_length,size_tnumber_of_keys);-eventmpmphp
从接口中可以看出在读取数据的时候,是没有超时设置的。
延伸阅读:
【如何实现超时】
程序中需要有超时这种功能,比如你单独访问一个后端Socket模块,Socket模块不属于我们上面描述的任何一种的时候,它的协议也是私有的,那么这个时候可能需要自己去实现一些超时处理策略,这个时候就需要一些处理代码了。 -eventmpmphp
[PHP中超时实现]
一、初级:最简单的超时实现 (秒级超时)
思路很简单:链接一个后端,然后设置为非阻塞模式,如果没有连接上就一直循环,判断当前时间和超时时间之间的差异。
phpsocket中实现原始的超时:(每次循环都当前时间去减,性能会很差,cpu占用会较高)
复制代码 代码如下:
?
$host="127.0.0.1";
$port="80";
$timeout=15;//timeoutinseconds
$socket=socket_create(AF_INET,SOCK_STREAM,SOL_TCP)
ordie("Unabletocreatesocketn");
socket_set_nonblock($socket) //务必设置为阻塞模式
ordie("Unabletosetnonblockonsocketn");
$time=time();
//循环的时候每次都减去相应值
while(!@socket_connect($socket,$host,$port))//如果没有连接上就一直死循环
{
$err=socket_last_error($socket);
if($err==115||$err==114)
{
if((time()-$time)=$timeout)//每次都需要去判断一下是否超时了
{
socket_close($socket);
die("Connectiontimedout.n");
}
sleep(1);
continue;
}
die(socket_strerror($err)."n");
}
socket_set_block($this-socket)//还原阻塞模式
ordie("Unabletosetblockonsocketn");
?
二、升级:使用PHP自带异步IO去实现(毫秒级超时)
说明:
异步IO:异步IO的概念和同步IO相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。异步IO将比特分成小组进行传送,小组可以是8位的1个字符或更长。发送方可以在任何时刻发送这些比特组,而接收方从不知道它们会在什么时候到达。 -eventmpmphp
多路复用:复用模型是对多个IO操作进行检测,返回可操作集合,这样就可以对其进行操作了。这样就避免了阻塞IO不能随时处理各个IO和非阻塞占用系统资源的确定。
使用socket_select()实现超时
socket_select(...,floor($timeout),ceil($timeout*1000000));
select的特点:能够设置到微秒级别的超时!
使用socket_select()的超时代码(需要了解一些异步IO编程的知识去理解)
复制代码 代码如下:
编程 调用类 编程#
?php
$server=newServer;
$client=newClient;
for(;;){
foreach($select-can_read(0)as$socket){
if($socket==$client-socket){
//NewClientSocket
$select-add(socket_accept($client-socket));
}
else{
//there'ssomethingtoreadon$socket
}
}
}
?
编程 异步多路复用IO 超时连接处理类 编程
?php
classselect{
var$sockets;
functionselect($sockets){
$this-sockets=array();
foreach($socketsas$socket){
$this-add($socket);
}
}
functionadd($add_socket){
array_push($this-sockets,$add_socket);
}
functionremove($remove_socket){
$sockets=array();
foreach($this-socketsas$socket){
if($remove_socket!=$socket)
$sockets[]=$socket;
}
$this-sockets=$sockets;
}
functioncan_read($timeout){
$read=$this-sockets;
socket_select($read,$write=NULL,$except=NULL,$timeout);
return$read;
}
functioncan_write($timeout){
$write=$this-sockets;
socket_select($read=NULL,$write,$except=NULL,$timeout);
return$write;
}
}
?
[CC++中超时实现]
一般在LinuxC/C++中,可以使用:alarm()设置定时器的方式实现秒级超时,或者:select()、poll()、epoll()之类的异步复用IO实现毫秒级超时。也可以使用二次封装的异步io库(libevent,libev)也能实现。 -eventmpmphp
一、使用alarm中用信号实现超时 (秒级超时)
说明:Linux内核connect超时通常为75秒,我们可以设置更小的时间如10秒来提前从connect中返回。这里用使用信号处理机制,调用alarm,超时后产生SIGALRM信号(也可使用select实现) -eventmpmphp
用alarym秒级实现 connect设置超时代码示例:
复制代码 代码如下:
//信号处理函数
staticvoidconnect_alarm(intsigno)
{
debug_printf("SignalHandler");
return;
}
//alarm超时连接实现
staticvoidconn_alarm()
{
Sigfunc*sigfunc;//现有信号处理函数
sigfunc=signal(SIGALRM,connect_alarm);//建立信号处理函数connect_alarm,(如果有)保存现有的信号处理函数
inttimeout=5;
//设置闹钟
if(alarm(timeout)!=0){
//...闹钟已经设置处理
}
//进行连接操作
if(connect(m_Socket,(structsockaddr*)addr,sizeof(addr))0){
if(errno==EINTR){//如果错误号设置为EINTR,说明超时中断了
debug_printf("Timeout");