数据是怎么多出来的?
2012-05-15这段时间比较折磨,在做一个广告页面,该页面需要统计到各个联盟站点过来的IP数和注册、充值量。
最开始的做法,是在静态的广告页面里放入一段php的script,由该php去实现ip/pv的统计。
即:
ad.html中嵌入
<script src=”http://xxxxx/stat.php?id=xxxxxxxx”></script>
在stat.php页面中主要有以下业务逻辑:
1、取到广告id
2、判断该广告id在数据库中是否存在,如果不存在,则直接中止
3、判断ip在该广告id中是否出现过,如果没有出现过,则insert,然后update统计表,做+1操作
4、对pv统计表做insert(当天当时的记录不存在)或update(存在,做+1)操作
这里采用了前期统计,即,每进来一条数据,都会更新一下统计表,这样后台在查询时,就无需做count或group之类的查询了。
二天后,广告开始投放了,结果发现我们统计到的数据比网盟的数据要少,相差约在30%-40%左右,正常情况下应该是在10%以下,很明显,这里产生了数据的丢失。
经过分析,可能是stat.php在处理一个请求时,要经过5次db操作,在大并发时可能产生mysql排队,无法处理后续的数据请求,造成数据丢失;由于stat.php文件与最终的广告页面不在同一个域,会造成一次多余的http请求,而对stat.php的请求可能会产生失败,这里也存在数据丢失的可能性。
后来,想到一个方案,去掉stat.php文件,对外提供一个ad.php文件,直接在该文件做ip的统计,该文件只做insert,不做任何判断,后台的数据查看采用后期统计,虽然会慢一点,但是可以最大限度保证原始数据的正确性。
表stat存储引擎为MyISAM,没有任何索引。ad.php文件大致内容如下:
<?php
mysql_pconnect('localhost','user','passwd');
mysql_select_db('ad_analysis');
//insert量比较大,这里用了延迟写入
mysql_query('insert delayed into.......');
//方便loadrunner加检测点,这里直接输出了//ok
die('//ok');
//其它html代码
//为了对比,这里还加入了站长统计的代码
?>
用loadrunner开始2400个虚拟用户,每1秒钟增加5个用户,当达到2400用户时,连续压测1个小时。1小时后loadrunner通过的事务数与我在数据库中查到的完全一致,此时loadrunner的每秒处理量是1700-1800左右,从数据的对比看起来好像没有问题。
下午找了一个网盟做测试,10分钟后,网盟给的数据是1.15W个独立ip,站长统计得到的ip是12000左右,可我这边对ip字段做distinct后却发现是15000个ip……,pv也远远多于站长统计里的pv量,我。。凌乱了。。。
这多的数据是哪里来的?分析nginx的日志,nginx中ad.php的访问量也少于我数据库中的记录数,ip也少于数据库中的记录数……我无语了……
简单的一条insert,却造成3方数据不统一,这问题到底出在哪?我开始怀疑自己了。。。。
MongoDB中自增ID的实现
2011-06-17MongoDB自己采用的是ObjectId,因为是分布式存储,所以并没有用自增型的ID。
但有时我们却又需要这种类型的字段,如何去实现呢?
MongoDB中新建一个Collection,数据为
{“app”:collectionname,”UniqueId”:0}
app为collection名称,UniqueId为当前的最大ID,利用MongoDB的FindAndModify方法,实现对指定collection中的UniqueId的自增操作。
Int64 GenerateUniqueId(string CollectionName,int InitValue)
{
Connect();
CollectionName = CollectionName.Trim();
var collection = db.GetCollection("UniqueStore");
var query = Query.EQ("app", CollectionName);
var update = Update.Inc("id", 1);
var doc = collection.FindAndModify(query, SortBy.Null, update, true);
if (doc.ModifiedDocument == null)
{
collection.Save(new BsonDocument { { "app", CollectionName }, { "UniqueId", InitValue } });
return InitValue;
}
return Convert.ToInt64(doc.ModifiedDocument["UniqueId"]);
}
这里采用的MongoDB驱动是官方推荐的MongoDB-CSharp
apache2在win7 rtm下无法启动
2009-07-19昨天安装的win7 rtm 7600.16385,这个是win7 rtm的最终版本了,值得一试。
安装完成后,装上apache2与mysql均一切顺利,配置好httpd.conf,加载php5apache2模块后,启动apache失败,日志如下:
[Sun Jul 19 17:05:55 2009] [warn] pid file I:/win7_amp/Apache2/logs/httpd.pid overwritten — Unclean shutdown of previous Apache run?
[Sun Jul 19 17:06:00 2009] [warn] pid file I:/win7_amp/Apache2/logs/httpd.pid overwritten — Unclean shutdown of previous Apache run?
[Sun Jul 19 17:06:04 2009] [warn] pid file I:/win7_amp/Apache2/logs/httpd.pid overwritten — Unclean shutdown of previous Apache run?
[Sun Jul 19 19:00:56 2009] [warn] pid file I:/win7_amp/Apache2/logs/httpd.pid overwritten — Unclean shutdown of previous Apache run?
注释掉LoadModule php5_module I:/win7_amp/php/php5apache2_2.dll后就能顺利启动,看来是加载这个模块后出了问题。但是我未能找到解决办法,以后在win7 rc 7100中都能正常使用:(,不知道有没有朋友和我一样遇到此类问题。
google httpd.pid overwritten — Unclean shutdown of previous Apache run?后倒是有些发现,但大家都是删除httpd.pid这个文件后重启就OK了,win7下无效。
mp3插放器插件,需要的拿去用吧
2009-06-28模仿一个runcode插件改写的,wp的插件写起来还是比较简单的。
播放器是用豆瓣的,你要不喜欢可以换成别的,就需要自己改代码了。
调用方法【mp3】xxxxx【/mp3】,全角换成半角的就行了。
代码如下:
<?php
/*
Plugin Name: mp3player
Plugin URI: http://yibin.us/archives/6348
Description: mp3player in a post
Version: 1.0
Author: yibin
Author URI: http://yibin.us
*/
$player = new player();
add_filter('the_content', array(&$player, 'convert'), -500);
unset($player);
class player
{
function __builderplayer($url) {
if(empty($url)) return '';
return sprintf('<p><embed src="http://www.douban.com/swf/player.swf?url=%s&amp;autoplay=0" type="application/x-shockwave-flash" wmode="transparent" allowscriptaccess="always" width="400" height="80" /></p>',$url);
}
function convert($content)
{
$str_pattern = "/\[mp3\](.*?)\[\/mp3\]/i";
$content = preg_replace($str_pattern,$this->__builderplayer('\\1'),$content);
return $content;
}
}
?>
上传到wp的插件目录,然后在后台启用就行了
我承认我在DZ上有RPWT
2009-06-22操作cdb_sessions表,发现大量的locked,直接后果就是mysql无法响应WEB的请求,WEB无法响应浏览器端的请求。
太壮观:
+-------+------+-----------+--------+---------+------+--------+------------------------------------------------------------------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+-------+------+-----------+--------+---------+------+--------+------------------------------------------------------------------------------------------------------+
| 84082 | root | localhost | discuz | Query | 54 | update | INSERT INTO cdb_sessions (sid, ip1, ip2, ip3, ip4, uid, username, groupid, styleid, invisible, acti |
| 84083 | root | localhost | discuz | Query | 54 | Locked | DELETE FROM cdb_sessions WHERE sid='Z71z19' OR lastactivity<(1245657270-900) OR ('0'<>'0' AND uid=' |
| 84084 | root | localhost | discuz | Query | 54 | Locked | SELECT uid, username, groupid, invisible, action, lastactivity, fid FROM cdb_sessions WHERE uid <> 0 |
| 84086 | root | localhost | discuz | Query | 54 | Locked | SELECT uid, username, groupid, invisible, action, lastactivity, fid FROM cdb_sessions WHERE uid <> 0 |
| 84085 | root | localhost | discuz | Query | 54 | Locked | SELECT uid, username, groupid, invisible, action, lastactivity, fid FROM cdb_sessions WHERE uid <> 0 |
| 84087 | root | localhost | discuz | Query | 54 | Locked | SELECT uid, username, groupid, invisible, action, lastactivity, fid FROM cdb_sessions WHERE uid <> 0 |
| 84088 | root | localhost | discuz | Query | 54 | Locked | SELECT uid, username, groupid, invisible, action, lastactivity, fid FROM cdb_sessions WHERE uid <> 0 |
| 84089 | root | localhost | discuz | Query | 54 | Locked | SELECT uid, username, groupid, invisible, action, lastactivity, fid FROM cdb_sessions WHERE uid <> 0 |
| 84090 | root | localhost | discuz | Query | 54 | Locked | SELECT uid, username, groupid, invisible, action, lastactivity, fid FROM cdb_sessions WHERE uid <> 0 |
| 84091 | root | localhost | discuz | Query | 54 | Locked | SELECT uid, username, groupid, invisible, action, lastactivity, fid FROM cdb_sessions WHERE uid <> 0 |
| 84092 | root | localhost | discuz | Query | 54 | Locked | SELECT uid, username, groupid, invisible, action, lastactivity, fid FROM cdb_sessions WHERE uid <> 0 |
| 84093 | root | localhost | discuz | Query | 54 | Locked | DELETE FROM cdb_sessions WHERE sid='wsX92s' OR lastactivity<(1245657270-900) OR ('0'<>'0' AND uid=' |
| 84095 | root | localhost | discuz | Query | 54 | Locked | SELECT uid, username, groupid, invisible, action, lastactivity, fid FROM cdb_sessions WHERE uid <> 0 |
| 84096 | root | localhost | discuz | Query | 54 | Locked | DELETE FROM cdb_sessions WHERE sid='Ra5ZqL' OR lastactivity<(1245657270-900) OR ('0'<>'0' AND uid=' |
| 84094 | root | localhost | discuz | Query | 54 | Locked | SELECT uid, username, groupid, invisible, action, lastactivity, fid FROM cdb_sessions WHERE uid <> 0 |
| 84097 | root | localhost | discuz | Query | 54 | Locked | SELECT sid, uid AS sessionuid, groupid, groupid='6' AS ipbanned, pageviews AS spageviews, styleid, l |
| 84100 | root | localhost | discuz | Query | 54 | Locked | SELECT sid, uid AS sessionuid, groupid, groupid='6' AS ipbanned, pageviews AS spageviews, styleid, l |
| 84099 | root | localhost | discuz | Query | 54 | Locked | SELECT uid, username, groupid, invisible, action, lastactivity, fid FROM cdb_sessions WHERE uid <> 0 |
最为BT的是,这些locked形成之后,必须重启mysql才行
DZ7在windows下的表现
2009-06-19Discuz7的性能问题一直没能得到很好的解决,
具体表现为在linux+apache环境下,做压力测试时总是当机,要么是mysql show processlist出现众多locked,致使mysql当机;要么是apache不响应,直接当掉。
昨天配置到linux+nginx中,效果还是一样,囧得要命~~~
linux我不知道怎么玩,只能交由平台运维部门的同事全权处理,所以有关的配置也只是他们最清楚了。
无奈之下,昨天晚上对我机器上的discuz做了压测,结果在10个多小时的持续测试中,未出现一个错误,而且Hits/sec总是保持在650左右。

并发人数控制如下(出于我机器性能考虑,并发人数不大):
100人浏览首页、50人发帖、50人查看帖子列表,这样的压力持续10小时。
真正兼容.net的php 3DES加解密
2009-06-15php中3des加密的结果与.Net/java不同的帖子与话题实在是太多了,
我前不久也在倒腾这些,不过今天已经搞定了,完全与.net中的兼容
<?php
class Crypt3Des
{
private $key = "";
private $iv = "";
/**
* 构造,传递二个已经进行base64_encode的KEY与IV
*
* @param string $key
* @param string $iv
*/
function __construct ($key, $iv)
{
if (empty($key) || empty($iv)) {
echo 'key and iv is not valid';
exit();
}
$this->key = $key;
$this->iv = $iv;
}
/**
*加密
* @param <type> $value
* @return <type>
*/
public function encrypt ($value)
{
$td = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');
$iv = base64_decode($this->iv);
$value = $this->PaddingPKCS7($value);
$key = base64_decode($this->key);
mcrypt_generic_init($td, $key, $iv);
$ret = base64_encode(mcrypt_generic($td, $value));
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $ret;
}
/**
*解密
* @param <type> $value
* @return <type>
*/
public function decrypt ($value)
{
$td = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, '');
$iv = base64_decode($this->iv);
$key = base64_decode($this->key);
mcrypt_generic_init($td, $key, $iv);
$ret = trim(mdecrypt_generic($td, base64_decode($value)));
$ret = $this->UnPaddingPKCS7($ret);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $ret;
}
private function PaddingPKCS7 ($data)
{
$block_size = mcrypt_get_block_size('tripledes', 'cbc');
$padding_char = $block_size - (strlen($data) % $block_size);
$data .= str_repeat(chr($padding_char), $padding_char);
return $data;
}
private function UnPaddingPKCS7 ($text)
{
$pad = ord($text{strlen($text) - 1});
if ($pad > strlen($text)) {
return false;
}
if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) {
return false;
}
return substr($text, 0, - 1 * $pad);
}
}
?>
直接拿去用吧。
UCenter简析
2009-05-10UCenter是采用很经典的MVC架构

php.js
2009-05-04嗯,这个标题没有错。
以前有个同事写了个asp版的Cute ASP Framework,封装了一些很实用的函数。
后来我们谈到php中的一些内置函数,他也曾有过将其翻译成asp版的想法。
没想到,有人居然把php中内置的函数直接翻成了js。
如php中的strcmp,JS版的:
function strcmp ( str1, str2 ) {
// Binary safe string comparison
//
// version: 812.316
// discuss at: http://phpjs.org/functions/strcmp
// + original by: Waldo Malqui Silva
// + input by: Steve Hilder
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + revised by: gorthaur
// * example 1: strcmp( 'waldo', 'owald' );
// * returns 1: 1
// * example 2: strcmp( 'owald', 'waldo' );
// * returns 2: -1
return ( ( str1 == str2 ) ? 0 : ( ( str1 > str2 ) ? 1 : -1 ) );
}
看这里:
http://phpjs.org/functions/index
这个太NB了。
寻Apache2下Discuz高性能配置方案
2009-04-28服务器品牌 DELL
服务器型号 PE1850
cpu类型 Intel Xeon 2.80GHz
cpu个数 2
内存条类型 512M
内存条个数 2
硬盘类型1 36G
硬盘个数1 1
操作系统:Linux centos2 2.6.18-92.el5
Apache 2.0
PHP 5.2.9
目前300并发,持续时间1小时
测试截图:
下午进行LoadRunner测试,
100用户并发时,响应时间在1.5s左右。
400用户并发时,响应时间约为3s,但每秒连接数一直处于170左右,无法继续上升。
此时,web服务器CPU占用70%-80%
Db服务器为2%,基本无压力。
在网上看到一些文章,Apache在配置正确的情况下基本上可以处理每秒2K的并发请求,但今天的测试让我大跌眼镜。
响应时间也不够理想,况且这次的测试只是测了首页的访问,而且首页是做了缓存处理的。
最开始是怀疑httpd.conf中最大连接数没有设置正确,改动后重启Apache依然如此。
最令人担忧的是居高不下的CPU占用率。
希望有在Apache下配置Discuz经验的大虾们能给一个合理的配置方案。



