[转]解决 textdb 核心问题:超负载与稳定性2

作者:    提交时间:2020-03-01    点击:1558    TAGS:负载 稳定

[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数据的安全问题。