轉載本文請保留做者信息,違者必究php
做者:覃學涵(http://www.3sys.cn/)mysql
Email:qinxuehan@126.comsql
如何讓discuz支持千萬級別的數據和大用戶量訪問呢?答案是使用memcached優化。本文討論DISCUZ論壇使用memcached優化的解決方案。做者使用的discuz版本是7.0, 7.0以後的優化方法本文沒有作介紹,能夠參考本文,觸類旁通。數據庫
思路:數組
1.無需修改全站的代碼,只對DISCUZ的MYSQL的數據庫操做類修改,支持MEMCACHED。緩存
2.有MEMCACHED總開關,須要的時候打開MEMCACHED緩存,訪問量不大時,關閉MEMCACHED緩存。服務器
3.爲不影響用戶體驗,用戶登陸的時候關閉MEMCACHED緩存,不登陸的用戶訪問,開啓memcached緩存。memcached
4.memcached開啓能夠防洪,應付大規模的DDOS攻擊。fetch
步驟1、安裝memcached.優化
安裝方法 參考本文做者,我寫的文章,網址:
http://blog.csdn.net/IeSneaker/archive/2010/07/21/5753264.aspx
步驟2、修改discuz的配置文件
修改根目錄下的config.inc.php,增長以下代碼
// ============================================================================ // memcache 改造 // ============================================================================ define("IS_RUN_MEMCACHE",true); //是否開啓memcached define("MEMCACHE_HOST",'127.0.0.1'); //memcache 服務器 define("MEMCACHE_PORT",11211); //memcache 端口 define("MEMCACHE_LIFETIME",5*60); //memcache 時間 define("MEMCACHE_PREFIX","MYSITE"); //cacheid使用的前綴 本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/IeSneaker/archive/2010/07/29/5774295.aspx
步驟3、修改discuz數據庫操做類
修改include/db_mysql.class.php文件,做者這裏貼出這個類修改後的完整代碼。
<?php /* [Discuz!] (C)2001-2009 Comsenz Inc. This is NOT a freeware, use is subject to license terms $Id: db_mysql.class.php 16688 2008-11-14 06:41:07Z cnteacher $ $modify by 覃學涵 網站: http://www.3sys.cn */ if(!defined('IN_DISCUZ')) { exit('Access Denied'); } class dbstuff { var $version = ''; var $querynum = 0; var $link = null; var $memcache = null; var $isCache = false; //是否開啓memcached var $arrCursor = array(); //數據遊標 function & get_memcache() { if (is_object($this->memcache) == false) { $this->memcache = new Memcache(); $this->memcache->connect(MEMCACHE_HOST, MEMCACHE_PORT); } return $this->memcache; } function connect($dbhost, $dbuser, $dbpw, $dbname = '', $pconnect = 0, $halt = TRUE, $dbcharset2 = '') { $func = empty($pconnect) ? 'mysql_connect' : 'mysql_pconnect'; if(!$this->link = @$func($dbhost, $dbuser, $dbpw, 1)) { $halt && $this->halt('Can not connect to MySQL server'); } else { if($this->version() > '4.1') { global $charset, $dbcharset; $dbcharset = $dbcharset2 ? $dbcharset2 : $dbcharset; $dbcharset = !$dbcharset && in_array(strtolower($charset), array('gbk', 'big5', 'utf-8')) ? str_replace('-', '', $charset) : $dbcharset; $serverset = $dbcharset ? 'character_set_connection='.$dbcharset.', character_set_results='.$dbcharset.', character_set_client=binary' : ''; $serverset .= $this->version() > '5.0.1' ? ((empty($serverset) ? '' : ',').'sql_mode=/'/'') : ''; $serverset && mysql_query("SET $serverset", $this->link); } $dbname && @mysql_select_db($dbname, $this->link); } } function select_db($dbname) { return mysql_select_db($dbname, $this->link); } function fetch_array($query, $result_type = MYSQL_ASSOC) { if ($this->isCache ) { //緩存 $row = false; if (is_array($query)) { $cacheId = $query["cacheId"]; $arr = & $query["result"]; $nums = $query["nums"]; $cursor = $this->arrCursor[$cacheId]; if ($cursor <= $nums-1) { $row = $arr[$cursor];//返回一行 $this->arrCursor[$cacheId] = $cursor+1;//遊標加一 } } return $row; }else { return mysql_fetch_array($query, $result_type); } } function fetch_first($sql) { return $this->fetch_array($this->query($sql)); } function result_first($sql) { return $this->result($this->query($sql), 0); } function query($sql, $type = '') { $query = false; if (IS_RUN_MEMCACHE == false) { //總開關關閉緩存 $this->isCache = false; } //echo "ALL:".$sql."<br>/n"; if ($this->isCache && $this->is_cache_sql($sql)) {//有緩存 $cacheId = $this->get_cache_id($sql); //cacheId $this->arrCursor[$cacheId] = 0; $query = & $this->get_cache($sql) ; //緩存中讀取 if (!is_array($query)) { //取數據庫 $res = & $this->_query_from_db($sql, $type) ; if (!$res) { return false; } //取出數組緩存到memcached $i = 0; $arr = array(); while($row = mysql_fetch_array($res)) { $arr[$i] = $row ; $i++; } $query["cacheId"] = $cacheId; $query["sql"] = $sql;//SQL語句 $query["result"] = $arr; //數據結果列表 $query["nums"] = $i; //數據結果數量 $query["fields_nums"] = mysql_num_fields($res); //字段數 $query["fields"] = mysql_fetch_field($res); //字段 $this->set_cache($sql,$query,MEMCACHE_LIFETIME); //緩存起來 }else{ //echo "Cache:".$sql."<br>/n"; } return $query; }else{ $query = & $this->_query_from_db($sql, $type) ; //無緩存 } return $query; } //數據庫訪問 function & _query_from_db($sql, $type = '') { global $debug, $discuz_starttime, $sqldebug, $sqlspenttimes; if(defined('SYS_DEBUG') && SYS_DEBUG) { @include_once DISCUZ_ROOT.'./include/debug.func.php'; sqldebug($sql); } $func = $type == 'UNBUFFERED' && @function_exists('mysql_unbuffered_query') ? 'mysql_unbuffered_query' : 'mysql_query'; if(!($query = $func($sql, $this->link))) { if(in_array($this->errno(), array(2006, 2013)) && substr($type, 0, 5) != 'RETRY') { $this->close(); require DISCUZ_ROOT.'./config.inc.php'; $this->connect($dbhost, $dbuser, $dbpw, $dbname, $pconnect, true, $dbcharset); $this->query($sql, 'RETRY'.$type); } elseif($type != 'SILENT' && substr($type, 5) != 'SILENT') { $this->halt('MySQL Query Error', $sql); } } $this->querynum++; return $query; } //從memcahce中取數據 function & get_cache($sql) { $cacheId = $this->get_cache_id($sql); $ret = $this->get_memcache()->get($cacheId); if (is_array($ret) || is_object($ret)) { return $ret; } return false; } //memcache緩存數據 function set_cache($sql,$data,$cacheTime=0) { $cacheId = $this->get_cache_id($sql); if (is_array($data) || is_object($data)) { $this->get_memcache()->set($cacheId,$data,0,$cacheTime); } } //判斷是否SQL須要緩存,部分SELECT語句須要緩存 function is_cache_sql($sql) { $sql = strtolower(trim($sql)); $pat = "/^(select){1}(/s)*(/w|/*|/,|/(|/)|/s|/.|/=|0-9|a-z|A-Z|/')*(from)*/i"; //判斷是否select語句 if (preg_match($pat,$sql)) { return true; }else{ return false; } } function affected_rows() { return mysql_affected_rows($this->link); } function error() { return (($this->link) ? mysql_error($this->link) : mysql_error()); } function errno() { return intval(($this->link) ? mysql_errno($this->link) : mysql_errno()); } function result($query, $row = 0) { if ($this->isCache ) { //緩存 $ret = false; if (is_array($query)) { $arr = & $query["result"]; $nums = $query["nums"]; if ($row < $nums-1) { $ret = $arr[$row];//返回一行 } } return $ret; }else { $query = @mysql_result($query, $row); return $query; } } function num_rows($query) { if ($this->isCache ) { //緩存 $ret = 0; if (is_array($query)) { $ret = $query["nums"]; } return $ret; }else { $query = mysql_num_rows($query); return $query; } } function num_fields($query) { if ($this->isCache ) { //緩存 $ret = 0; if (is_array($query)) { $ret = $query["fields_nums"]; } return $ret; } return mysql_num_fields($query); } function free_result($query) { if ($this->isCache ) { //緩存 unset($query); return true; } return mysql_free_result($query); } function insert_id() { return ($id = mysql_insert_id($this->link)) >= 0 ? $id : $this->result($this->query("SELECT last_insert_id()"), 0); } function fetch_row($query) { if ($this->isCache ) { //緩存 $row = false; if (is_array($query)) { $cacheId = $query["cacheId"]; $arr = & $query["result"]; $nums = $query["nums"]; $cursor = $this->arrCursor[$cacheId]; if ($cursor <= $nums-1) { $row = $arr[$cursor];//返回一行 $this->arrCursor[$cacheId] = $cursor+1;//遊標加一 } } return $row; }else { $query = mysql_fetch_row($query); return $query; } } function fetch_fields($query) { if ($this->isCache ) { //緩存 $ret = false; if (is_array($query)) { $ret = $query["fields"]; } return $ret; } return mysql_fetch_field($query); } function version() { if(empty($this->version)) { $this->version = mysql_get_server_info($this->link); } return $this->version; } function close() { return mysql_close($this->link); } function halt($message = '', $sql = '') { define('CACHE_FORBIDDEN', TRUE); require_once DISCUZ_ROOT.'./include/db_mysql_error.inc.php'; } function get_cache_id($sql) { $cacheId = MEMCACHE_PREFIX . "_".md5($sql); return $cacheId; } } ?>
步驟4、修改common.inc.php
修改include/common.inc.php文件,增長用戶是否登陸的判斷,而後根據用戶是否登陸,開啓memcached緩存。
在文件中找到下面這幾行
$discuz_auth_key = md5($_DCACHE['settings']['authkey'].$_SERVER['HTTP_USER_AGENT']); list($discuz_pw, $discuz_secques, $discuz_uid) = empty($_DCOOKIE['auth']) ? array('', '', 0) : daddslashes(explode("/t", authcode($_DCOOKIE['auth'], 'DECODE')), 1);
在下面增長下面幾行,做用是:據用戶是否登陸,開啓memcached緩存
//緩存 if ($discuz_uid) {//已經登陸 $db->isCache = false; //關閉緩存 }else{ $db->isCache = true; //未登陸用戶開啓緩存 }
轉載本文請保留做者信息,違者必究
做者:覃學涵(http://www.3sys.cn/)
Email:qinxuehan@126.com