SlideShare uma empresa Scribd logo
1 de 53
Baixar para ler offline
Discuz!技术交流 
                浪湾<langwanluo@comsenz.com>




http://www.phpchina.com 
到场嘉宾 
•  技术主管、经理、系统构架师 
•  高级、中级程序员 
•  网管 
•  教师、学生 
•  PCB工程师 
•  投资顾问 
•  技术支持
大家关心的问题 
•  论坛性能优化 
•  缓存 
•  Discuz!速度、稳定性、功能。 
•  6.0及下版本的发布时间。 
•  代码规范、团队管理以及大型项目应对。 
•  二次开发、整合、扩展能力、用户系统。 
•  数据库设计。 
•  详细的技术分析。
DISCUZ!技术交流 




http://www.phpchina.com
•  骨干构架稳定,版本挑剔性底。 
  •  fopen mysql_query  array  md5 time explode list strlen PHP3 
  •  print_r  var_export  PHP4.2.0以下 
•  错误处理简单,没有复杂的错误信息。 
•  语法近于C与Java之间,并顺装了Linxu下的不少Shell。 
  •  strlen printf strcmp / system chmod touch 
  •  PHP5的类设计更像JAVA。 
•  有广泛自由的设计空间与现成构架。 
  •  平行的函数构架。 
  •  pear开源网站 
•  嵌入式PHP也是不错的选择。 
  •  路由器 机顶盒 KTV 酒店系统 
•  开发环境舒适。 
  •  记事本 
  •  Zend Studio 类比微软和Sun来说还是精简的。 
  •  UE, SQLyog(database) 
•  应用能力适中,结合性强。 
•  缺点,缺乏线程机制,内存控制力,编译不够完美。 
•  小李飞刀闻名再人而非刀。
Discuz!宣言

一、  我们Discuz!所有成员,在成立四周年之际,于2005年12月12日在北京中关
村,重申我们对于社区事业的信心,并拟定《Discuz!宣言》作为下一步服务社区事
业的方向和依据!

二、  我们认识到,我们做的Discuz!不仅仅是一个软件,在承担服务软件用户的
责任之外,我们还有一个更为重要的使命,那就是怎样与社区建设者一起,共同维护
网民的表达权利、创建平等而公平的社区信用体系、增强不同社区网民之间有效而便
捷的沟通。

三、  我们重申一直以来对Discuz!用户的各项宗旨和原则的承诺,它们已证实是
永不过时的,是普遍适用的。事实上,随着Discuz!和用户之间的相互联系和相互依
赖日益增加,它们的现实意义更加重要。

四、  我们决心在互联网上,进一步推动社区形态的整体价值提升,进一步降低社
区创建者的进入门槛,进一步完善对各类社区的个性化服务。

五、  我们希望,社区建设者不为任何概念诱惑所动,在互联网大潮的各个阶段,
都能服务好本社区网民,成为互联网造福人类的一股最积极向上的力量。因为尽管互
联网给人们带来了巨大机遇,但它的部分应用也带来了负面效应。
六、     我们认为某些基本价值是Discuz!永远坚持的。这包括:
――自由。人们不分男女,有权在不违法、不影响他人的情况下选择自己的网上社
区生活。社区建设者有权在最大化维护社区网民的利益下,以民为本的自由选择各
类经营项目!包括对社区技术系统平台的自由替换和选择权利!
――平等。社区经营者不分信仰、国别、年龄、性别及背景,皆享有免费使用 
Discuz!产品的平等权利!
――安全。与网站或网页不同,社区内的每个文字和记录都是由网民亲自创造的,
社区上承载的每个ID都有着丰富感情的现实个体。正因为如此,Discuz!将确保能
永远提供网上最安全的社区技术平台和解决方案。
――跨平台。无论社区经营者选择哪一种技术平台系统,Unix、Windows或Linux,
皆有选择Discuz!的自由,犹如好客的主人,尊重五湖四海宾客的信仰一样, 
Discuz!过去、现在、直至将来,永远都不会放弃这种跨平台的选择自由!
――技术性能与效率。与所有的软件产品一样,追求产品本身的卓越质量都是无可
厚非的。但是,作为一个社区软件系统,我们追求高性能高效率还有另外一层含
义,那就是,尽量帮助我们的社区建设者最大化降低硬件成本、最大可能地减少带
宽资源的投资!
――优质服务。Discuz!一直坚持给社区网民、社区建设者提供最优质的产品和服
务为己任。我们深知,社区的服务需求万万千,Discuz!谦虚谨慎,不断开发各类
个性化服务。
七、  为了把这些价值和原则变为行动,兹将我们特别重视的一些关键目标从2006 
年起,逐步展示于众。

八、  我们将竭尽全力,在保证我们能够生存并持续发展的前提下,对Discuz!社
区软件产品实施免费。在目前数万免费用户的基础上,将此项福利惠及更多的社区建
设者。

九、  因此,我们决心:
--永远为免费版用户提供最全面的产品功能。
――永远向免费版用户提供稳定、长期的可升级支持。
――永远让免费版用户享受到基本的网上社区技术支持服务。
――永远支持中小网站、个人网站,尤其鼓励基于草根的社区应用创新,我们将在免
费产品中不断开发新功能,满足这些灵感的技术实现。

十、  我们希望Discuz!产品永远永远免费下去,如果非要在她前面加上一个期限,
我们希望将是一万年。
组成
Discuz! 特征(一) 
•  版本2 
    •  独有先进的编译模板内核,全部模板采用文件存储,前台界面完全使用语言包构件语言元素 
    •  全面支持多模板,多语言和分论坛间设定不同的模板,风格和语言 
    •  自建 SMTP 模块,支持 ESMTP 验证,并提供三种可选方式发送邮 
•  版本3 
    •  新增带缓存的高效率首页新帖调用功能 
    •  Discuz! 3.10 在论坛易用性,人性化方面做了重大改进,同时安全级别也明显提升 
•  版本4 
    •  新增整合的论坛 Blog 系统,最大限度的实现资源多层次利用并可设定哪些用户有权使用本功能 
   •  增加广告管理系统,可实现表格自动排布、分版及随机展现 
   •  新增 WAP 功能,可实现登录、看帖、发帖、回帖、收发短消息等功能 
   •    彻底革命的积分体系 
   •    新增 Cron(计划任务) 机制,并提供自定义计划任务接口 
   •    新增URL静态化选项,可将常见URL翻译为静态形式(伪html),使论坛更容让搜索引擎收录 
   •    优化 mysql 模块,提高对Mysql各版本的兼容性,完美支持 Mysql 5.0新增数据库字符集的设置 
   •  新增附件点击数延迟更新功能 
   •  增加系统数据加密方法
Discuz! 特征(二) 
•  版本5 
    •  融入更多 Web 2.0 元素,新增多样化论坛主题功能,最多可扩充至 256 种主题类型 
    •  新增 My(我的 ...)功能模块更加关注论坛用户的使用体验和成长经历,用户可以随时查阅发
       表的主题、回复、交易、活动、收藏 ... 
    •  新增所见即所得编辑器,可兼容大部分浏览器,支持自定义 Discuz! 代码快捷输入按钮 
    •  新增 js 菜单支持,为用户自定制 js 菜单留有接口 
  •    优化计划任务,避免论坛并发人数过大,任务重复执行。 
  •    优化搜索引擎支持,调整论坛网页 title 显示顺序,提高搜索引擎收录几率 
  •    新增 MiniSpace 功能,充分关注会员的成长历程和个性展示 
  •    增强 WAP 系统,新增WAP注册功能在手机设备兼容性能上大为提高,重新设计的操作界面更
       符合 WAP 标准和手机用户的使用习惯 
  •    新增 左右分栏功能,显示风格与论坛自动融合,扩展方便。支持后台开关和会员开关 
  •    首创 GIF 动画验证码支持,提高灌水机识别难度 
  •    新增 论坛策略方案系统 
  •    新增 公告类型-公共短消息,可强制提醒用户阅读某些重要内容。公共短消息无论一次发给多
       少用户,均为一条数据存储,不会占用过多资源 
  •    广告位全新布局 提升论坛盈利空间 
  •  加强论坛安全防御措施,让站长更加安心 
  •  新增 远程附件上传、管理功能
Discuz! 特征 (三) 
•  版本6 
   •    全面优化论坛显示模板,大幅度提升页面显示速度,为您带来极速浏览体验 
   •    论坛页面采用 XHTML 标准以及结构化 CSS 设计,让风格设计更加随心所欲 
   •    内置 6 套精心设计的炫酷风格,让论坛更具个性风采,可符合大部分站点需求 
   •    新增 Insenz 社区系列营销服务,为广大站长提供高质量的、与社区定位相匹配的广告和稳定的
        收益 
   •    采用 Ajax 技术让管理人员通过双击帖子标题或者帖子内容进行进行标题和内容的编辑 
   •    采用 Ajax 技术完成阅读短消息和发送短消息 
   •    新增 标签(Tag)功能,主动式信息分类让论坛主题相互链接,提高站点 PV 
   •    新增 辩论主题功能,会员可发起辩论主题,实时显示辩论情况 
   •    全新 论坛交易体系,使论坛可以迅速搭建成 C2C、B2C 电子交易平台 
   •    新增 个性化分类信息主题发布系统,彻底打破论坛传统的(主题+内容)模式。 
   •    新增 论坛板块 SEO 设置,各板块可分别设置关键词,更利于搜索引擎收录 
   •    新增 发布视频功能 
   •    增强 CC 防御体系,调整 CC 防御策略,减少在防御功能开启后对正常用户浏览的干
重要版本
用户驱动开发   使用基数不断攀升去年30万,今年40万
Discuz!的一些技术指标 
• 页脚执行时间保持在0.02秒。 
• 官方最高上线人数达到2.2万,央视复兴论坛达
  到6万。 
• 第二次刷新以上,SQL查询保持在3到6个之间。 
• 有关安全的设计,包括函数定义过程等20余处。 
• 安装包仅3.7M,Discuz! 1.0 仅500k。 
• 6.0的数据表93张,文件总数1500个。 
• 类似smarty的模板引擎共128行。 
• 后台基本选项229个。
Discuz!团队概况 
•  一支不足10人的队伍。 
•  100%的开发人员有自己的Discuz!论坛。 
•  80%的个人爱好是论坛,20%的爱好是其它。 
•  每个人,代码熟悉程度70%左右。 
•  加班与正常下班的比值1:90。 
•  但分不清上下班,回家还是搞这套。 
•  新功能先在自己的论坛上实现在移植到Discuz!上。 
•  工作主动性强,没有非常明显的管理者与被管理
   者。 
•  凑这样一只队伍不容易。
基本开发过程
遵守团队的代码规范 
1. 尽量一次完成代码,而不要多次修订。 
2. XHTML代码要满足至少IE Firefox Opera等浏览器。 
3. 程序要能适应最低PHP 4.0.5(4.3.0) + MySQL3.2.3 + 虚拟主机 
4. 尽量使用三元操作而减少一般的if过程。 

$username = !empty($username) ? dhtmlspecialchars($username) : ''; 

5. 使用$comma连接多节字符串 

$ids = $comma = ''; 
foreach($delete as $id) { 
            $ids .= "$comma'$id'"; 
            $comma = ','; 
} 

6. 习惯使用empty(), isset(), in_array()校验变量及变量有效范围。 

if(!in_array($key, array('action', 'sid', 'formhash', 'admin_password')) && $val) { 
... 
}
if(in_array($action, array('moderate', 'delete', 'move', 'highlight', 'type', 

if(!empty($url_forward)) { 
            echo "<meta http­equiv=refresh content="0;URL=$url_forward">";exit; 
} 

7. SQL语句中的=、<>、>、<、+等操作符前后不允许有空格。 

groupuid WHERE gid='$gid' AND uid='$discuz_uid' AND flag>1", 'SILENT'); 

8. 段前段后留白 

} elseif($action == 'split') { 

               if(!submitcheck('splitsubmit')) { 

                               require_once DISCUZ_ROOT.'./include/discuzcode.func.php'; 

                               ... 

­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ 

               include template('topicadmin_split'); 

} else { 

9. 简单if的替代写法 $page > $totalpage && $page = $totalpage;
尽可能减小执行时间、IO、查询、内存消耗和执行时间

统计执行时间和查询数 
$mtime = explode(' ', microtime()); 
$discuz_starttime = $mtime[1] + $mtime[0]; 

$debuginfo = array('time' => number_format(($mtime[1] + $mtime[0] ­ $discuz_starttime), 6) 
            , 'queries' => $db­>querynum); 

function query($sql, $type = '') { 
            ... 
            $this­>querynum++; 
            return $query; 
} 

统计I/O次数,例如封装fopen­>sfopen(); 
function sfopen($filename) { 
             global $ios; 
             $ios++; 
             return fopen($filename); 
} 

fopen() filemtime() touch() file_exists() 

$ios += count(get_included_files());
统计内存消耗 

(PHP 4 >= 4.3.2, PHP 5) 

if(function_exists('memory_get_usage')) { 
             $mem = number_format(memory_get_usage() / 1024, 2); 
}
尽可能减少实时性操作

函数定义                     表     判定ID  更新列            缓存 
function updateviews($table, $idcol, $viewscol, $logfile) { 
            global $db, $tablepre; 

            $viewlog = $viewarray = array(); 
            if(@$viewlog = file($logfile = DISCUZ_ROOT.$logfile)) { 
                        @unlink($logfile); 
                        $viewlog = array_count_values($viewlog); 
                        foreach($viewlog as $id => $views) { 
                                     $viewarray[$views] .= ($id > 0) ? ','.intval($id) : ''; 
                        } 
                        foreach($viewarray as $views => $ids) { 
                                     $db­>query("UPDATE LOW_PRIORITY $tablepre$table 
                                     SET $viewscol=$viewscol+'$views' WHERE $idcol IN (0$ids)" 
                                     , 'UNBUFFERED'); 
                        } 
            } 
}
触发机制 

$logfile = './forumdata/cache/cache_attachviews.log'; 
if(substr($timestamp, ­1) == '0') { 
               require_once DISCUZ_ROOT.'./include/misc.func.php'; 
               updateviews('attachments', 'aid', 'downloads', $logfile); 
} 

if(@$fp = fopen(DISCUZ_ROOT.$logfile, 'a')) { 
             fwrite($fp, "$aidn"); 
             fclose($fp); 
} elseif($adminid == 1) { 
             showmessage('view_log_invalid'); 
}
基本环境 

1. showmessage()的使用 
if(!$member = $db­>fetch_array($query)) { 
             showmessage('member_nonexistence'); 
                           ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ 
                                  识别标签 
}if(!$allowviewpro) { 
             showmessage('group_nopermission', NULL, 'NOPERM'); 
} 

message.lang.php  文件中有定义 
'member_nonexistence' => '指定的用户不存在或已被删除,请返回。', 
                                          ­­­­­­ 
                                     都有返回上一页链接

                         信息       是否跳转              扩展属性 
function showmessage($message, $url_forward = '', $extra = '') { 

<!­­{if $url_forward}­­> 
              <p><a href="$url_forward">{lang message_forward}</a></p> 
<!­­{elseif stristr($show_message, '{lang return}')}­­> 
              <p><a href="javascript:history.back()">{lang message_go_back}</a></p> 
<!­­{/if}­­>
2. 统一路径 
define('DISCUZ_ROOT', substr(dirname(__FILE__), 0, ­7)); 

3. 围绕在common.inc.php周围 
require_once './include/common.inc.php'; 
* 加载必要的其它子文件,初始化数据库链接。 
* 最初的对变量的安全处理。 
* 统一路径。 
* 负担计划任务的触发。 
* 获取用户最根本的身份。 

4. 翻页处理multi() 
$multipage = multi($threadcount, $tpp, $page 
            , "forumdisplay.php?fid=$fid$forumdisplayadd" 
            , $threadmaxpages); 

5. 定义有全局的动作。 
$discuz_action = 14; //附件 
$discuz_action = 111; //... 

6. function implodeids($array) { 
             if(!empty($array)) { 
                         return "'".implode("','", is_array($array) ? $array : array($array))."'"; 
             } else { 
                         return ''; 
             } 
}
安全处理 
1. error_reporting(0); 

2. 丢掉有问题的GLOBAL 

if (isset($_REQUEST['GLOBALS']) OR isset($_FILES['GLOBALS'])) { 
             exit('Request tainting attempted.'); 
} 

3. 避免可能的对超级变量的覆盖 
foreach(array('_COOKIE', '_POST', '_GET') as $_request) { 
             foreach($$_request as $_key => $_value) { 
                         $_key{0} != '_' && $$_key = daddslashes($_value); 
             } 
}
4. 在foreach while for if外对数组严格进行初始化。 
* 6.0中使用 = array(); 共445处,涉及到112个文件。 
$forumsarray = array(); 
if(!empty($forums)) { 
           foreach((is_array($forums) ? $forums : explode('_', $forums)) as $forum) { 
                      if($forum = intval(trim($forum))) { 
                                 $forumsarray[] = $forum; 
                      } 
           } 
} 

$type = ­1; 
if($threads > 0) { 
            $type = 1; 
} 

5. unset()敏感信息 
*unset() 共使用了148次,在57个文件中好处 1. 节省内存开支。2. 敏感信息暴露可能性降低。 

6 打开error_reporting(E_ALL)关注NOTICE级别警告
7 注意几个极限 
intval() 解决办法 floatval() 

<?php 

$string = pow(2, 31) ­ 1; 
echo "string=$string"; 
$integer = intval($string); 
echo "<br/>integer=$integer"; 

echo "<hr/>"; 

$string = pow(2, 31); 
echo "string=$string"; 
$integer = intval($string); 
echo "<br/>integer=$integer"; 

?>
mysql_insert_id() 解决办法 
function insert_id() { 
             return ($id = mysql_insert_id($this­>link)) >= 0 ? $id : 
                          $this­>result($this­>query("SELECT last_insert_id()"), 0); 
} 

后者是按照字符串返回的。 

8. 数据库安全 要考虑BIG5冲码问题,以及在查询中增加 
if($dbcharset) { 
             @mysql_query("SET character_set_connection=$dbcharset 
             , character_set_results=$dbcharset 
             , character_set_client=binary" 
             , $this­>link); 
}
9. mysql对特殊字符的转义只管入不管出。 

­­­­­­­­­­­­­­­­­­­­­­­­ 
langwan' 
­­­­­­­­­­­­­­­­­­­­­­­­ 

$sql = "update t1 set f1 = '$data' where id=1"; 
mysql_query($sql); 

$sql = "select f1 from t1 where id = 1"; 
$data = mysql_result(mysql_query($sql), 0); 

echo "<Hr>".$data; 
­­­­­­­­­­­­­­­­­­­­­­­­ 
langwan' 
­­­­­­­­­­­­­­­­­­­­­­­­ 
10. 安全相关的还有formhash() authcode() wipespecial() transsid() 函数等。
协议安全性
由于HTTP、FTP协议的老弱,协议封装不严格,导致的因换行为主的隐患。 

1. IP地址的漏洞 
preg_match("/[d.]{7,15}/", $onlineip, $onlineipmatches); 
$onlineip = $onlineipmatches[0] ? $onlineipmatches[0] : 'unknown'; 
unset($onlineipmatches); 

2. FTP换行漏洞 
function dftp_get($ftp_stream, $local_file, $remote_file, $mode, $resumepos = 0) { 
             $remote_file = wipespecial($remote_file); 
             $local_file = wipespecial($local_file); 
             $mode = intval($mode); 
             $resumepos = intval($resumepos); 
             return @ftp_get($ftp_stream, $local_file, $remote_file, $mode, $resumepos); 
} 

function wipespecial($str) { 
            return str_replace(array('..', "n", "r"), array('', '', ''), $str); 
}
3. HTTP协议的换行漏洞 

function dheader($string, $replace = true, $http_response_code = 0) { 
            $string = str_replace(array("r", "n"), array('', ''), $string); 
            if(empty($http_response_code) || PHP_VERSION < '4.3' ) { 
                          @header($string, $replace); 
            } else { 
                          @header($string, $replace, $http_response_code); 
            } 
            if(preg_match('/^s*location:/is', $string)) { 
                          exit(); 
            } 
}
authcode 
* Discuz!核心加密函数,利用了md5 RC4 两种加密算法。 
* 随着开源,安全意识的增加,逐步authcode的使用率随版本上升。
效率和性能 
1. 使用内存表改善缓存性数据。 
cdb_sessions  CREATE TABLE `cdb_sessions` ( 
    `sid` char(6) character set ... 
    ... 
) ENGINE=MEMORY DEFAULT CHARSET=gbk 

2. 使用以下手段解决limit变慢的问题 
* 缓存查询结果 
* 限制翻页的最大上限,例如PAGE * MAXROW = TOTAL,100 * 20 = 2000条以内其实足够了,百度、新浪、 
google也是如此。 
* 增加最大上限查询时间。例如一年内或者按年归档数据。 
* 使用其它数据源做搜索,例如备份数据联合lucene等。 
* 作为小系统限制为主,索引为辅、技巧其次。 
* 当每页行数在30以上,可以仅使用 where id < B  and id > A , B – A = 30来罗列。
* 可以判定翻页条件 例如 CUR_PAGE > TOTAL_PAGE / 2,改变order by的升降 

       $totalpage = ceil(($thread['replies'] + 1) / $ppp); 
       $page > $totalpage && $page = $totalpage; 
       $pagebydesc = $page > 50 && $page > ($totalpage / 2) ? TRUE : FALSE; 

       if($pagebydesc) { 
                   $firstpagesize = ($thread['replies'] + 1) % $ppp; 
                   $ppp2 = $page == $totalpage && $firstpagesize ? $firstpagesize : $ppp; 
                   $realpage = $totalpage ­ $page + 1; 
                   $start_limit = max(0, ($realpage ­ 2) * $ppp + $firstpagesize); 
                   $numpost = ($page ­ 1) * $ppp; 
                   $pageadd =  "ORDER BY dateline DESC LIMIT $start_limit, $ppp2"; 
       } else { 
                   $start_limit = $numpost = ($page ­ 1) * $ppp; 
                   if($start_limit > $thread['replies']) { 
                                 $start_limit = $numpost = 0; 
                                 $page = 1; 
                   } 
                   $pageadd =  "ORDER BY dateline LIMIT $start_limit, $ppp"; 
       }
2. 使用explain分析效率。 
* 如果rows字段过大例如rows = 100000 需要缩小where语句的条件或更换where条件的顺序。 
* 如果Extra信息里包含Using filesort并且rows也很大需要增大sort_buffer_size 
 SET GLOBAL sort_buffer_size=value; 
 出现using filesort需要对索引重新调整,还是可以消除filesort的 
* Using temporary创建临时表,需要优化group by 
3. 使用show processlist; 

mysql> show processlist; 
+­­­­+­­­­­­­+­­­­­­­­­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­+ 
| Id  | User | Host               | db            | Command  | Time | State       | Info | 
+­­­­+­­­­­­­+­­­­­­­­­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­+ 
|  1  | root | localhost:1032 | discuz6    | Sleep             |   45   |                | NULL                    | 
|  2 | root | localhost:1033 | NULL        | Sleep             |  78   |Locked    | select * from cdb | 
|  5 | root | localhost:1036 | NULL       | Query            |  0    | NULL     | show processlist  | 
+­­­+­­­­­­+­­­­­­­­­­­­­­­­­­+­­­­­­­­­­­­+­­­­­­­­­­­­­­­­+­­­­­­­+­­­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­+ 
3 rows in set (0.00 sec) 

* 如果State=Locked就是锁表,如果Time时间过长,超过20秒,就会带着下面一系列的SQL全部锁死。
<?php 
define('MAX_SLEEP_TIME', 120); 

$hostname = "localhost"; 
$username = "root"; 
$password = "password"; 

$connect = mysql_connect($hostname, $username, $password); 
$result = mysql_query("SHOW PROCESSLIST", $connect); 
while ($proc = mysql_fetch_assoc($result)) { 
   if ($proc["Command"] == "Sleep" && $proc["Time"] > MAX_SLEEP_TIME) { 
       @mysql_query("KILL " . $proc["Id"], $connect); 
   } 
} 
mysql_close($connect); 
?>

使用上面这段代码可以杀掉锁死的MySQL查询,会大量缓解。但不是正解做法。
正确的方法是 打开MySQL慢查询记录,得到慢速SQL,使用Explain进行分析,
对索引甚至是查询条件进行优化。

当然请使用Linux下的Cron或者Windows下的AT命令挂到。
对于LEFT JION > 3个的要格外注意,在有效观察下适当拆分 

1.  单独执行条件简单。 
2.  尽量缩短重要表的独占时间,例如cdb_posts表。 
3.  拆分LEFT JOIN有利于单独部署。
md5的效率性 随着字符串长度的增加时间也在增加。
XHTML的提速作用
缓存设计 
• 系统缓存 
 • settings forums icons ranks usergroups 
 • index[announcements onlinelist...] 
• 帖子缓存 
 • 根据缓存系数进行的缓存。 
• 点击量缓存 
 • 根据重复次数,减少数据库插入次数。 
• 搜索缓存
系统缓存特点

* 缓存页PAGE 可以包含多个子页 sub_cache。也可以仅包含一个sub_cache。 
* 每次执行updatecache(sub_cache),仅会刷新子缓存,并对有影响的PAGE做更新。 
* 缓存结果存为一般php数组。对于PAGE没有过期时间的判定。 
* 当触发后台事件,才会调用updatecache() 
帖子缓存
1. 对游客才生效的缓存 

if($cachethreadlife && $forum['threadcaches'] && !$discuz_uid && $page == 1 && !$forum['special']) { 
             viewthread_loadcache(); 
} 

2. viewthread_loadcache() 加载缓存函数 

3. 计算缓存系数 

$threadcachemark = 100 ­ ( 
                       $forum['displayorder'] * 15 + 
                       $forum['digest'] * 10 + 
                       min($forum['views'] / max($forum['livedays'], 10) * 2, 50) + 
                       max(­10, (15 ­ $forum['lastpostdays'])) + 
                       min($forum['replies'] / $_DCACHE['settings']['postperpage'] * 1.5, 15)); 
4. 获取缓存信息,并调用缓存 

if($threadcachemark < $forum['threadcaches']) { 

                        $threadcache = getcacheinfo($tid); 

                        if($timestamp ­ $threadcache['filemtime'] > $cachethreadlife) { 
                                    @unlink($threadcache['filename']); 
                                    define('CACHE_FILE', $threadcache['filename']); 
                                    $styleid = $_DCACHE['settings']['styleid']; 
                                    @include DISCUZ_ROOT.'./forumdata/cache/style_'.$styleid.'.php'; 
                        } else { 
                                    readfile($threadcache['filename']);
5. getcacheinfo()函数 

function getcacheinfo($tid) { 
             global $timestamp, $cachethreadlife, $cachethreaddir; 
             $tid = intval($tid); 
             $cachethreaddir2 = DISCUZ_ROOT.'./'.$cachethreaddir; 
             $cache = array('filemtime' => 0, 'filename' => ''); 
             $tidmd5 = substr(md5($tid), 3); 
             $fulldir = $cachethreaddir2.'/'.$tidmd5[0].'/'.$tidmd5[1].'/'.$tidmd5[2].'/'; 
             $cache['filename'] = $fulldir.$tid.'.htm'; 
             if(file_exists($cache['filename'])) { 
                           $cache['filemtime'] = filemtime($cache['filename']); 
             } else { 
                           if(!is_dir($fulldir)) { 
                                         for($i=0; $i<3; $i++) { 
                                                      $cachethreaddir2 .= '/'.$tidmd5{$i}; 
                                                      if(!is_dir($cachethreaddir2)) { 
                                                                    @mkdir($cachethreaddir2, 0777); 
                                                                    @touch($cachethreaddir2.'/index.htm'); 
                                                      } 
                                         } 
                           } 
             } 
             return $cache; 
} 

取md5(tid)的前三位,作为三层目录结构。得到缓存的路径及创建时间,存放到数组中返回。
6. 在output()函数中生成缓存 

if(defined('CACHE_FILE') && CACHE_FILE && !defined('CACHE_FORBIDDEN')) { 
             global $cachethreaddir; 
             if(diskfreespace(DISCUZ_ROOT.'./'.$cachethreaddir) > 1000000) { 
                          if($fp = @fopen(CACHE_FILE, 'w')) { 
                                      flock($fp, LOCK_EX); 
                                      fwrite($fp, empty($content) ? ob_get_contents() : $content); 
                          } 
                          @fclose($fp); 
                          chmod(CACHE_FILE, 0777); 
             } 
} 

7. 系统缓存在cache.func.php里面定义的。
搜索缓存 
* 搜索结果从searchindexs表取出。 
* 如果缓存过期或是没有类似搜索,则从cdb_posts表查询并将结果存到searchindexs。 
* 无论怎样搜索数据都根据searchid从缓存表中得到。
计划任务 
* 第一步,在settings里面存放了下一次任务执行时间。 
} elseif($cronnextrun && $cronnextrun <= $timestamp) { 
           require_once DISCUZ_ROOT.'./include/cron.func.php'; 
           runcron(); 

* 当前时间超过计划任务时间,触发runcron()。 
 1. 从cdb_crons中取出需要执行的仅一条limit 1的计划任务。 
 2. touch($lockfile)锁住,导致同时间触发的其它计划任务无法执行。 
 3. cronnextrun()执行计划任务并把下一条任务的时间写到settings中。 
 4. unlink($lockfile)解除锁定状态。 

* 重新从第一步开始新的流程。
用户系统 
1. 使用cdb_sessions表来存储活动用户。 

* sessions表是一张内存表 
* 重要字段 sid username groupid styleid pageviews seccode fid tid 
* sid 随机产生的,每一次来访都不一样。 
* seccode 如果BBS需要验证码,验证码存在sessions表里更安全。 

2. 使用cdb_members + cdb_memberfields表存储实际用户信息 

* 两张表的主要区别在于前者是定长且常用表,后者是变长且不常用表。 
* 主要字段 uid username password secques adminid groupid 

3. cookie中两个重要变量 
* $_COOKIE['xxx_sid'] 
* $_COOKIE['xxx_auth'] 
C(sid) = S(sid) 
C(auth) = authcode(password + secques + uid) 

4. $discuz_auth_key = md5($_DCACHE['settings']['authkey'] 
                                .$_SERVER['HTTP_USER_AGENT']); 

5. $_DSESSION 作为在论坛活动中的用户活跃信息。
积分体系 
1. 使用8+1机制,8种积分+总积分。 
2. 8种积分中的一种作为交易积分。 
3. 积分公式默认等于积分1,而可以对积分1­8、发帖数、级别等多种数据任意公式。 
4. 使用函数updatecredits() updatepostcredits()函数更新用户和主题积分。 
5. 使用checklowerlimit()检查积分下限要求。 
6. 用户等级的依据是总积分。 
7. 用户表cdb_members包含积分字段 
credits 
extcredits1 
extcredits2 
extcredits3 
extcredits4 
extcredits5 
extcredits6 
extcredits7 
extcredits8 
8. 登录、查看帖子或是他人信息的时候会触发getgroupid()更新等级。
项目改造、二次开发 
1.     开启帖子缓存功能,大幅减少SQL查询。 
2.     把部分常态缓存放到/dev/shm/的共享缓存里,减少IO数量。 
3.     使用F5均衡Web负载。 
4.     使用squid技术做前端静态缓存。 
5.     独立附件服务器,设置独立的域名。 
6.     对磁盘做Raid5或Raid10。 
7.     使用MySQL商业版本的集群技术。 
8.     对大表分表存归档。 
9.     使用lucene等分离搜索服务器。 
10.    对不同版块使用不同服务器不同域名。搜索不可以跨板块。 
11.    处理好SSO或者通行证系统。 
12.    尝试使用Zeus、lighttpd服务器来替代apache。 
13.    买CDN吧。 
14.    从数据库备份中搜索或做统计信息,避免由于搜索带来的锁表,引起的数据库错误。 
15.    使用系统Cron或AT来代替PHP脚本的计划任务。 
16.    适当增加一些守护进程或系统级计划任务来缓存或交换数据。 
17.    系统级的对web服务器、Apache服务器进行缓存调优。 
18.    对不良来源的请求进行屏蔽。 
19.    适当增加索引,减慢插入,加速查询。
ajax技术
GIF验证码

Mais conteúdo relacionado

Mais procurados

Yui3入门
Yui3入门Yui3入门
Yui3入门cly84920
 
Sina App Quick Guide 1
Sina App Quick Guide 1Sina App Quick Guide 1
Sina App Quick Guide 1guestf4aed35
 
[DCTPE2010] Drupal 模組開發入門
[DCTPE2010] Drupal 模組開發入門[DCTPE2010] Drupal 模組開發入門
[DCTPE2010] Drupal 模組開發入門Drupal Taiwan
 
古斯塔斯集团的Qmail邮件系统
古斯塔斯集团的Qmail邮件系统古斯塔斯集团的Qmail邮件系统
古斯塔斯集团的Qmail邮件系统gavin shaw
 
Node getting-started
Node getting-startedNode getting-started
Node getting-startedlylijincheng
 
6kbbs vulnerability report
6kbbs vulnerability report6kbbs vulnerability report
6kbbs vulnerability reportinsight-labs
 
Spring入门纲要
Spring入门纲要Spring入门纲要
Spring入门纲要yiditushe
 
KISSY for starter
KISSY for starterKISSY for starter
KISSY for starteryiming he
 
Zencart网站模板复制过程
Zencart网站模板复制过程Zencart网站模板复制过程
Zencart网站模板复制过程xiaochenlbm
 
jQuery实践经验与技巧
jQuery实践经验与技巧jQuery实践经验与技巧
jQuery实践经验与技巧fangdeng
 
Mongodb
MongodbMongodb
Mongodbbj
 
MongoDB for C# developer
MongoDB for C# developerMongoDB for C# developer
MongoDB for C# developerdianming.song
 
1.oracle 11g 用户管理新功能
1.oracle 11g 用户管理新功能1.oracle 11g 用户管理新功能
1.oracle 11g 用户管理新功能WASecurity
 
用Jquery实现拖拽层
用Jquery实现拖拽层用Jquery实现拖拽层
用Jquery实现拖拽层yiditushe
 
jQuery 選取器解析
jQuery 選取器解析jQuery 選取器解析
jQuery 選取器解析Kingsley Zheng
 

Mais procurados (20)

Yui3入门
Yui3入门Yui3入门
Yui3入门
 
Sina App Quick Guide 1
Sina App Quick Guide 1Sina App Quick Guide 1
Sina App Quick Guide 1
 
J query
J queryJ query
J query
 
[DCTPE2010] Drupal 模組開發入門
[DCTPE2010] Drupal 模組開發入門[DCTPE2010] Drupal 模組開發入門
[DCTPE2010] Drupal 模組開發入門
 
古斯塔斯集团的Qmail邮件系统
古斯塔斯集团的Qmail邮件系统古斯塔斯集团的Qmail邮件系统
古斯塔斯集团的Qmail邮件系统
 
Node getting-started
Node getting-startedNode getting-started
Node getting-started
 
6kbbs vulnerability report
6kbbs vulnerability report6kbbs vulnerability report
6kbbs vulnerability report
 
Spring入门纲要
Spring入门纲要Spring入门纲要
Spring入门纲要
 
KISSY for starter
KISSY for starterKISSY for starter
KISSY for starter
 
Zencart网站模板复制过程
Zencart网站模板复制过程Zencart网站模板复制过程
Zencart网站模板复制过程
 
jQuery实践经验与技巧
jQuery实践经验与技巧jQuery实践经验与技巧
jQuery实践经验与技巧
 
Mongodb
MongodbMongodb
Mongodb
 
MySQL入門介紹
MySQL入門介紹MySQL入門介紹
MySQL入門介紹
 
MongoDB for C# developer
MongoDB for C# developerMongoDB for C# developer
MongoDB for C# developer
 
1.oracle 11g 用户管理新功能
1.oracle 11g 用户管理新功能1.oracle 11g 用户管理新功能
1.oracle 11g 用户管理新功能
 
用Jquery实现拖拽层
用Jquery实现拖拽层用Jquery实现拖拽层
用Jquery实现拖拽层
 
MySQL進階介紹
MySQL進階介紹MySQL進階介紹
MySQL進階介紹
 
Ooredis
OoredisOoredis
Ooredis
 
JQuery Plugin
JQuery PluginJQuery Plugin
JQuery Plugin
 
jQuery 選取器解析
jQuery 選取器解析jQuery 選取器解析
jQuery 選取器解析
 

Semelhante a Discuz技术交流

Migrations 與 Schema操作
Migrations 與 Schema操作Migrations 與 Schema操作
Migrations 與 Schema操作Shengyou Fan
 
PHP & MySQL 教學
PHP & MySQL 教學PHP & MySQL 教學
PHP & MySQL 教學Bo-Yi Wu
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验QLeelulu
 
Introduction to CodeIgniter
Introduction to CodeIgniterIntroduction to CodeIgniter
Introduction to CodeIgniterChun-Kai Wang
 
前端MVC之backbone
前端MVC之backbone前端MVC之backbone
前端MVC之backboneJerry Xie
 
Migrations 與 Schema 操作
Migrations 與 Schema 操作Migrations 與 Schema 操作
Migrations 與 Schema 操作Shengyou Fan
 
Introduction to MVC of CodeIgniter 2.1.x
Introduction to MVC of CodeIgniter 2.1.xIntroduction to MVC of CodeIgniter 2.1.x
Introduction to MVC of CodeIgniter 2.1.xBo-Yi Wu
 
Javascript autoload
Javascript autoloadJavascript autoload
Javascript autoloadjay li
 
Web development with zend framework
Web development with zend frameworkWeb development with zend framework
Web development with zend frameworkthinkinlamp
 
一拍一产品背后的故事(React实战)
一拍一产品背后的故事(React实战)一拍一产品背后的故事(React实战)
一拍一产品背后的故事(React实战)Kejun Zhang
 
Spring 2.x 中文
Spring 2.x 中文Spring 2.x 中文
Spring 2.x 中文Guo Albert
 
面向未来的重构
面向未来的重构面向未来的重构
面向未来的重构Kejun Zhang
 
旺铺前端设计和实现
旺铺前端设计和实现旺铺前端设计和实现
旺铺前端设计和实现hua qiu
 
jQuery底层架构
jQuery底层架构jQuery底层架构
jQuery底层架构fangdeng
 
Drupal 版型設計 - 瞭解版型程式
Drupal 版型設計 - 瞭解版型程式Drupal 版型設計 - 瞭解版型程式
Drupal 版型設計 - 瞭解版型程式Chris Wu
 
CKAN : 資料開放平台技術介紹 (CAKN : Technical Introduction to Open Data Portal)
CKAN : 資料開放平台技術介紹 (CAKN : Technical Introduction to Open Data Portal)CKAN : 資料開放平台技術介紹 (CAKN : Technical Introduction to Open Data Portal)
CKAN : 資料開放平台技術介紹 (CAKN : Technical Introduction to Open Data Portal)Jian-Kai Wang
 
用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Servicesjavatwo2011
 
大型互联网应用架构设计
大型互联网应用架构设计大型互联网应用架构设计
大型互联网应用架构设计thinkinlamp
 

Semelhante a Discuz技术交流 (20)

Migrations 與 Schema操作
Migrations 與 Schema操作Migrations 與 Schema操作
Migrations 與 Schema操作
 
PHP & MySQL 教學
PHP & MySQL 教學PHP & MySQL 教學
PHP & MySQL 教學
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验
 
CRUD 綜合運用
CRUD 綜合運用CRUD 綜合運用
CRUD 綜合運用
 
Introduction to CodeIgniter
Introduction to CodeIgniterIntroduction to CodeIgniter
Introduction to CodeIgniter
 
前端MVC之backbone
前端MVC之backbone前端MVC之backbone
前端MVC之backbone
 
Node way
Node wayNode way
Node way
 
Migrations 與 Schema 操作
Migrations 與 Schema 操作Migrations 與 Schema 操作
Migrations 與 Schema 操作
 
Introduction to MVC of CodeIgniter 2.1.x
Introduction to MVC of CodeIgniter 2.1.xIntroduction to MVC of CodeIgniter 2.1.x
Introduction to MVC of CodeIgniter 2.1.x
 
Javascript autoload
Javascript autoloadJavascript autoload
Javascript autoload
 
Web development with zend framework
Web development with zend frameworkWeb development with zend framework
Web development with zend framework
 
一拍一产品背后的故事(React实战)
一拍一产品背后的故事(React实战)一拍一产品背后的故事(React实战)
一拍一产品背后的故事(React实战)
 
Spring 2.x 中文
Spring 2.x 中文Spring 2.x 中文
Spring 2.x 中文
 
面向未来的重构
面向未来的重构面向未来的重构
面向未来的重构
 
旺铺前端设计和实现
旺铺前端设计和实现旺铺前端设计和实现
旺铺前端设计和实现
 
jQuery底层架构
jQuery底层架构jQuery底层架构
jQuery底层架构
 
Drupal 版型設計 - 瞭解版型程式
Drupal 版型設計 - 瞭解版型程式Drupal 版型設計 - 瞭解版型程式
Drupal 版型設計 - 瞭解版型程式
 
CKAN : 資料開放平台技術介紹 (CAKN : Technical Introduction to Open Data Portal)
CKAN : 資料開放平台技術介紹 (CAKN : Technical Introduction to Open Data Portal)CKAN : 資料開放平台技術介紹 (CAKN : Technical Introduction to Open Data Portal)
CKAN : 資料開放平台技術介紹 (CAKN : Technical Introduction to Open Data Portal)
 
用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services
 
大型互联网应用架构设计
大型互联网应用架构设计大型互联网应用架构设计
大型互联网应用架构设计
 

Discuz技术交流