由于平台老是出现间歇性502。排查发现,php死进程过多耗费大量系统资源。
除了优化代码之外,静态化可以减少php进程。缓解一下服务器压力。
把首页生成html后,出现问题频率下降。所以需要做首页静态化,并自动按规定时间更新。
1,在模板引入生成脚本,k的值随便定,只是为了防止没参数时,直接访问脚本static.php的触发。
<script type="text/javascript" src="/static.php?k=XXXXXX"></script>
2,脚本
$k = trim($_GET['k']); if (!is_string($k) || strlen($k) < 32 || $k !== md5("XXXXX")) { return false; } //首页1分钟更新一次 if (!file_exists("index.html") || time() - filemtime("index.html") > 60) { create_html(); } //生成静态 function create_html() { //开启output buffer 缓冲区,如果php已经开启,则不需要。 // php.ini 中,output_buffering = 4096 // if (!ini_get('output_buffering')) { ob_start(); // } //调用模板组织成页面 require "index.php"; //获取缓冲区中的页面,并清除缓冲区 $content = ob_get_clean(); //将页面保存成为静态文件 $s=file_put_contents("index.html", $content); if($s){ echo $s; }else{ echo 0; } }
如果写入失败,考虑写入权限问题 chmod -R 777 XXX
出现问题:
1,因为首页上面有登陆后,出现欢迎你,XXX的,东西,会出现,登陆用户如果更新缓存会把这些字符给抓下来,写入index.html
屏蔽ob缓存,采用file_get_content或者curl,或者用了ob之后phpquery来处理文档也可以。
2,超时问题
如果本身由于各种问题,index.php访问过慢。有可能会写入失败或者不完整。做了3套方案。
并且做了超时,和内容长度判断
以下是修改后代码
<?php /** * 静态化 * User: lee * Date: 2015/12/7 * Time: 17:40 */
//自定义验证 $k = trim($_GET['k']); if (!is_string($k) || strlen($k) < 32 || $k !== md5("XXX")) { die('{"status":0,"info":"k is error"}'); } //首页1分钟更新一次 if (!file_exists("index.html") || time() - filemtime("index.html") > 60) {
//刷新缓存 ob_flush(); flush(); $obj = new StaticPage(); $obj->create_html(); } else { die('{"status":0,"info":"file exists"}'); } //静态类 class StaticPage { //生成静态 public function create_html() { $ob = json_decode($this->P(1), 1);//优先ob缓存 if ($ob['status'] == 0) { $file_get_content = json_decode($this->P(2), 1); //失败,采用http if ($file_get_content['status'] == 0) {
//采用curl $curl = json_decode($this->P(3), 1); if ($curl['status'] == 0) { die('{"status":0,"info":"server error"}'); } else { echo json_encode($curl); } } else { echo json_encode($file_get_content); } } else { echo json_encode($ob); } } /** * http get请求 * @param string $url * @param mixed $param * @param int $time * @return mixed */ private function httpGet($url, $param = null, $time = 1000) { $ch = curl_init(); // set URL and other appropriate options curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);//不验证证书 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//不验证host curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 500);//设置时间 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); curl_setopt($ch, CURLOPT_NOSIGNAL, 1); //注意,毫秒超时一定要设置这个 curl_setopt($ch, CURLOPT_TIMEOUT_MS, $time); //curl_setopt($ch, CURLOPT_TIMEOUT, $time);//设置时间 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//不直接输出 // grab URL and pass it to the browser $result = curl_exec($ch); if (curl_errno($ch)) { //echo 'Errno2'.curl_error($ch);//捕抓异常 return false; } // close cURL resource, and free up system resources curl_close($ch); return $result; } /** * 获取页面 */ private function P($type = 1) { $url = "http://" . $_SERVER['HTTP_HOST'] . "/index.php"; //ob缓存 if ($type == 1) { //由于首页有登陆状态,使用ob缓存会记录登陆者名字进入缓存文件。 // if (!ini_get('output_buffering')) { ob_start(); // } require "index.php"; $content = ob_get_clean(); //把登陆欢迎信息替换,不能缓存用户名,phpQuery是一个dom处理的类,详细可以看我另外的文章 http://www.cnblogs.com/findgor/p/4955321.html require "../App/Common/phpQuery.php"; phpQuery::newDocument($content); $str = <<<STR <a href="http://{$_SERVER['HTTP_HOST']}/XXXXX" rel="nofollow">立即登录</a> <a href="http://{$_SERVER['HTTP_HOST']}/XXXXX" style="background:#A3A3A3;font-size:16px;font-weight:bold;color:#fff;" rel="nofollow">免费注册</a> <a href="http://{$_SERVER['HTTP_HOST']}/XXXX/" style="color:#cccccc">帮助中心</a>| <a href="http://{$_SERVER['HTTP_HOST']}/XXXX/" style="color:#cccccc" rel="nofollow">关于我们</a>| <a href="XXXXX" style="color:#cccccc" rel="nofollow">VIP中心</a> STR; pq("#head #head_nav .right")->html($str); $dom = pq()->html(); return $this->W($dom, 1); } //file_get_contents if ($type == 2) { $opts = array( 'http' => array( 'method' => "GET", 'timeout' => 1, //设置超时 ) ); $context = stream_context_create($opts); $content = @file_get_contents($url, false, $context); return $this->W($content, 2); } //curl if ($type == 3) { $content = $this->httpGet($url); return $this->W($content, 3); } } /** * 写入 * @param null $content 数据 * @param int $type 类型 * @return json */ private function W($content = null, $type = 1) { //大于1W字符写入 if (strlen($content) > 10000) { $index = @file_put_contents("index.html", $content); if ($index) { return json_encode(array("status" => 1, "data" => $index, "info" => "write ok!", "type" => $type)); } else { return json_encode(array("status" => 0, "data" => $index, "info" => "write false!", "type" => $type)); } } else { return json_encode(array("data" => 0, "info" => "<10000", "type" => $type)); } } } ?>
===================
考虑到其他页面的静态化。有2种想法
1,同样在这个static.php脚本里面触发,增加批量检测更新
2,后台按钮手动触发。
这两种方式那种最好。待我测试之后再行更新此文章。
补充:
过了2年了,再看这篇文章,技术显然不太符合现在的开发规范。目前采用的是redis缓存,所有首页数据都存到redis里面,定时cron更新
目标都是减少数据库开销,而redis是基于内存的,比磁盘读写速度要快,比较符合当前的开发概念。
参考:http://blog.csdn.net/jetxt/article/details/44563145#0-tsina-1-16123-397232819ff9a47a7b7e80a40613cfe1