web常见问题排查
一般排查方法
- 检查error_log
- 检查access_log
- 检查slow_log
- linux命令工具
- tcpdump分析网络状况
- 程序的gdb调试
error_log
error_log提供了有关异常的丰富信:
- 网络超时:connect,write,read timeout
- File not found
- HTTP状态码
举例来讲,更新nginx后,http请求不能返回完整数据,返回部分数据后请求就结束了,每次都能复现。这时候查看error_log,看到有Permission denied错误,即查实为nginx的临时写目录没有权限所造成。
slow_log
php-fpm慢日志slowl_og设置可以让开发者很好的查找哪些php进程速度过慢而导致的网站问题,让开发者方便的找到问题的所在。该方法同样适用于排查nginx的500、502问题根源,当nginx收到如上错误码时,可以确定后端php-fpm解析php出了某种问题,比如,执行错误,执行超时等。
access_log
对access_log进行统计分析,可以很好地展示与监控web服务的状态。包括200请求次数的变化,流量大小,后端响应时间等
1 | 1. 统计HTTP状态码的比例,可以知道nginx服务健康状况; |
linux工具命令
strace 跟踪进程中的系统调用
使用strace命令工具可跟踪系统调用并打印出丰富的信息,如系统调用发生的时间,调用耗时,传送的参数,调用返回结果等等。
1 | 常用参数有: |
strace只能追踪系统调用,普通函数是无法追踪的。CPU很高,说明程序一直在跑,但strace没有异常,说明是用户状代码在消耗CPU。问题必定出现在自己程序逻辑上。
tcpdump
tcpdump是linux本身得供的一款强大的网络抓包工具。对于两台设备之间传输的数据是否正常,为何响应慢等网络问题,都可以使用tcpdump来抓包排查。
windows下面有一款具有同样功能的工具软件–wireshark,也很好用。
还记得刚才示例中提到的慢连接吧,Nginx的access_log显示请求响应时间为3s多,而后端是毫秒计,这种慢就可以使用tcpdump来抓包查看了
可以看到后端响应ack花了3s.这种慢连接,我们线上会经常碰到。通常nginx做反向代量连接后端时、php程序在访问后端资源时、以及php用curl请求其他接口时,经常出现慢连接的情况。这些慢连接产生的根本原因在于:
–服务端listen时,设置的backlog太小,导致连接队列很小;
–连接队列满时,对于新的连接请求,服务端会直接丢弃SYN包;
–SYN包初始重传时间为3s;
再举一下综合案例:PHP升级后,开始运行正常,但几天后,系统负载突然上升,达到200-400左右,CPU使用不高,内存使用不高,netstat发现大量的PHP进程处于CLOSE_WAIT状态。
排查:error_log与access_log都没有问题;
nginx与PHP不在同一台机器,暂时无法查看其error_log;
CPU、内存都不高,为何负载这么高?
CLOSE_WAIT是怎么造成的
我们先从CLOSE_WAIT入手,TCP关闭连接过程中,被动关闭的一方,在接收到对方的FIN后,发送自己的FIN前,这个状态就是CLOSE_WAIT。
系统调用close,关闭连接,发送FIN
从CLOSE_WAIT的状态看,PHP应该是没有调用close函数,程序可能因为某种原因堵塞,而无法调用close。
启用strace追踪PHP进程到底堵塞在哪里。
strace追踪结果来看,PHP进程没有堵塞,但write函数调用失败,Broken pipe说明连接已经关闭,调用close了。
继续strace分析,连接为什么关闭,是后端PHP处理太慢导致nginx超时么?从strace看到,PHP从accept到close,总共耗时1ms,nginx不可能超时。
我们启动tcpdump抓包(windows下使用wireshark查看)
发现3个异常:
–3次握手nginx发送的SYN,PHP响应是ACK,而不是SYN+ACK
–Nginx发送FIN关闭连接后,PHP没有发送FIN
–第二个连接的SYN,PHP同样只返回ACK,但ACK序列号却是确认上一个连接的。
结合strace与tcpdump来看,accept调用比接收到SYN晚了2分钟
这里可以看到:SYN三次握手完成后,socket放到了连接队列里,accept从连接队列获取socket,如果队列过大,等到accept消费到这个socket,可能已经超时关闭连接。队列中关闭的连接处于CLOSE_WAIT状态。若PHP一个关闭的连接,就会出现Broken Pipe报错现象。
这其实就是backlog设置过大引起。
总结一下,web问题排障很复杂,找到正确的方向很重要。学会看log与系统状态,学会使用统计数据(常用的一些awk,grep命令),熟悉一些常用的工具。
问题一定是有原因的,要找到root cause(真正的根本原因)
小说推荐
修仙 | 凡人修仙传 |
---|---|
遮天 | |
一仙难求 | |
仙灵图谱 | |
凡女仙葫 | |
慢慢仙途 | |
修真之上仙 | |
仙本纯良 | |
天下… | |
机甲 | 信不信我吃了你 |
机甲护翼 | |
重生古言 | 九重紫 |
金陵春 | |
慕南枝 | |
庶女攻略 | |
嫡谋 | |
金枝 | |
穿越古言 | 名门闺杀 |
穿越之丑夫 | |
万事如意 | |
新唐遗玉 | |
知否,知否?应是红肥绿瘦 | |
宋史 | 柔福帝姬 |
孤城闭 | |
御天香 | |
清朝 | 永和宫主 |
清穿日常 | |
上古神话 | 曾许诺 |
香蜜沉沉烬如霜 | |
三生三世十里桃花 | |
三生三世枕上书 | |
长相思 | |
华胥引 | |
游戏 | 微微一笑很倾城 |
玩个天下好胃疼 | |
现代言情 | 何以笙箫默 |
原来你还在这里 | |
致我们终将逝去的青春 | |
山月不知心底事 | |
青梅竹马 | 百花深处 |
娇术 | |
花开锦绣 | |
红茱记 | |
热血青春 | 择天记 |
php魔术方法
PHP 将所有以 开头的类法保 为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 为前缀
一、方法简介
__construct(),类的构造函数,在同一个类中只能声明一个构造方法
php不支持重载,如需要父类的构造函数需显式调用
- __destruct(),类的析构函数,析构方法允许在销毁整个类之前执行的某些操作,无参数
- call()、callStatic(),方法重载,调用未定义过的(静态)方法时被调用,可以使用__call进行友善的
错误处理
,避免当调用不存在的方法时产生错误,意外的导致程序中止 - 属性重载
1 | <?php |
- __clone()复制时调用,复制时引用复制(浅复制),结合clone关键字实现真正的复制
- autoload()作用: 是当你调用不存在的类时会被动调用,不建议使用,原因:autoload()重复定义时,冲突报错,只能有一个__autoload()函数
1 | <?php |
推荐使用spl_autoload_register()
1 | <?php |
- __sleep()在对一个对象序列化时(调用serialize()时)会被调用。它不接收任何参数,而且应该返回一个包含所有应该被序列化的属性的数组;
- __wakeup()在对存储的对象反序列化时会被调用;
- __toString() :在我们将对象当作字符串一样使用时会被调用;
- __set_state:使用var_export()函数输出对象时会调用该方法
- __debugInfo(): 打印调试信息时调用
- __invoke() :使用调用函数的方式调一个对象时调用该函数
1 | <?php |
二、 AOP在PHP中的实现
在传统的OOP(面向对象编程:Object-Oriented Programming)思想 ,一般把应用程序分解成若干个对象,强调高内聚
,弱耦合
,从而提高应用程序的模块化程度,但是在处理某些问题的时候,OOP会显得不够灵活,比如说:
1 | 应用程序很多业务逻辑都要在操作之初进 “权限检查”,在操作之后进行“日志记录”,如果直接把处理逻辑直接加到 |
正是为了处理这样的问题,AOP
(面向切面编程:Aspect-Oriented Programming)思想应运而生,假设把应用程序想成一个立体结构的话,OOP的刃是纵向
切入系统,把系统划分为很多个模块(如:用户模块,文章模块等), AOP的刀刃是横向切分系统,提取各个模块可能都要重复操作的部分(如:权限检查,日志记录等等)。由此可见,AOP是OOP的一个有效补充。
1 | 就目前的PHP来说,还没有一个完整的AOP内置实现,虽然出现 RunKit,但估计很长时间内不太可能成为PHP的缺省设置。 |
三、魔术变量
- LINE: 文件中的当前行号。
- FILE: 文件的完整路径和文件名。当在被包含文件中,则返回被包含的文件名
- DIR: 文件所在的目录。如果用在被包括文件中,则返回被包括的文件所在的目录。
- FUNCTION: 常量,返回该函数被定义时的名字
- CLASS: 常量,返回该类被定义时的名字(区分大小写)。
- METHOD:返回该方法被定义时的名字(区分大小写)。
7.NAMESPACE:当前命名空间的名称(区分大小写)
四、超全局变量
- $GLOBALS:储存全局作用域中的变量。
- $_SERVER:获取服务器相关信息。
- $_REQUEST:获取POST和GET请求的参数
- $_POST:获取表单的POST请求参数
- $_GET:获取表单的GET请求参数
- $_FILES:获取上传文件的的变量
- $_ENV:获取服务器端环境变量的数组
- $_COOKIE:浏览器cookie的操作
- $_SESSION:服务端session的操作
五、结语
PHP中的”重载”与其它绝大多数面向对象语言不同。传统的”重载”是提供多个同名的类方法,但各方法的参数类型和个数不同。 PHP所提供的”重载”(overloading)是指动态地”创建”类属性和方法。 当调用当前环境下未定义或 不可见的类属性或方法时,重载方法会被调用