这里抛出一个常见问题:PHP环境下脚本运行超时,尤其是处理后台服务数据处理时经常会遇到。
Maximum execution time of 120 seconds exceeded
常规解决排查方式
我们的排查思路一般从数据量开始,主观判断由于程序需要处理的数据过多,造成运行处理时间过长,超出了系统限定的脚本最大执行时间。那么真的是处理的数据过多,还是程序写法或者逻辑存在风险问题?我们从以下几个方面分析
1 瓶颈出现在数据库层面,比如关系型或者nosql数据库中的字段缺失,即字段拼写错误,造成数据库查询卡死或者数据库数据量巨大,没有在条件字段下建立索引。这种情况下,程序会一直等待数据库操作的返回,脚本自然会中断报错。
Read timed out after reading 0 bytes, waited for 30.000000 seconds
2 减少单次处理的数据量,避免foreach中循环操作数据库
数据库层面能够顺利读取数据,常规循环次数过多,应用服务器与数据库服务器IO频率过高仍然会出现以上问题。
3 程序过程中涉及到大数组的读取,合并,组合,造成内存过载,比如PHP的最大使用内存是128M,而一个脚本耗时几分钟,使用内存达到50M,着这样的比例,长期来看必定存在风险。
PHP内置函数memory_get_usage()能返回当前分配给PHP脚本的内存量,单位是字节(byte).
memory_get_peak_usage()函数返回内存使用峰值,getrusage()返回CUP使用情况。
如何解决
第一种解决方式: 最简单,但是不持久,不合理
从配置的角度解决
脚本中设定程序执行不超时,set_time_limit(0);
内存使用不限制,ini_set(‘memory_limit’,0);
增加脚本超时时间,合作加大内存使用M数。
第二种解决方式对症下药
合理存取数据,优化数据库结构,优化数据存取比例和程序逻辑,通过unset释放大数组。
索引优化
实际例子,一张100万数据量的MongoDb集合增加普通的索引,即可让一次从1o几秒的查询耗时降低到0.1秒以下。可以预见这样的程序性能提升。
以上讨论的解决方式都能正确解决问题吗,我们发现以上的解决方式都局限在同步编程模型下,更深层次深究,或许我们应该从同步处理的思维下,转换为异步思维。
在php-fpm模式下,php处理耗时比较长任务时,会发生堵塞,此时可以用异步方法,将该任务抛出,程序继续向下执行。
异步处理方式
那么PHP应用程序编程有哪些常见的异步处理方式
使用Redis或者其它消息中间件做中转,分离数据与程序,结合消息队列异步处理长时间的大数据耗时任务
或者引入Swool服务框架,在大并发的前提下才能感知到效果。
根据不同的业务需求做技术选择。
参考文档