php进程导致服务器cpu 100问题追查过程

简介:
前段时间,出现了一次服务器cpu 占用100的问题。以下为追查原因的过程。仅当抛砖引玉,欢迎拍砖。
查看占用cpu高的进程

想找出占用cpu高的进程,用top命令就可以搞定。


$top
.....此处省略n多行...
10434 root     20   0  509m 174m 1528 R 99.7  0.5   8:42.43 php                                                                                                        
 5638 root     20   0  509m 174m 1528 R 99.1  0.5   9:12.35 php                                                                                                        
16390 root     20   0  541m 182m 5244 R 98.4  0.6   8:40.92 php        


此时,轻轻按下C键。就会看到如下信息。


10434  root     20   0  540m 182m 5244 R 101.0  0.6   9:57.39 php /home/gearman_manager/pecl-manager.php -P /home/gearman_manager/manager.pid -u root -d -v
5638 root     20   0  509m 174m 1528 R 101.0  0.5  10:15.28 php /home/gearman_manager/pecl-manager.php -P /home/gearman_manager/manager.pid -u root -d -v
16390 root     20   0  509m 174m 1528 R 99.5  0.5   9:41.18 php /home/gearman_manager/pecl-manager.php -P /home/gearman_manager/manager.pid -u root -d -vv

找出进程占用cpu高的原因
进程占用cpu高,一般是由于进程长时间占用cpu,又没有主动释放占用。如果想主动释放cpu,可以调用sleep。在写程序的时候,尤其要注意while 等循环的地方。

找出php进程在执行那段代码


$sudo gdb -p 10434
(gdb) print (char *)executor_globals.active_op_array->filename
$13 = 0x2924118 "/home/gearman_manager/pecl-manager.php"
(gdb) print executor_globals->current_execute_data->opline->lineno
$14 = 55
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00000031d32306d0 in sigprocmask () from /lib64/libc.so.6
(gdb) print executor_globals->current_execute_data->opline->lineno
$15 = 71
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00000000006250e1 in zend_hash_find ()
(gdb) print executor_globals->current_execute_data->opline->lineno
$16 = 53

如果对上面的命令有疑问,可以查看 [当cpu飙升时,找出php中可能有问题的代码行]
根据上面的信息,我们可以知道,cpu高时,正在执行/home/gearman_manager/pecl-manager.php文件。并且正在执行53和71行附近的代码。

分析相关代码
php的相关代码如下:


while(!$this->stop_work){ //此处是第51行
 
            if(@$thisWorker->work() ||
               $thisWorker->returnCode() == GEARMAN_IO_WAIT ||
               $thisWorker->returnCode() == GEARMAN_NOT_CONNECTED ||
               $thisWorker->returnCode() == GEARMAN_NO_JOBS) {
                 
                if ($thisWorker->returnCode() == GEARMAN_SUCCESS) continue;
 
                if (!@$thisWorker->wait()){
                    if ($thisWorker->returnCode() == GEARMAN_NO_ACTIVE_FDS){
                        sleep(5);
                    }
                }
 
            }
 
            /**
             * Check the running time of the current child. If it has
             * been too long, stop working.
             */
            //此处是第71行
            if($this->max_run_time > 0 && time() - $start > $this->max_run_time) {
                $this->log("Been running too long, exiting", GearmanManager::LOG_LEVEL_WORKER_INFO);
                $this->stop_work = true;
            }
 
            if(!empty($this->config["max_runs_per_worker"]) && $this->job_execution_count >= $this->config["max_runs_per_worker"]) {
                $this->log("Ran $this->job_execution_count jobs which is over the maximum({$this->config['max_runs_per_worker']}), exiting", GearmanManager::LOG_LEVEL_WORKER_INFO);
                $this->stop_work = true;
            }
 
        }

看来作者已经考虑到某些情况可能导致cpu 100,因此在代码中使用了sleep方法。现在php进程占用cpu 100,看来是没执行sleep(5)。如果$thisWorker->work() 和 $thisWorker->returnCode() 方法中没有IO等操作,能释放cpu的占用,又没有调用sleep的情况下,很容易导致进程占用cpu 100。
根据代码我们可以得出如下几个结论:
- 肯定没执行slepp(5)
- $thisWorker->work() 和 $thisWorker->returnCode() 方法中没有IO等操作,能释放cpu的占用。

进一步跟踪代码中可疑部分
分析 $thisWorker->returnCode() 的返回值。如果很容易复现cpu 100的话,你可以在程序中echo $thisWorker->returnCode() 来获得返回值。但是现在cpu 100的问题,复现比较麻烦。所以,还是使用gdb 来搞吧。


$gdb -p 10434
(gdb)b zif_gearman_worker_return_code 
Breakpoint 1, zif_gearman_worker_return_code (ht=0, return_value=0x2a1b648, return_value_ptr=0x0, this_ptr=0x2a14090, return_value_used=1)
    at /home/php_src/pecl/gearman-1.1.1/php_gearman.c:3186
3186    in /home/php_src/pecl/gearman-1.1.1/php_gearman.c
(gdb) p return_value
$3 = (zval *) 0x2a1b648
(gdb) p *$3
$4 = {value = {lval = 0, dval = 0, str = {val = 0x0, len = 0}, ht = 0x0, obj = {handle = 0, handlers = 0x0}}, refcount__gc = 1, type = 0 '\0', is_ref__gc = 0 '\0'}
(gdb) s
3189    in /home/php_src/pecl/gearman-1.1.1/php_gearman.c
(gdb) p *$3
$5 = {value = {lval = 0, dval = 0, str = {val = 0x0, len = 0}, ht = 0x0, obj = {handle = 0, handlers = 0x0}}, refcount__gc = 1, type = 0 '\0', is_ref__gc = 0 '\0'}
(gdb) s
3186    in /home/php_src/pecl/gearman-1.1.1/php_gearman.c
(gdb) p *$3
$6 = {value = {lval = 0, dval = 0, str = {val = 0x0, len = 0}, ht = 0x0, obj = {handle = 0, handlers = 0x0}}, refcount__gc = 1, type = 0 '\0', is_ref__gc = 0 '\0'}
(gdb) s
3189    in /home/php_src/pecl/gearman-1.1.1/php_gearman.c
(gdb) p *$3
$7 = {value = {lval = 0, dval = 0, str = {val = 0x0, len = 0}, ht = 0x0, obj = {handle = 0, handlers = 0x0}}, refcount__gc = 1, type = 0 '\0', is_ref__gc = 0 '\0'}
(gdb) s
3190    in /home/php_src/pecl/gearman-1.1.1/php_gearman.c
(gdb) p *$3
$8 = {value = {lval = 0, dval = 0, str = {val = 0x0, len = 0}, ht = 0x0, obj = {handle = 0, handlers = 0x0}}, refcount__gc = 1, type = 0 '\0', is_ref__gc = 0 '\0'}
(gdb) s
3191    in /home/php_src/pecl/gearman-1.1.1/php_gearman.c
(gdb) p *$3
$9 = {value = {lval = 25, dval = 1.2351641146031164e-322, str = {val = 0x19 <Address 0x19 out of bounds>, len = 0}, ht = 0x19, obj = {handle = 25, handlers = 0x0}}, 
  refcount__gc = 1, type = 1 '\001', is_ref__gc = 0 '\0'}

从最后的lval = 25 和 type =1 我们可以看出 returnCode()方法的最后返回值是 25 。
根据文档,返回值25 对应的是 GEARMAN_NOT_CONNECTED。
## 解决问题
既然出问题时, returnCode()方法的最后返回值是 25,而现在程序中对这种情况又没进行出来,导致了cpu 100。那我们只要在出现这种情况时,sleep几秒就ok了。


if(@$thisWorker->work() ||
               $thisWorker->returnCode() == GEARMAN_IO_WAIT ||
               $thisWorker->returnCode() == GEARMAN_NOT_CONNECTED ||
               $thisWorker->returnCode() == GEARMAN_NO_JOBS) {
                //下面一行是新增的
                if ($thisWorker->returnCode() == GEARMAN_NOT_CONNECTED) sleep(5);
                if ($thisWorker->returnCode() == GEARMAN_SUCCESS) continue;
 
                if (!@$thisWorker->wait()){
                    if ($thisWorker->returnCode() == GEARMAN_NO_ACTIVE_FDS){
                        sleep(5);
                    }
                }
 
            }

相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
目录
相关文章
|
7天前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
17天前
|
存储 缓存 PHP
阿里云服务器实例、CPU内存、带宽、操作系统选择参考
对于使用阿里云服务器的用户来说,云服务器的选择和使用非常重要,如果实例、内存、CPU、带宽等配置选择错误,可能会影响到自己业务在云服务器上的计算性能及后期运营状况,本文为大家介绍一下阿里云服务器实例、CPU内存、带宽、操作系统的选择注意事项,以供参考。
阿里云服务器实例、CPU内存、带宽、操作系统选择参考
|
23天前
|
监控 安全 容灾
PHP服务器稳定性保障
确保PHP服务器稳定性,需关注以下几点:配置合适硬件及优化操作系统;使用最新稳定版PHP,及时更新安全补丁;编写高质量代码并优化性能;处理异常,记录日志以便监控;管理资源,使用性能监控工具;加强安全防护,如权限设置、防注入攻击;采用自动化部署和持续集成工具;定期备份数据,建立容灾机制。
13 0
|
1月前
|
弹性计算 固态存储 Linux
2024年阿里云服务器租用详细价格表(CPU/内存/带宽/系统盘)
2024阿里云服务器租用优惠价格表,轻量服务器2核2G3M带宽轻量服务器一年61元,2核4G4M带宽轻量服务器一年165元12个月,ECS云服务器e系列2核2G配置、3M固定带宽、40G ESSD Entry云盘,99元一年、2核4G服务器30元3个月、2核4G配置365元一年、2核8G配置522元一年,云服务器u1、云服务器c7、g7和r7优惠价格表,CPU内存带宽系统盘配置详细报价:
728 3
|
1月前
|
弹性计算 固态存储 调度
阿里云服务器部署配置选择全攻略,ECS实例规格、CPU内存配置
阿里云服务器部署配置选择全攻略,ECS实例规格、CPU内存配置,CPU内存、公网带宽和系统盘怎么选择?个人用户选择轻量应用服务器或ECS通用算力型u1云服务器,企业用户选择ECS计算型c7、通用型g7云服务器,阿里云百科分享阿里云服务器配置选择方法
|
1月前
|
弹性计算 固态存储 调度
阿里云服务器选购指南_2024新版CPU内存带宽系统盘选择攻略
阿里云服务器选购指南_2024新版CPU内存带宽系统盘选择攻略,CPU内存、公网带宽和系统盘怎么选择?个人用户选择轻量应用服务器或ECS通用算力型u1云服务器,企业用户选择ECS计算型c7、通用型g7云服务器,阿里云百科分享阿里云服务器配置选择方法
|
1月前
|
弹性计算 固态存储 调度
阿里云配置服务器详细指南_2024新版CPU内存带宽系统盘选择
阿里云配置服务器详细指南_2024新版CPU内存带宽系统盘选择,阿里云服务器配置怎么选择?CPU内存、公网带宽和系统盘怎么选择?个人用户选择轻量应用服务器或ECS通用算力型u1云服务器,企业用户选择ECS计算型c7、通用型g7云服务器,阿里云百科分享阿里云服务器配置选择方法
|
1月前
|
弹性计算 数据挖掘 大数据
阿里云4核8G云服务器怎么样?2024年阿里云4核8G云服务器测评:价格配置、CPU性能
在数字化时代,数据成为驱动业务发展的核心力量。因此,无论是个人站长还是企业用户,都对云服务器的性能和价格提出了更高要求。阿里云作为国内云服务市场的领军者,始终致力于为用户提供卓越性能和极具竞争力的价格。阿里云4核8G通用算力型u1实例云服务器ECS备受瞩目。这款服务器凭借强大的4核CPU和8GB内存,能够轻松应对搭建网站、应用服务器以及进行数据分析和计算等多重任务。而其年度价格仅为955.58元,换算下来每月仅需80元,这一价格无疑在同类产品中极具竞争力。对于那些寻求高性能服务器以支持业务发展的用户来说,阿里云这款4核8G服务器无疑是一个理想选择。它不仅提供了出色的性能,还通过优惠活动大大降低
55 0
|
2月前
|
弹性计算 大数据 测试技术
阿里服务器租用多少钱一年?阿里云服务器租用价格表(最新CPU/内存/带宽/磁盘收费标准)
阿里服务器租用多少钱一年?阿里云服务器租用价格表(最新CPU/内存/带宽/磁盘收费标准)。阿里云服务器的租用费用因实例类型、地域、配置等因素而有所不同,价格范围可以从几百元到几千元不等。2024年阿里云服务器租用费用价格表更新,云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、ECS u1实例2核4G、5M固定带宽、80G ESSD Entry盘优惠价格199元一年,轻量应用服务器2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月、2核4G服务器30元3个月,幻兽帕鲁4核16G和8核32G服务器配置,云服务器ECS可以选择经济型e实例、通用算力u1实
|
26天前
|
存储 Shell Linux
【Shell 命令集合 系统设置 】⭐⭐⭐Linux 限制进程资源 ulimit命令 使用指南
【Shell 命令集合 系统设置 】⭐⭐⭐Linux 限制进程资源 ulimit命令 使用指南
33 0