您的位置:首页 > 数据库 > Memcache

DISCUZ论坛使用memcached优化解决方案

2010-07-29 16:34 225 查看
转载本文请保留作者信息,违者必究

作者:覃学涵(http://www.3sys.cn/

Email:qinxuehan@126.com

如何让discuz支持千万级别的数据和大用户量访问呢?答案是使用memcached优化。本文讨论DISCUZ论坛使用memcached优化的解决方案。作者使用的discuz版本是7.0, 7.0之后的优化方法本文没有做介绍,可以参考本文,举一反三。

思路:

1.无需修改全站的代码,只对DISCUZ的MYSQL的数据库操作类修改,支持MEMCACHED。

2.有MEMCACHED总开关,需要的时候打开MEMCACHED缓存,访问量不大时,关闭MEMCACHED缓存。

3.为不影响用户体验,用户登录的时候关闭MEMCACHED缓存,不登录的用户访问,开启memcached缓存。

4.memcached开启可以防洪,应付大规模的DDOS攻击。

步骤一、安装memcached.

安装方法 参考本文作者,我写的文章,网址:

http://blog.csdn.net/IeSneaker/archive/2010/07/21/5753264.aspx

步骤二、修改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


步骤三、修改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;
}
}

?>


步骤四、修改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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: