PHP-Trace-设计原理

技术文档网 2021-04-16
PHPTrace 设计原理

简单介绍

PHPTrace致力于打造一款实时跟踪PHP函数调用,获取PHP函数调用栈信息以及PHP解释器状态的工具,这个PHP工具应该像系统工具strace/pstack一样强大易用。要设计完成这款工具,需要解决三方面的问题:

  • 外部命令工具如何获取PHP进程内部的相关信息
  • 能够实时开启和关闭,不需要编写代码或者修改配置
  • 单独开启一个PHP进程的trace/stack功能,将线上服务器的影响减至最小

详细分析

1. 如何获取PHP进程内部的相关信息

strace可以通过系统调用ptrace,使被trace的进程每次进入或退出系统调用时暂停, 这样strace通过ptrace(PTRACE_PEEK*)获取此时进程内存的内容,从而获取到系统调用的名称、参数、返回值、调用时间等内容。

由于PHP是一种动态脚本语言,并不是传统的C调用模型,PHP程序的运行依赖于一个PHP的解释器。通过ptrace系统调用获取的是解释器本身的状况,控制系统调用的执行与暂停,而不是PHP脚本的运行情况,因此不能控制一个PHP函数的执行或暂停。

为了解决如何从PHP虚拟机中获取调用信息的难题,我们决定引入PHP扩展,由扩展hook PHP解释器,PHP解释器在每次执行一个PHP函数或扩展函数时,调用zend_execute_*等系列函数,通过 hook zend_execute_*系列函数,这样解释器在调用PHP函数或扩展函数时,先进入我们的PHPTrace的hook函数,PHPTrace获取到调用信息后,调用PHP解释器真正的执行函数,并在PHP真正执行函数退出后, 获取调用结果:返回值,调用耗时。

2. 实时开启和关闭

为了定位线上正在运行中的PHP出现的问题,开启trace或stack的功能不能依赖于修改配置文件和写PHP代码,应该能够想strace和pstack那样给一个进程的ID,实时开启或者关闭。

我们形成了外部命令行工具跟PHP扩展共同协作的设计,由命令通知扩展开始trace,扩展收到通知后才开始真正的抓取PHP调用信息,抓取的信息不断写到共享内存,命令行工具不断读取共享内存,从而实现PHPTrace随时随地实时输出trace结果的目的。

3. 单独开启一个PHP进程的trace/stack功能

开启一个进程的trace/stack功能,必然会降低该进程执行PHP脚本的性能,strace也是如此。但是其它没有开启该功能的进程应该不受影响。

在外部命令工具通知扩展执行trace之前, 扩展并不会抓取任何信息,仅仅判断trace开关的状态,然后调用了原PHP虚拟机的zend_execute_*函数, 基本不会增加开销。

总体设计

PHPTrace从设计上分为三大部分: 扩展、通信共享内存部分以及命令行工具。如下图所示:

[[phptrace_arch.png]]

  • 扩展用于收集PHP解释器中的相关信息
  • 通信共享内存部分负责在命令行工具和扩展之间传递控制信息和数据信息
  • 命令行工具用于开启某一个进程的trace或stack功能,并输出相关信息

最后

因为解决了以上三个问题,PHPTrace可以帮助排查线上线下的各种PHP问题。

Xdebug虽有trace功能, 但其输出的结果却不能实时开启并打印出来;另外Xdebug挂钩了很多opcode,导致在不启用trace功能时,仍然有大量性能消耗。因此无法达到线上随时trace问题的要求。

本节主要偏重PHPTrace的设计原理,后续会给出每一部分的详细实现,敬请期待!

相关文章

  1. 如何通过xhprof分析性能

    使用方法 xhprof_enable(); /** ... 要检查的php代码 ... **/ $xhprof_data = xhprof_disable(); // 引入xhprof_lib i

  2. LUMEN API Controller 规范

    1. 第三方依赖库规范 在使用LUMEN实现API接口时,以下库必须需要包含在composer包依赖中,以实现代码编写的一些规范 dingo/api : 实现API接口库 vlucas/phpdo

  3. PHP文件锁

    共享锁(LOCK_SH) 什么时候加共享锁? 当在读取数据的时候同时进行着其他的写操作,这个时候需要对文件加共享锁,否则无论有没有对写操作加写锁都会写入成功,导致数据不一致 当文件获得共享锁时,其他

  4. Hello-Risen-程序

    首先需要说明的是,您下载到的文件包含两部分,其中src中是开发源码,用于对Risen框架本身的开发,risen 目录中是通过源码生成的包含debug和release版本的框架程序,用于您应用程序的开发

  5. PHP自定义类示例(Weixin消息解析类)

    PHP自定义类示例(Weixin消息解析类) /** * Created by Qingger. * User: jsspf * Date: 2017/3/24 * Time: 10:50

随机推荐

  1. 如何通过xhprof分析性能

    使用方法 xhprof_enable(); /** ... 要检查的php代码 ... **/ $xhprof_data = xhprof_disable(); // 引入xhprof_lib i

  2. LUMEN API Controller 规范

    1. 第三方依赖库规范 在使用LUMEN实现API接口时,以下库必须需要包含在composer包依赖中,以实现代码编写的一些规范 dingo/api : 实现API接口库 vlucas/phpdo

  3. PHP文件锁

    共享锁(LOCK_SH) 什么时候加共享锁? 当在读取数据的时候同时进行着其他的写操作,这个时候需要对文件加共享锁,否则无论有没有对写操作加写锁都会写入成功,导致数据不一致 当文件获得共享锁时,其他

  4. Hello-Risen-程序

    首先需要说明的是,您下载到的文件包含两部分,其中src中是开发源码,用于对Risen框架本身的开发,risen 目录中是通过源码生成的包含debug和release版本的框架程序,用于您应用程序的开发

  5. PHP自定义类示例(Weixin消息解析类)

    PHP自定义类示例(Weixin消息解析类) /** * Created by Qingger. * User: jsspf * Date: 2017/3/24 * Time: 10:50