当前位置: 首页 > 后端技术 > PHP

教你使用Swoole-Tracker秒定位PHP卡死问题

时间:2023-03-30 00:41:26 PHP

PHPer一定收到过这样的投诉:小菊花一直在转!为什么你的网站这么卡!当我们线上业务遇到这种卡(堵)的情况时,大多数PHPer都会眼前一黑,然后就会想到那句名言:性能瓶颈都在数据库然后把锅甩给DBA,赶紧找慢SQL,但这是一种非常错误的做法,因为有太多的因素会导致业务卡住。以下是一些常见的卡住问题。1、死循环最常见的形式是写死循环代码connect('127.0.0.1',9501,-1)){$cli->send("数据");$cli->recv();}else{echo"connectfailed.";}5.Swoole协程的锁在Swoole协程模式下,不正确的使用锁也会导致所有协程的大面积被卡住。下面的代码是go方法创建了2个协程(不懂协程的同学可以理解为创建了2个线程),第一个协程锁在co::sleep的位置拿到锁并让出cpu开始执行第二个协程。第二个协程会卡在第6行获取锁的位置,第一个协程永远无法恢复执行。lock();//获取锁Co::sleep(1);//放弃cpu$lock->unlock();//释放锁});}如何发现卡住以上只是一些例子,仍然有各种姿势卡在真正的业务中。有经验的PHPer会使用strace-p命令查看当前PHP进程阻塞在哪个系统调用上,从而定位问题。但是,有几种方法可以做到这一点。问题:定位问题不明确,比如死锁。strace的时候只能看到futex(0x7f4c8d567128,FUTEX_WAIT,2,NULL)这样的信息,非常不直观。很多人不知道哪些PHP代码会触发futex系统调用,还有上面提到的session_start的问题,很多人甚至不知道这里会触发flock,也就是说很难根据一个系统来定位具体的问题称呼。不知道哪个进程用-p。我们的在线环境通常会启动几十个甚至上百个PHP进程。当有的请求卡住,有的请求正常时,应该strace-p哪个进程?似乎这只是运气。无法发现死循环的问题由于strace命令的原理是跟踪所有的系统调用,所以如果是上面提到的第一种情况,也就是死循环的卡死循环,strace无法获取到任何有用的信息根本。这时候我们只能通过gdb工具来获取当前死循环的具体位置。具体方法如下:首先:gdbattach后面跟一个进程id。然后:p(char*)executor_globals.current_execute_data.func.op_array.filename.val打印当前正在执行的PHP文件。p(char*)executor_globals.current_execute_data.func.op_array.function_name.val打印当前执行函数的名称。pexecutor_globals.current_execute_data.opline.lineno打印当前执行的行数。另外,调用栈也可以获得,这里不再展开。但这显然太低级了,需要注意很多细节。不精通PHP核心的人很难通过这种方式发现问题(ps:通过.gdbinit可以稍微降低难度,但是还有很多其他问题)。使用SwooleTracker查找卡住问题针对以上问题,Swoole官方发布了解决方案SwooleTracker的栈工具,同时支持FPM和Swoole。使用方法很简单:先点击上面的链接注册一个账号。然后安装swoole_tracker扩展。最后登录后台,在debugger=>processlist中点击stack按钮,可以得到当前卡在什么地方,如图:除了最后出现上面卡住的问题,还有一种情况是调用很慢,比如原来的系统调用5ms,但是由于网络等原因,这个调用直到100ms才返回,业务的性能反而变慢了,而不是卡在那里。这种情况下,通过tracker的stackcapture工具是无法定位问题的,因为卡住的时间很短。很难捕获调用堆栈。这个时候就需要Swoole工具链中的另外一个工具来阻断IO检测工具,后面会介绍给大家。