利用redis的list队列解决类似微博中msgbox表的性能问题
2012-12-11 14:26
537 查看
在常见的类似微博的社交应用中,用户发布一条新微博的时候需要把该微博信息写入follow他的用户的msgbox中。在用户活跃高峰期的时候,msgbox变成读写都很频繁的表(看微博的用户需要查询这个表的内容,写微博的用户同时需要往这个表写东西),同时这个表往往又是数据条数大表,在mysql中就很容易长时间锁表。我们采用redis来解决这个问题,redis主要两个功能:1)存储每个user最新的300条msgbox信息 2)作为队列存储待写入msgbox的msg列表
1.从msgbox中抽取对每个user抽取最新300条msgbox存在redis的sorted set中
利用phpredis的pipe批量写入
while (
$row = mysql_fetch_assoc ( $rs1 ) ) {
$score = convertStrToMillSecTime($row ['time']);
$userID = $row ['userID'];
$msgID = $row ['msgID'] ;
$pipe->zadd ( "ss-msgbox-$userID", $score, "$msgID,0" );
$pipe->zremrangebyrank ( "ss-msgbox-$userID", 0, -301 );
$sqlCount ++;
$totalcount ++;
if ($sqlCount >= 5000) {//5000条写入一次
$pipe->execute();
$sqlCount = 0;
$pipe = $redis->pipeline();
echo "current userID: $userID \n";
}
}
2.发微博的时候把微博写入微博表( msg)同时写入用户自己的msgbox,然后写入到redis的list,随后就返回前台。这样好处时发微博的人觉得很快,同时又能看到自己发的微博
写redis的list代码:
$obj = array
();
$obj ["senderID"] = $senderID;
$obj ["senderName"] = $senderName;
$obj ["content"] = $content;
$obj ["msgType"] = $msgType;
$obj ["attachment"] = $attachment;
$obj ["usericon"] = $usericon;
$obj ["resultMsgID"] = $resultMsgID;
$obj ["video"] = $video;
$obj ["notice"] = $notice;
$json_str = json_encode ( $obj );
$rs = $redis->lpush (
"msgbox-list", $json_str );
3.后台有个轮询的php程序来负责读取redis的list队列,然后解析后同时往mysql的msgbox和redis的sorted set中插入数据
轮询php代码:
while ( true ) {//循环
try
{
$str = $redis->brpop ( REDIS_MSGBOX_LIST, 20 );//block读,减小服务器负担
if ($str ==NULL) {
continue;
}
if (! mysql_ping ( $db )) {
mysql_close ( $db );
$db = mysql_connect ( DBHOST, DBUSER, DBPWD );
mysql_select_db ( DBNAME, $db );
}
if ($redis->ping () !="PONG") {//判断redis连接是否失效
// $redis->quit ();
$redis = new
Redis ();
$redis->connect ( REDIS_DB_HOST, REDIS_PORT );
$redis->auth ( REDIS_DB_PWD );
$redis->select ( REDIS_DB_NAME );
}
$obj = json_decode ( $str [1] );
_write_OtherInfo_exec($obj->senderID, $obj->senderName, $obj->content, $obj->msgType,
$obj->attachment, $obj->usericon, $obj->resultMsgID, $obj->video, $obj->notice);//写如msgbox表
} catch ( Exception $err ) {
$fp = fopen ( $log_file_path,
"w" );
fwrite ( $fp, getShanghaiCurrentTime () .
":" . $err->getMessage () );
flush ();
fclose ( $fp );
echo $err;
}
}
4.用户查询微博时,前300台直接从redis读id列表,然后从微博表读具体内容,超过300条再从msgbox表读取。
1.从msgbox中抽取对每个user抽取最新300条msgbox存在redis的sorted set中
利用phpredis的pipe批量写入
while (
$row = mysql_fetch_assoc ( $rs1 ) ) {
$score = convertStrToMillSecTime($row ['time']);
$userID = $row ['userID'];
$msgID = $row ['msgID'] ;
$pipe->zadd ( "ss-msgbox-$userID", $score, "$msgID,0" );
$pipe->zremrangebyrank ( "ss-msgbox-$userID", 0, -301 );
$sqlCount ++;
$totalcount ++;
if ($sqlCount >= 5000) {//5000条写入一次
$pipe->execute();
$sqlCount = 0;
$pipe = $redis->pipeline();
echo "current userID: $userID \n";
}
}
2.发微博的时候把微博写入微博表( msg)同时写入用户自己的msgbox,然后写入到redis的list,随后就返回前台。这样好处时发微博的人觉得很快,同时又能看到自己发的微博
写redis的list代码:
$obj = array
();
$obj ["senderID"] = $senderID;
$obj ["senderName"] = $senderName;
$obj ["content"] = $content;
$obj ["msgType"] = $msgType;
$obj ["attachment"] = $attachment;
$obj ["usericon"] = $usericon;
$obj ["resultMsgID"] = $resultMsgID;
$obj ["video"] = $video;
$obj ["notice"] = $notice;
$json_str = json_encode ( $obj );
$rs = $redis->lpush (
"msgbox-list", $json_str );
3.后台有个轮询的php程序来负责读取redis的list队列,然后解析后同时往mysql的msgbox和redis的sorted set中插入数据
轮询php代码:
while ( true ) {//循环
try
{
$str = $redis->brpop ( REDIS_MSGBOX_LIST, 20 );//block读,减小服务器负担
if ($str ==NULL) {
continue;
}
if (! mysql_ping ( $db )) {
mysql_close ( $db );
$db = mysql_connect ( DBHOST, DBUSER, DBPWD );
mysql_select_db ( DBNAME, $db );
}
if ($redis->ping () !="PONG") {//判断redis连接是否失效
// $redis->quit ();
$redis = new
Redis ();
$redis->connect ( REDIS_DB_HOST, REDIS_PORT );
$redis->auth ( REDIS_DB_PWD );
$redis->select ( REDIS_DB_NAME );
}
$obj = json_decode ( $str [1] );
_write_OtherInfo_exec($obj->senderID, $obj->senderName, $obj->content, $obj->msgType,
$obj->attachment, $obj->usericon, $obj->resultMsgID, $obj->video, $obj->notice);//写如msgbox表
} catch ( Exception $err ) {
$fp = fopen ( $log_file_path,
"w" );
fwrite ( $fp, getShanghaiCurrentTime () .
":" . $err->getMessage () );
flush ();
fclose ( $fp );
echo $err;
}
}
4.用户查询微博时,前300台直接从redis读id列表,然后从微博表读具体内容,超过300条再从msgbox表读取。
相关文章推荐
- 利用tomcat-redis-session-manager解决tomcat的分布式session问题
- Redis 常见的性能问题和解决方法
- Redis命令之HGetAll性能问题解决方案
- 一次Redis 的性能测试和问题 [问题已经自己解决,见文章最后]
- 利用CodeDom来解决反射性能问题
- 利用List的Sort()、Find()、FindAll()、Exist()来解决一些问题
- 利用复合索引解决性能问题一例
- Redis性能问题排查解决手册
- Redis性能问题排查解决手册(七)
- Redis 常见的性能问题和解决方法
- Redis性能问题排查解决手册
- Redis性能问题排查解决手册
- Redis 常见的性能问题和解决方法
- spring-session,利用redis存储session,解决集群共享session的问题
- 有效利用索引和SQL构造,成功解决性能问题的经验
- Redis性能问题排查解决手册(七)
- Redis 常见的性能问题和解决方法
- Redis性能问题排查解决手册
- Redis 常见的性能问题和解决方法
- Redis性能问题排查解决手册