今天是周一,即将面临新一轮挑战。

上午看一会书,过会听说今天的502已经9%了,我就调了若干参数,把nginx 的worker prosess 调成8 了,php-fpm 调到250,接着502飙到了20%,资源监视窗更是变成了条形码。

据一个大牛说,要开启连接池,就是mysql的优化。
一个叫sqlrelay的东西,百度了一下。

参看了http://hi.baidu.com/mrvsumbeujeinxe/item/8ba0c60888cf47c490571896

wget在sourseforge下载了rudiments和sqlrelay。
解压了,./configure –prefix=XXX,按照帖子上面说的做了,结果运行
sqlr-start -id mysqltest
被提示Unable to load dynamic library ‘/usr/local/php/lib/php/extensions/no-debug-non-zts-20060613/sql_relay.so’
仔细检查,发现拼错了–with-php-prefix=/usq/local/php,囧
重新make make install,结果这个错误解决了。

再次运行sqlr-start -id mysqltest被提示
sqlr-listener error:Unable to create a shared memory segment.
搜索找不到
重启php-fpm,报错shmget() failed:  Invalid argument
觉得应该是shm共享内存的错误。
这下可以搜索到,http://blog.sina.com.cn/s/blog_9a4d43d801014avs.html
sysctl -a| grep shmm 居然发现 shmmax是0,什么情况!!
vi /etc/sysctl.conf 了,发现kernel.shmmax=4294967296,觉得是有些大了,就为0 了,
尝试设置为32M,重启reboot,经过漫长等待…………………………

擦,还得不行,只不过报的错不同了:shmget() failed:  No space left on device
搜索之,发现还有一个shmall的东西,应该和shmmax设置的一样。
再次重启,ok。。。

这是原来的配置文件
# Controls the maximum shared segment size, in bytes
kernel.shmmax = 4294967295
# Controls the maximum number of shared memory segments, in pages
kernel.shmall = 268435456

kernel.shmmax 数值说明:单位:字节。一般建议使用物理内存的一半
kernel.shmall 数值说明:单位:页。1页=4k,设置数值则为物理内存大小
以4G内存为例:4096*1024*1024/4000=1073742
注:以上两项数值如果填写大于本身物理内存则会不生效

看了这个文章http://www.xmydlinux.org/?p=366
觉得我们的kernel.shmmax=1073741824;kernel.shmall=262144

大功告成,502很少了!!共享内存也解决了。

主要是kernel.shmmax=1073741824;kernel.shmall=262144 这两个参数的设置问题。

ecoder是个很好的在线编辑器,不过有几个地方值得去搞一下,没有完善的登录功能,任何人不经授权可以读写代码,还有google的广告。

首先,上传到服务器上面要配置code.php文件,
两处 $code['root'] = ‘/wwwroot/’
还有secure的安全问题
$code['secure'] = 1;
$code['secure_variable'] = ‘login_security’;
$code['secure_url'] = ‘login.php’;
$code['secure_logouturl']=’login.php?action=logout’;

需要自己写一个login.php的登录入口。
<?php
session_start();

if ($_GET['action'] == ‘logout’){
unset ($_SESSION['login_security']);
echo “<strong>Logout!</strong><br />”;
}
if ($_POST['username'] == “root” && $_POST['password']==”YOURPASSWORD”){
$_SESSION['login_security'] = $_POST['username'];
header(“Location:index.php”);
}
elseif (isset($_POST['username']))
echo “<strong>Wrong password!</strong><br />”;
?>
<form action=”login.php” method=”POST”>
Username:<input name=”username” /><br />
Password:<input name=”password” type=”password”/><br />
<input name=”login” type=”submit” value=”Login” />
<a href=”login.php?action=logout”>Logout</a>
</form>

消除广告比较简单,只要在index.php的16行注释掉就可以
// test if javascript enabled ##
//include “code/base/loader.php”;

项目需要,需要将自己开发的应用和discuz共享用户表并且同步登陆。
首先下载discuz7.2和ucenter1.6,安装完毕,discuz直接和ucenter绑定到一起了。
接下来是将自己的程序和ucenter进行整合了。
在ucenter中新建一个应用,得到一个key,写到config.inc.php里,除此之外还要api、uc_client目录等。
———————–login.php———————-

<?php
require_once(“config.inc.php”);
require_once(“uc_client/client.php”);
list($uid,$username) = explode(“\t”, uc_authcode($_COOKIE['xuanjianghui_login'], ‘DECODE’));
$avatar = UC_API.’avatar.php?uid=’.$uid.’&size=small’;
if ($uid >0 ) {
echo $uid.” | “.$username;
echo “<a href=’logout.php’>logout</a>”;
}
else{
?>
<form method=”post” action=”dologin.php”>
账号<input name=”username” id=”username”><br/>
密码<input name=”password” id=”password” type=”password”><br/>
<input name=”login” id=”login” type=”submit” value=”登陆”>
</form>
<?php }

——————————–dologin.php——————————

<?php  error_reporting(E_ALL);
require_once(“config.inc.php”);
require_once(“uc_client/client.php”);
list($uid, $username, $password, $email) = uc_user_login($_POST['username'], $_POST['password']);
$avatar = UC_API.’avatar.php?uid=’.$uid.’&size=small’;
$p = array(‘uid’=>$uid,’username’=>$username,’email’=>$email,’avatar’=>$avatar);
setcookie(‘xuanjianghui_login’, ”, -86400);
if($uid > 0) { echo “!”;
//用户登陆成功,设置 Cookie,加密直接用 uc_authcode 函数,用户使用自己的函数
setcookie(‘xuanjianghui_login’, uc_authcode($uid.”\t”.$username, ‘ENCODE’));
//生成同步登录的代码
$ucsynlogin = uc_user_synlogin($uid);
echo ‘登录成功’.$ucsynlogin.’<br><a href=”‘.$_SERVER['PHP_SELF'].’”>继续</a>’;
echo $ucsynlogin;
}

echo json_encode($p);
同步登陆需要执行一段JS,即ucsynlogin返回的东西。
之前一直得不到ucsynlogin返回的代码,就深入往下找,直到找到一段代码,是访问缓存,如果同步的站点大于一才同步,不知为何我的缓存从来没变过,我就把那个验证缓存内容的if语句注释掉了,结果就返回了同步登陆代码,果然bbs也随之登陆了,注销也是如此。

接下来是通信失败的问题了,经过分析代码,发现检查通信是一个向、api/uc.php发送ping的一个过程。
返回1表示成功,其他是失败,我的程序什么都没返回。检查发现禁止报错了,error_reporting(E_ALL)一下,发现include就出问题了,
原来是配置文件的一个路径出问题了,修改一下路径,就通信成功了。

因为项目整合需要,需要机器人代发帖,于是乎开发一个接口。
有发布帖子和发布留言的两个接口。
有两种方法可以实现这个功能,一个是模拟用户提交表单,第二个是直接写数据库。
第一种的优点是高层接口,不用考虑底层的数据库操作,可以防止注入,灌水等,缺点是表单验证太复杂,而且有防灌水设置。
第二种的优点是随心所欲,不用考虑账户权限、防灌水等问题,缺点是数据库操作过于复杂。
采用第二种方法,这就需要知道发布一篇帖子时,数据库进行了哪些操作。
利用phpmyadmin导出整个数据库操作前和操作后的sql,利用Notepad++进行Compare操作,得到一些diff,这样可以找到发帖时的数据库改动。
主要有
1.向thread里添加一条记录,记录了帖子的标题、作者、上次回复时间等内容。
2.向posts里添加一条记录,记录了帖子的内容等信息。
3.向favoritethreads添加一条记录。
4.更新forum的最新帖子。
5.更新member的最后发布时间。

回复的一些改动
1.向posts里添加一条记录,记录了回复的内容等信息。
2.更新thread的最后回复时间。
3.更新forum的最新帖子。
4.更新member的最后发布时间。

找到了这些就可以开工了。最后测试成功。

function insert_thread($uid, $author, $fid, $title, $content)
{
global $tablepre,$dbname;
database_connect($dbname);
$time = time();
$sql1 = “INSERT INTO `{$tablepre}threads` (`fid`, `iconid`, `typeid`, `sortid`, `readperm`, `price`, `author`, `authorid`, `subject`, `dateline`, `lastpost`, `lastposter`, `views`, `replies`, `displayorder`, `highlight`, `digest`, `rate`, `special`, `attachment`, `moderated`, `closed`, `itemid`, `supe_pushstatus`, `recommends`, `recommend_add`, `recommend_sub`, `heats`, `status`) VALUES ($fid, 0, 0, 0, 0, 0, ‘$author’, $uid, ‘$title’, $time, $time, ‘$author’, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);”;
database_query($sql1);
$newid = mysql_insert_id();

$sql2 = “INSERT INTO `{$tablepre}posts` (`fid`, `tid`, `first`, `author`, `authorid`, `subject`, `dateline`, `message`, `useip`, `invisible`, `anonymous`, `usesig`, `htmlon`, `bbcodeoff`, `smileyoff`, `parseurloff`, `attachment`, `rate`, `ratetimes`, `status`) VALUES ($fid, $newid, 1, ‘$author’, $uid, ‘$title’, $time, ‘$content’, ’127.0.0.1′, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0);”;
database_query($sql2);

$sql3 = “INSERT INTO `{$tablepre}favoritethreads` (`tid`, `uid`, `dateline`, `newreplies`) VALUES ($newid, $uid, $time, 0);”;
database_query($sql3);

$sql4 = “UPDATE `{$tablepre}forums` SET `posts` = `posts`+1 , `threads` = `threads`+1 , `todayposts` = `todayposts`+1 , `lastpost` = ‘$newid\t$title\t$time\t$author’ WHERE `fid` = $fid ;”;
database_query($sql4);

$sql5 = “UPDATE `{$tablepre}members` SET `lastpost` = $time , `posts` = `posts`+1 , `threads` = `threads`+1 , `lastpost` = $time WHERE `uid` = $uid ;”;
database_query($sql5);

return $newid;
}

function insert_post($uid, $author, $fid, $tid, $content, $ip)
{
global $tablepre,$dbname;
database_connect($dbname);
$time = time();
$sql1 = “INSERT INTO `{$tablepre}posts` (`fid`, `tid`, `first`, `author`, `authorid`, `subject`, `dateline`, `message`, `useip`, `invisible`, `anonymous`, `usesig`, `htmlon`, `bbcodeoff`, `smileyoff`, `parseurloff`, `attachment`, `rate`, `ratetimes`, `status`) VALUES( $fid, $tid, 0, ‘$author’, $uid, ”, $time, ‘$content’, $ip, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0);”;
database_query($sql1);
$newid = mysql_insert_id();

$sql2 = “UPDATE `{$tablepre}threads` SET `views` = `views`+1 , `replies` = `replies`+1 , `lastpost` = $time, `lastposter` = ‘$author’ WHERE `tid` = $tid ;”;
database_query($sql2);

$sql3 = “UPDATE `{$tablepre}forums` SET `posts` = `posts`+1 , `todayposts` = `todayposts`+1 , `lastpost` = ‘$tid $title $time $author’ WHERE `fid` = $fid ;”;
database_query($sql3);

$sql4 = “UPDATE `{$tablepre}members` SET `lastpost` = $time , `posts` = `posts`+1 , `lastpost` = $time WHERE `uid` = $uid ;”;
database_query($sql4);

return $newid;
}