避免PHP-FPM内存泄漏导致内存耗尽

 更新时间:2016年11月25日 15:34  点击:1697
PHP-FPM如果出现存存泄漏问题可能导致服务器内存不足从而导致服务器资源用尽了,这样就会导致网站无法访问了,下面一起来看一篇避免PHP-FPM内存泄漏导致内存耗尽的配置。

对于PHP-FPM多进程的模式,想要避免内存泄漏问题很简单,就是要让PHP-CGI在处理一定数量进程后退出即可。
否则PHP程序或第三方模块(如Imagemagick扩展)导致的内存泄漏问题会导致内存耗尽或不足。
php-fpm.conf中有相关配置:
#请自行按需求配置

pm.max_requests = 1024

实际上还有另一个跟它有关联的值max_children,这个是每次php-fpm会建立多少个进程,这样实际上的内存消耗是max_children*max_requests*每个请求使用内存。

另外一些粗暴的方法包括建立cron kill掉占用内存过多的php-cgi,


1.检查php进程的内存占用,杀掉内存使用超额的进程

一般情况下,如果php-cgi进程占用超过1%的内存,就得考虑一下是否要杀掉它了。因为普通情况下,php-cgi进程一般占用0.2%或以下。

这里提供一个脚本供各位使用,就是放在cron任务里,每分钟执行一次。

使用crontab -e 命令,然后添加如下调度任务

* * * * * /bin/bash /usr/local/script/kill_php_cgi.sh

kill_php_cgi.sh脚本如下

#!/bin/sh
#如果是要杀掉php-fpm的进程,下面的语句中php-cgi请改成php-fpm
pids=`ps -ef|grep php-cgi|grep -v "grep"|grep -v "$0"| awk '{print $2}'`
if [ "$pids" != "" ];then
for  pid  in   $pids;
do
kill -9 $pid
done

fi

2.增加内存,将PHP_FCGI_MAX_REQUESTS的值设置成跟你内存总存储量相对应的值

3.优化程序,降低处理每次请求占用的内存大小

如果PHP-FPM能够提供配置子进程内存超过指定大小就被kill,那就省事多了

OpenCart 开发支付宝,财付通,微信支付如果我们不注意可能出现很多的一些问题,主要就是参数错误但一般是看不了来的,这里有一站长分享了一篇不错的文章大家来看看吧。

最近在给OpenCart集成支付宝,财付通和微信扫码支付,其实这些插件都是有的卖的,但是还蛮贵的,还是自己开发集成吧,省钱。但是集成过程中发现了一些坑,有opencart的坑,也有支付sdk的坑,浪费了不少时间,这里整理几条,给需要的人跨坑。

1.微信native 模式二中的notify_url 地址必须是公网地址

2.支付宝的notify_url不能是query string的形式,比如 xxx/notify.php?route=a/b,只能为xxx/notify.php
3.OpenCart 中支付宝和财付通中的同步回调处理中最好unset($_GET[‘route’])再做支付回调验证,否则因为这个多余的参数参与校检导致回调验证不成功

4.微信回调notify的时候是发送数据流,所以GET和POST是获取不到支付后异步通知过来的数据的,用官方的SDK的时候你可以这样改一下:

$GLOBALS['HTTP_RAW_POST_DATA'] = file_get_contents('php://input', 'r');

$notify = new PayNotifyCallBack();

$notify->Handle(false);

5.PC浏览器的支付宝用ios设备访问的时候会弹出支付宝客户端来支付,这样是接收不到异步和同步通知的,所以需要判断一下访问设备是移动端还是客户端,如果是移动端的话得用支付宝的wap方式来支付
6.财付通支付QQ浏览器支付一直参数错误,还没找到为什么a

Laravel Debugbar是一款bug调试插件了,我们下面一起来看看这款,Laravel Debugbar的调试例子,具体如下。

aravel Debugbar是Laravel的调试利器,有非常漂亮的Debug Bar。
如何使用Laravel Debugbar(github):
1.使用compser引入package

composer require barryvdh/laravel-debugbar

2.config/app.php的providers中添加

'Barryvdh\Debugbar\ServiceProvider',

看看Laravel Debugbar收集了哪些信息:

QueryCollector  你还在用DB::getQueryLog()打印sql吗?  QueryCollector收集了所有数据库的执行sql和时间


query-collector2.png


RouteCollector : 显示当前route信息
ViewCollector: 可以看到被render的模板


view-collector.png


EventsCollector:所有events
MemoryCollector内存使用大小;
TimeDataCollector 请求时间及TimeLine;
ExceptionsCollector 异常信息
FilesCollector 加载的php文件
ConfigCollector 加载配置文件值
LogCollector 所有log信息

过滤html标签在php中太简单了,我们可以直接使用strip_tags函数来实现了,下面给各位整理了一些关于 strip_tags函数的例子。


php过滤html的函数:

 

strip_tags(string)

 

这样就可以过滤掉所有的html标签了。

 

如果想过滤掉除了<img src="">之外的所有html标签,则可以这样写:

strip_tags(string,"<img>");


过滤除了<img src=""><p>xxx</p><b></b>之外的所有html标签,则可以这样写:

strip_tags(string,"<img><p><b>");

php有效的过滤html标签,js代码,css样式标签:

<?php 

$str = preg_replace( "@<script(.*?)</script>@is", "", $str ); 

$str = preg_replace( "@<iframe(.*?)</iframe>@is", "", $str ); 

$str = preg_replace( "@<style(.*?)</style>@is", "", $str ); 

$str = preg_replace( "@<(.*?)>@is", "", $str ); 

?>


自定义函数

function uh($str)

 {

     $farr = array(

         "/s+/",                                                                    

                        //过滤多余的空白

         "/<(/?)(script|i?frame|style|html|body|title|link|meta|?|%)([^>]*?)>/isu",

   //过滤 <script 等可能引入恶意内容或恶意改变显示布局的代码,如果不需要插入flash等,还可

 以加入<object的过滤

         "/(<[^>]*)on[a-za-z]+s*=([^>]*>)/isu",                                     

 //过滤网页特效的on事件

      

    );

    $tarr = array(

         " ",

         "<123>",           //如果要直接清除不安全的标签,这里可以留空

         "12",

    );

  $str = preg_replace( $farr,$tarr,$str);

    return $str;

 }

set_error_handler() 函数设置用户自定义的错误处理函数。该函数用于创建运行时期间的用户自己的错误处理方法。该函数会返回旧的错误处理程序,若失败,则返回 null。下面来看一些例子。


set_error_handler()

PHP从4.1.0开始提供了自定义错误处理句柄的功能函数set_error_handler(),但很少数脚本编写者知道。set_error_handler这个函数可以很好地防止错误路径泄露,当然还有其它更多的作用。

1.可以用来屏蔽错误。 出现错误一来会把一些信息暴漏给用户,极有可能成为黑客攻击你网站的工具。 二来让用户觉得你的水平很挫。
2.可以记下错误的信息, 及时发现一些生产环境的出现的问题。
3.可以做相应的处理, 出错的时候可以显示跳转到预先定义好的出错页面,提供更好的用户体验。
4.可以作为调试工具, 一些时候必须在生产环境调试一些东西, 但又不想影响正在使用的用户。
5.。。。。
set_error_handler的使用方法如下:

view sourceprint?1 string set_error_handler ( callback error_handler [, int error_types])

 

我们利用error_reporting();看到的错误信息包括三个部分,错误信息,错误文件的绝对地址,错误出现的行数。其实还有一个是错误类型。Array ( [type] => 1 [message] => Call to undefined method SomeClass::somemedthod() [file] => /home/zhangy/www/aaaa/stasdf.php [line] => 67 ),页面的绝对路径最好不要暴露给别人,不然给有些人可称之机,为了杜绝这一点,好多人都会采用,ini_set("display_errors",0);直接把错误信息给屏蔽掉了。这样就不方便了,如果我们要看信息怎么办呢?每次查看的时候,是不是都要改一下代码,或者是改一下apache的配置,在重起一下呢?

php有函数set_error_handler可以解决这个问题

用法如下:

mixed set_error_handler ( callback $error_handler [, int $error_types = E_ALL | E_STRICT ] )

php函数register_shutdown_function也可以解决这个问题

用法如下:

int register_shutdown_function ( string $func )

个人觉得报错函数自己定义,至少有三点好处,

1,不会把文件的绝对路径显示出来,安全些

2,即使真的出现了错误信息,我们可以对错误信息进行处理,让用户也看不到fatal error这样的东西。用户体验要好

3,项目上线后,有的时候,你还是要帮用户去解决问题,这个时候难免要去修改代码,但是我们又要让错误信息报出来,又不能让用户看到,这个时候,用set_error_handler这样的函数就很爽了。

个人做了一个小测试

<?php
error_reporting(0);

register_shutdown_function('error_alert');
function error_alert()
{
 if(is_null($e = error_get_last()) === false)
 {
 set_error_handler('errorHandler');
 if($e['type'] == 1){
 trigger_error("fatal error", E_USER_ERROR);
 }elseif($e['type'] == 8){
 trigger_error("notice", E_USER_NOTICE);
 }elseif($e['type'] == 2){
 trigger_error("warning", E_USER_WARNING);
 }else{
 trigger_error("other", E_USER_OTHER);
 }

 }else{
 echo "no error";
 }
}

 set_error_handler('errorHandler');

function errorHandler($errno, $errstr, $errfile, $errline,$errcontext)
{
 switch ($errno) {
 case E_USER_ERROR:
 echo "<b>My ERROR</b> [$errno] $errstr<br />\n";
 echo "  Fatal error on line $errline in file $errfile";
 echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
 break;

 case E_USER_WARNING:
 echo "<b>My WARNING</b> [$errno] $errstr<br />\n";
 echo "  warning on line $errline in file $errfile";
 echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
 break;

 case E_USER_NOTICE:
 echo "<b>My NOTICE</b> [$errno] $errstr<br />\n";
 echo "  notice on line $errline in file $errfile";
 echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
 break;

 default:
 echo "Unknown error type: [$errno] $errstr<br />\n";
 echo "  warning on line $errline in file $errfile";
 echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
 break;
 }

 return true;
}

class SomeClass {
 public function someMethod() {

 }
}

SomeClass::someMedthod();

$a="asdf";
foreach($a as $d){
 echo $d;
}
?>

现在我们就用自定义的错误处理把实际路径过滤掉。假设有一个变量$admin,我们是用来判断访问者是否是管理员的(可以通过IP或者登录的用户id来做这个判断)

//admin为管理员的身份判定,true为管理员。 
//自定义的错误处理函数一定要有这4个输入变量$errno,$errstr,$errfile,$errline,否则无效。 
function my_error_handler($errno,$errstr,$errfile,$errline) 

    //如果不是管理员就过滤实际路径 
    if(!admin) 
    { 
        $errfile=str_replace(getcwd(),"",$errfile); 
        $errstr=str_replace(getcwd(),"",$errstr); 
    } 
    switch($errno) 
    { 
        case E_ERROR: 
        echo "ERROR: [ID $errno] $errstr (Line: $errline of $errfile) \n"; 
        echo "程序已经停止运行,请联系管理员。"; 
        //遇到Error级错误时退出脚本 
        exit; 
        break; 
 
        case E_WARNING: 
        echo "WARNING: [ID $errno] $errstr (Line: $errline of $errfile) \n"; 
        break; 
 
        default: 
        //不显示Notice级的错误 
        break; 
    } 

这样就自定义了一个错误处理函数,那么怎么把错误的处理交给这个自定义函数呢?

// 应用到类 
set_error_handler(array(&$this,"appError")); 
 
//示例的做法 
set_error_handler("my_error_handler"); 


so easy,这样,就可以很好地解决安全和调试方便的矛盾了。而且你还可以花点心思,使错误提示更加美观以配合网站的风格。

 

上面的例子中,我把错误信息关掉了,而用自己的函数处理错误,上面的这个页面会报fatal error,报出来的错误信息我们是可以利用errorHandler来控制和处理。

好了,总结一下,下面是 set_error_handler 三种用法:

Php代码
class CallbackClass {
function CallbackFunction() {
// refers to $this
}

function StaticFunction() {
// doesn’t refer to $this
}
}

function NonClassFunction($errno, $errstr, $errfile, $errline) {
}

// 三种方法如下:

1: set_error_handler(‘NonClassFunction’); // 直接转到一个普通的函数 NonClassFunction

2: set_error_handler(array(‘CallbackClass’, ‘StaticFunction’)); // 转到 CallbackClass 类下的静方法 StaticFunction

3: $o =& new CallbackClass();
set_error_handler(array($o, ‘CallbackFunction’)); // 转到类的构造函数,其实本质上跟下面的第四条一样。

4. $o = new CallbackClass();

// The following may also prove useful:

class CallbackClass {
function CallbackClass() {
set_error_handler(array(&$this, ‘CallbackFunction’)); // the & is important
}

function CallbackFunction() {
// refers to $this
}
}

[!--infotagslink--]

相关文章