调试排错能力

编    写:袁    亮
时    间:2015-01-20
说    明:php后端程序人员简单排错能力

一、说明
能力强不强是通过解决问题来体现的,不能解决问题的话,其他的都是白搭
ps:不要觉得错误莫名其妙,我这边明明是好的,用户那边有问题,就怀疑是电脑有问题啊,服务器有问题啊什么的,mysql有问题啊之类
99%的问题,都是程序上的问题,没能重新,只是你没重现出那个特殊的情况

二、常见错误类型
1、网站打不开,不能访问
2、能打开页面,但是页面显示不正常,比如白页,404等
3、操作失败,比如不能发帖,不能删帖等
4、逻辑错误,比如帖子的回复数不对,页面缓存一直错误
5、页面打开很慢,性能问题,超时,卡等
6、定时脚本执行结果不符合预期

三、网站不能访问
当有人反馈,网站打不开的时候,可以参考以下几个步骤来进行排查
ps:需要确定的是,直接访问不了,而不是访问的时候页面出错,访问出错请参考第四条
1、要到相应的链接及报错截图,自己打开电脑访问下,是否能正常
2、如果自己能正常访问,使用阿里测或者17测看下,是否正常
3、如果17测等不能正常访问,看下是否是自己加了host所以能正常访问
4、如果17测等有些不能正常访问,需要让对方ping下这个域名是到哪个ip
这个时候需要看该域名是否使用了CDN加速,如果使用了可能是CDN节点有问题
如果ping的ip和自己的电脑一样,那就需要看下对方访问出错的截图,是否是因为cookie头过长等原因导致不能访问
5、通过以上步骤,基本上都能搞定该类问题

四、页面能打开,但是显示不正常
该问题指的是,已经能正常由apache返回数据,但是返回的页面和正常页面不同
1、查看http返回头状态码(firebug或者chrome里,网络中都能很容易看到)
2、500
如果有显示报错,根据报错信息查看哪边出问题即可
如果直接白页,查看apache错误日志中的报错信息即可,或者复制一个临时文件出来,开启报错查看也可
3、404
是否是文件被删了
还是rewrite规则写的有问题,导致没有找到相应文件
也有可能是程序逻辑中判断,比如哪个资源没有了,所以显示的404,需要根据具体的代码逻辑来查找
4、502
一般来说,这是由nginx返回的,说明后端apache的响应时间过久
查看apache日志,找到超时的请求,看下执行了多久
在程序中的响应地方记录log,看是哪段代码超时了
一般来说,都是sql语句导致,查看对应数据库的慢查询sql即可快速找到,然后优化
5、200
页面如果显示错误信息等,根据错误提示调试代码即可
如果没有显示,可以查看apache错误日志
页面排版错误等,直接按F12查看调整或者查看源代码,一般来说html代码有问题,源代码里都会标红等,一眼就能看到
页面错误还有很大一种可能是静态文件缓存:CDN缓存,nginx缓存,浏览器缓存等等需要注意

重要:如果是正式项目中,页面有显示报错信息,务必将报错关闭,不允许在线上开启报错

五、操作失败
页面等能正常访问,但是进行相应操作的时候失败,比如发帖,删帖等
1、自己操作一遍,看下是否能成功
在操作测试的时候,请以真实的数据去测试,并及时删除,不要乱写什么test之类的进行测试
并且在测试完之后,马上将测试数据通过正常操作删除
2、如果自己能成功,其他人失败,看是否有失败的提示信息
比如权限不足,有违禁词等等,根据提示找到为什么失败
3、需要通过修改程序来debug的话,请务必保证在以下两种情况(线上项目)
3.1 项目有测试机
在测试机上进行调试,debug,改完之后,通过svn上线到线上版本
3.2 没有测试机,并且比较紧急的话
将相应的操作文件copy一份出来,然后输出调试,找到问题出在哪
改完之后,copy回去之前,先备份原文件,并diff比对下两个文件,保证没有改了多余的地方
copy覆盖回去之后,必须要进行全面测试,保证之前出问题的情况不会出现,以及正常操作的时候也没问题
不要出现原来的问题解决了,但是带来了新的问题
4、在3满足的情况下,参考以下的debug步骤
第一步就是开启报错,80%的问题,开启报错之后就能知道是什么问题了(或者看错误日志)
不要从头开始看代码,指望着看出来问题,这是不现实的,我很讨厌别人跟我在说,我在看
根据问题状况,定位到哪边出的问题,比如发帖之后,posts表没有插入数据,那就先找到插入posts表的代码在哪
找到这段代码的时候,可以通过var_dump,die看下这段代码是否执行到了,是否执行成功
如果执行不成功,sql的话,直接输出这条sql,放在phpmyadmin里执行看报错
如果没有执行到的话,向前找节点(if else判断等)),看是在哪一步判断导致没有运行到该出
在大段代码,设置debug节点的时候,不要很秀气的每次一行一行的设置,那会疯掉的
最简单的二分法,400行代码,出问题,先在200行左右var_dump,die一次,不行,就100行的地方,再不行,就50行的地方
5、注意事项
有些时候觉得有些bug莫名其妙,总是重现不了,需要考虑下,用户的情况跟你是不一样的
比如账号不同,比如cookie不同,比如当前电脑的时间不同,比如发了一些特殊符号等等都有可能导致用户出问题
之前还出现过一次因为bing爬虫爬取错误链接然后导致缓存出错的问题,这个问题在解决之前也是觉得莫名其妙

六、逻辑错误
比如帖子的回复数不对,用户的积分不对,用户付完钱,结果订单被取消等等
1、这种问题,一般来说都比较麻烦,首先需要知道的是有哪些地方涉及到该逻辑
2、猜测哪些操作可能导致该问题的出现,比如用户的积分多了,是不是该减积分的地方没减,加的时候加多了?
3、针对比较可能出问题的操作点,重新操作,看是否有问题

七、页面性能
该类问题比较大,只列几个粗略的方向
1、查看apache日志,找到最慢的那些请求和平均的请求时间,定位哪些访问有问题
2、找到对应请求,设置时间点,找到慢的程序块
3、具体分析,打印相应的块执行时间,找到问题点
4、查看mysql慢日志是一种比较快能定位到问题,一般来说web项目卡都是数据库层面出了问题

八、定时脚本执行未达到预期
1、确定定时脚本是否有执行
查看定时脚本执行log,是否有
如果没有,则查看下报错log,根据报错log调整
复制要执行的脚本,其他操作都不执行,只输出一个最简单的内容,修改定时脚本的执行时间,每分钟执行,看是否正常
2、脚本有执行,但是结果和预期不同
定时脚本编辑的时候,必须在各个关键节点输出日志
出问题之后,根据自己记录的log日志,查看哪一步跟预期不同
如果之前未记录,则根据问题表象,在相应节点输出相应的log,可以临时执行该定时脚本,查看是哪边出的问题

RPC接口的使用


编	写:袁	亮
时	间:2015-01-15
说	明:xmlrpc的工作原理和使用

一、为什么需要这个?
	1、学名叫远程过程调用,即调用远程其他项目的函数方法
	2、例如A项目,里面有用户的图片,在B项目里,我需要获取到这个用户的图片,最老的方法,就是直接连A项目的数据库,重新写一遍获取数据的逻辑。这会带来非常多的问题:
		2.1 同样的一个功能,我需要重复写非常多遍
		2.2 如果项目要迁移,我都不知道要改多少地方(比如数据库连接等等)
		2.3 如果之前的功能稍微做点改动,我得把每个涉及到的项目都得改一遍,然后测试,保证没问题
	3、为了解决上述问题,我们希望通过接口的方式去调用其他项目的相应功能,xmlrpc就是其中一种解决办法
		soap,或者直接通过http获取数据等,也都可以解决
	4、数据采用xml的形式进行传递,

二、工作原理
	1、一次服务器与服务器之间的http调用
	2、客户端根据相应的参数,构建相应的http请求头信息
	3、使用fsockopen发送数据请求,请求数据转为xmlrpc协议格式
	4、服务端接收到请求,查看是否有定义相应的函数
	5、服务端调用已注册的rpc方法,并输出xml格式的返回值
	6、客户端接收到相应的响应数据后,将xml重新解析会php变量
	7、rpc过程结束

三、使用范例
	1、服务端编写接口
		include_once("../inc/class_xmlrpc.php");

		function messAdd($m,$p){
		    $p = $p[0];
		    $ms = new MessClass;
		    return $ms->messAdd($p);
		}

		$xmlrpc_funcs = array(// 注册函数
    		'messAdd',
		);
		$xmlrpc_name = 'api/mess';
		$xmlrpc_server = new xmlrpc_server();
		foreach ($xmlrpc_funcs as $v) {
		        $xmlrpc_server->register_method($xmlrpc_name.'.'.$v, $v);
		}
		$xmlrpc_server->call_method();

		1.1 引入xmlrpc类
		1.2 正常写一个函数,第一个参数预留,封装的类里用到的,第二个参数是客户端传过来的参数
			$p[0] $p[1] 分别代表第一、第二个参数,依次类推
		1.3 将本地的方法注册,使其可以成为可以被rpc调用的方法
			需要一个命名空间,类似api/mess
			register_method中,函数名可以不一样,但我习惯会命名成一样的
		1.4 查看是否有语法错误
			访问下接口地址,是否正常的输出xml格式的数据

	2、客户端调用
		include_once("../inc/class_xmlrpc.php");

		$c = new xmlrpc_client("http://commentdev.ci123.com/mess/rpc/server.php","api/mess");
		$p = array(
		    'to_user_id'    => 1535917,
		    'temp_id'       => 134,
			'target_id' => 3217,
		    'platforms'     => '1,3',
		    'user_id'   => 2199,
		);
		$data = $c->call("messAdd",$p);
		var_dump($data);

		2.1 引用封装的类
		2.2 初始化rpc client类
			api/mess需要跟服务端那边取的名字保持一致
		2.3 调用相应的方法
		2.4 这边data只能接受到服务端return的返回值,使用var_dump,echo等输出是不行的
			因为那边输出的是函数的返回值,var_dump等并不是函数返回值
		2.5 如果是测试机,需要在对应的服务器上加host,在本地加host是没用的
			因为这是服务器跟服务器之间的通信(如果在本机上测试,hosts是同一份)

四、常见问题
	1、在服务器上调用一个测试服务器的rpc,出错
		需要在服务器上加host,因为服务器找不到测试机的域名
	2、如果rpc所在服务器加了http basic认证
		可以在client初始化的时候,把账号、密码传过去
	3、超时时间在客户端初始化的时候设置
	4、测试用例保留
		客户端调用范例文件保存,在最开始die掉