[转]解决 textdb 核心问题:超负载与稳定性2
[4]关键字文件
php中使用的主要是其思想! 其实上面的两种数据文件都些许使用了这一思想.复杂的就不再累述了! 这里举个简单的也非常实用的例子! 其中主要还借助了定长的思想!
比如对单一主题.的 主题点击率 代码如下( read.php ):
$articlearray=openfile("$dbpath/$fid/$tid.php"); $topic_detail=explode("│",$articlearray[0]); list($tpc_fb,$tpc_covert,$tpc_author,$rd_icon,$tpc_date,$tpc_title,$tpc_ip,$tpc_sign,$tpc_download,$tpc_rvrc,$tpc_buy,$tpc_ipfrom,$tpc_ifconvert,$tpc_email,$tpc_content,$tpc_null1)=$topic_detail; list($rd_hit,$rd_islock,$rd_null)=explode(',',$tpc_covert); $rd_hit=trim($rd_hit); $rd_hit++; //$rd_hit=str_pad($rd_hit,8); $hitwrite="<?die;?>│$rd_hit"; $fp=fopen("$dbpath/$fid/$tid.php","rb+"); flock($fp,LOCK_EX); fputs($fp,$hitwrite); fclose($fp);
以上这一套思想完全解决了textdb帖子数据的更新的高效和稳定性问题,对于帖子等大型数据索引进行添加删除.修改都无须全部读取再写入,对在线等修改性频繁的数据.也只对需要修改添加的行(数据)进行写入.
因此无论你处理什么数据都可以应用上面的3种数据结构进行无负载性的添加删除和修改!
(2)保证textdb频繁数据处理时的稳定性
在解决 textdb 负载问题的前提下.必须考虑数据处理的问题.毕竟数据的准确与稳定是一个程序的灵魂.以下我不直接给出具体实现的算法.取而用程序测试比较的方式!
主要讲解两个方面
1) 数据的准确性
大家可能用习惯了传统论坛程序在写入的开始进行EX锁定,下面的两个函数就是现在传统textdb类程序包括论坛所使用的读写函数!
function readover($filename,$method="rb") { if($handle=@fopen($filename,$method)){ flock($handle,LOCK_SH); $filedata=fread($handle,filesize($filename)); fclose($handle); } return $filedata; }
function writeover($filename,$data,$method="wb") { $handle=fopen($filename,$method); flock($handle,LOCK_EX); fputs($handle,$data); fclose($handle); }
这对于小流量的网站而言是更本不会有问题.可是在大流量的网站.这样的函数不得不让人质疑textdb的稳定性和数据的准确性!
因为同时请求更新同一数据有好几个时.数据的不准确性便产生了.比如 当你发贴时在索引表中进行写入或修改你的索引信息.需要对索引进行琐定.可是如果你在读完索引后正准备写入时.另一个线程也在共享的前提下读取数据完毕.也正准备写入.这时如果是你的线程先进入了锁定写入.那么等你写完后.他将马上写入不包含你索引信息的内容.这便造成了所谓的帖子丢失的假象! 当然如果你使用了(一)中的负载的定长索引的某种数据结构.这一现象发生的几率将几乎为0.因为它对索引操作不再是全部写!
下面给出读写时保证数据的准确性算法:
function readlock($filename,$method="rb+") { $file=fopen($filename,$method); flock($file,LOCK_EX); $filedata=fread($file,filesize($filename)); rewind($file); return array($file,$filedata); }
function writelock($filename,$data,$handle) { fputs($handle,$data); ftruncate($handle,strlen($data)); fclose($handle); }
这样的函数实现便完美解决了任何场合保证数据的准确性!!!!(上面两个函数已解决数据的稳定性) 大家可以编写程序测试以上的科学性!
2) 数据的稳定性
下面先给出测试的一个程序:
function readlock($filename,$method="wb") { $file=fopen($filename,$method); flock($file,LOCK_EX); $filedata=fread($file,filesize($filename)); return array($file,$filedata); }
function writelock($filename,$data,$handle) { fputs($handle,$data.$data); fclose($handle); }
function filelock($filename,$method="wb") { $filedb=openfile($filename); $handle=fopen($filename,$method); flock($handle,LOCK_EX); return array($handle,$filedb); } $filename='c.php' list($file,$ofstarfile)=readlock($filename); $ofstarfile=explode('│',$ofstarfile); $ofstarfile[4]++;$ofstarfile[5]++; echo $ofstarfile[4];echo'<br>' $ofstardb=implode("│",$ofstarfile); echo $ofstardb; for($I=0;$I<1500000;$I++)//增加多个线程同时请求的时间 { $A=$B=2; } writelock($filename,$ofstardb,$file);
***********************************
c.php的数据内容是
<?die;?>│42 │1│1│101│101│0│64│1067443200│1067961600│fengyu│fengyu│fengyu││1│2003-10-22 13:33│天天天│
大家可以放在 unix 与NT上进行测试.
具体测试方法是 同时运行这个程序达到多线程同时请求同一数据 如果数据段不发生紊乱且第4.5数据段的值不断增加说明是稳定的.如果发生紊乱则不是稳定的.注意需要线程同时请求大于4个以上!
具体测试结果是:在NT空间上大于4个线程同时请求的出现紊乱的几率为 50--100%具体依赖于操作系统的多线程服务器.
linux/freebsd上 进行大于4个线程同时请求出现的几率为0-0.001%也就是说几乎为 0
当然出现错误的几率还是有的! 也证实过! 具体要求是几十个线程同时请求.具体的问题在于php中的系统函数在NT的多线程操作系统与服务器下的不兼容问题.
针对传统textdb的数据不准确和不稳定问题--------彻底解决方案是:
使用以下的写函数:
/*写入数据保证稳定性*/
在给出写入的稳定性函数前.先说明一个问题.
大家可能为了让速度更为快速,常用直接包含 .php 文件直接得到值. 当然这一方法很有效.不过在对于数据处理频繁的文件.切记不可使用 include $filename; 然后对数据处理后 writeover(); 因此建议对频繁处理数据的文件采用共享读取!
下面为解决稳定性的实现方法:
function writeover($filename,$data,$method="rb+") { touch($filename);/*文件不存在则创建之.可以采用file_exists验证并其他创建文件函数代替.测试结果效率相当*/ $handle=fopen($filename,$method); flock($handle,LOCK_EX); fputs($handle,$data); if($method=="rb+") ftruncate($handle,strlen($data)); fclose($handle); }
function readlock($filename,$method="rb+") { $file=fopen($filename,$method); flock($file,LOCK_EX); $filedata=fread($file,filesize($filename)); rewind($file); return array($file,$filedata); }
function writelock($filename,$data,$handle) { fputs($handle,$data); ftruncate($handle,strlen($data)); fclose($handle); }
这便圆满解决了 textdb 数据处理的稳定性问题
加上解决数据的准确性问题. 有理由相信 textdb 不再是脆弱的数据处理”容器”!
( 以上负载算法和稳定性算法归属Ofstar board .请务必尊重我们的劳动成果! )
(三)textdb整体效率提高的细节性问题
其实这个主要是看程序的水平了.不过站得更高收获总是可以更丰厚.下面将一下ofstar内部研究的 php—textdb数据处理的一写算法或是一些技巧:
1)获取ip地址来源
function cvipfrom($onlineip) { $detail=explode(".",$onlineip); if (file_exists("ipdata/$detail[0].txt")) $filename="ipdata/$detail[0].txt"; else $filename="ipdata/0.txt"; for ($i=0; $i<=3; $i++) { $detail[$i] = sprintf("%03d", $detail[$i]); } $onlineip=join(".",$detail); $db=fopen($filename,"rb"); flock($db,LOCK_SH); $onlineipdb=fread($db,filesize($filename)); if($ofstarset=strpos($onlineipdb,"$detail[0].$detail[1].$detail[2]")){ $ipfrom=ipselect($db,$ofstarset,$onlineip); }elseif($ofstarset=strpos($onlineipdb,"$detail[0].$detail[1]")){ $ipfrom=ipselect($db,$ofstarset,$onlineip); }elseif($ofstarset=strpos($onlineipdb,$detail[0])){ $ipfrom=ipselect($db,$ofstarset,$onlineip); } fclose($db); if(empty($ipfrom)) $ipfrom='未知地址' return $ipfrom; }
function ipselect($db,$offset,$onlineip){ fseek($db,$offset,SEEK_SET); $getcontent=fgets($db,100); $iparray=explode("│",$getcontent); if ($onlineip>=$iparray[0] && $onlineip<=$iparray[1]) return $iparray[2].$iparray[3]; }
这个算法将比比传统效率高3-5倍.具体思想是.在处理非规则性行时.大可不必行行进行 explode 要知道这样将耗用很大的时间.其实可以变通过来先全部读取.使用strpos 得到关键字的位置! 再使用指针偏移! 条件是关键字需要在行的开头! 这样处理起来比较方便.当然如果不在开头也可以.只要使用两次 strops 就可以找到具体位置,具体可参看ofstar 在线会员的代码
2)return 与 global
在函数中,传递数组时
使用 return 比使用 global 要高效
比如
function userloginfo($usertemp){ $detail=explode("│",$usertemp); return $detail; } $login=userloginfo($userdb);
比
function userloginfo($usertemp){ global $detail; $detail=explode("│",$usertemp); } userloginfo($userdb);
要高效
3)
判断的时候尽量使用if($a==他的值) 否定的时候尽量使用if(empty($a)),因为这样程序运行更快速
4)对小数据操作避免使用 file()和 fget(效率低)
算法如下:
function openfile($filename,$style='Y') { if($style=='Y'){ $filedata=readover($filename); $filedata=str_replace("\n","\n<:ofstar:>",$filedata); $filedb=explode("<:ofstar:>",$filedata); //array_pop($filedb); $count=count($filedb); if($filedb[$count-1]==''││$filedb[$count-1]=="\r"){unset($filedb[$count-1]);} if(empty($filedb)){$filedb[0]="";} return $filedb; }else{ $filedb=file($filename); return $filedb; } }
/*openfile函数无论在速度还是稳定上都大于file系统函数,不过openfile是具有负载问题的.所以有时 file 函数在解决大型数据非常有用*/
5)同一页面刷新并不更新在线数据.代码如下
if($timestamp-$lastvisit>$db_onlinetime││ ($fid&& $fid!=$HTTP_COOKIE_VARS['lastfid'])││($HTTP_COOKIE_VARS['lastfid']!='' && $star_action=='hm')) { $runfc='Y' include "./require/userglobal.php"; }
6)帖子浏览时判断作者是否在线时.采用的是 cookie 加 strops 进行快速查找,大大提高了程序运行的效率
if(!$HTTP_COOKIE_VARS['forum_online']) { $onlinearray=openfile('bbsdata/online.php'); $count_ol=count($onlinearray); for ($i=1; $i<$count_ol; $i++) { $rd_onlinedb=explode("│",$onlinearray[$i]); if($rd_onlinedb[0]!='隐身会员') { if ($timestamp-$rd_onlinedb[1]<=$db_onlinetime ) $forum_online.='│'.$rd_onlinedb[0]; } } setCookie('forum_online',$forum_online, $cookietime,$ckpath,$ckdomain,$secure); } @strpos($forum_online,$tpc_author) !== false ? $read[ifonline]="<img src='$imgpath/$stylepath/read/online.gif' alt='该用户目前在线'>":$read[ifonline]="<img src='$imgpath/$stylepath/read/offonline.gif' alt='该用户目前不在线'>";
(四)对数据的检索
经过多次测试采用 索引中读取数据id.使用 fopen 文件. Fread 得到帖子数据.不再采用fgets 读取数据. 大大提高了检索的速度.由于在程序效率上已经推证过 使用 file()函数的速度问题.所以 ofstar 的检索里不采用 file()读取数据,实践证明使用这一方法 textdb检索对 cpu 和内存耗用极低!
(五)textdb安全维护
无论是.RDBMS还是textdb 程序安全都牵涉到3个方面!这里就解说三方面的textdb解决安全问题的方法: 程序数据接口安全问题.程序恶意代码攻击,服务器的安全问题
1) 程序数据接口安全问题
由于数据是以文件直接保存在空间上的.所以必须对数据文件采用加密或是特定的防护.常见的方法有.使用特定的目录名.采用随机的目录名为数据存放的目录! 这一方法安全性可以保证.但是万一目录名被获知.将是致命的打击.因此 ofstar 对数据文件采用 .php 可执行文件结尾.对文件内第一行 加上 <?die?> 将外来的访问屏蔽!! 彻底解决textdb 数据文件的安全问题.!
2) 程序恶意代码攻击
直接讲 ofstar的思想:在保证防止普通变量攻击的同时,程序方面全部防止自动提交所带来的安全隐患,并全智能判断附件可能存在的恶意代码!自动过滤与屏蔽恶意会员所带来的恶意代码等
3) 服务器的安全问题
这里只针对linux/unix 多用户的操作系统.利用程序创建帖子数据和用户数据目录,从而避免了要手动设置‘777’属性而造成数据文件属主的问题.这样既方便安装又解决了unix/ linux系统textdb数据的安全问题。