Discuz!官方免费开源建站系统

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索

[已解决] 大数据论坛快速升级方案

[复制链接]
Luca. 发表于 2013-1-30 17:02:02 | 显示全部楼层 |阅读模式
本帖最后由 Luca. 于 2013-2-5 11:34 编辑

在的convert工具简单强大,但是对于超大型论坛的升级来说,还是有不少瓶颈的。
利用浏览器运行自然会受限于浏览器本身局限和脚本超时限制,对于拥有自己服务器的网站耗时长且服务器本身资源没有得到有效利用。
我们来探讨一下快速升级的方案,方案的前提是:拥有服务器权限

根据我们的经验,大型网站的大数据量主要涉及到两块:会员数据,帖子数据。
会员数据涉及的表包括UC中的members,pms表,论坛中的common_member,common_member_count,common_member_field_forum,common_member_field_home,common_member_profile,common_member_status等。
帖子数据主要涉及到thread,post,attachment表。
如果我们能加快转换这些表,那么整个升级速度就快了。
下面根据我们小组的以往大论坛转换经验,提供一种快速升级思路和方法示例。

升级的时候明确几点:
1,源数据库停止写操作。
2,在保证1的条件下,源数据库所有的表都是独立的,不用考虑相关联的表的数据对应关系(特殊情况除外,下面会说明)。当一个表出现问题时,只单独重新处理这个表。
3,UC的版本变更上,数据库变动不大,主要是1.5到1.6的pms表变动,以及无UC版本到UC的变更。
4,在DISCUZ的个版本变迁上,各字段含义及格式变化不大,主要是存在与否的差别。有少量需要计算的部分。

基于上面几点,我们可以得出如下结论:
1,对于大部分表,我们可以直接在数据库通过SQL语句进行复制。
2,大多表相互独立,操作出现问题后清空目标表,重新转就行。
3,对于需要计算或者过于复杂的数据处理,可以使用服务器直接跑脚本来避免convert工具的JS跳转的耗时。
4,对于剩下的一些需要计算的且数据量小的表,直接使用convert工具进行升级。

所以大致升级思路如下:
1,按照常规方法准备,在运行convert的时候,只勾选数据量小的表进行转换。
2,大表直接使用INSERT INTO …… SELECT FROM……语句进行复制。
3,需要计算的,比如某些版本member的转换,使用脚本,在服务器使用php命令运行。
4,检查数据,转移附件等。

下面是一些常用的升级语句示例,可以按需选取。

1,非UC转UC的member表,例子是6.0转UC。
  1. TRUNCATE
  2. cdb_uc_members;
  3. REPLACE
  4. INTO `cdb_uc_members`(`uid`, `username`,
  5. `password`,`secques`,`email`,`regip`,`regdate`) (SELECT `uid`, `username`,
  6. `password`,`secques`,`email`,`regip`,`regdate` FROM cdb_members);
  7. UPDATE
  8. cdb_uc_members SET salt = right(md5(rand()),6);  //生成随机6位数
  9. UPDATE
  10. cdb_uc_members SET password = md5(concat(password,salt)); //生成符合UC的密码加密
复制代码
2,短信部分,6.0转UC(<=1.5.2)
  1. TRUNCATE cdb_uc_pms;
  2. REPLACE INTO `cdb_uc_pms` (`pmid`, `msgfrom`, `msgfromid`, `msgtoid`, `folder`, `new`, `subject`, `dateline`, `message`, `delstatus`) (SELECT `pmid`, `msgfrom`, `msgfromid`, `msgtoid`, `folder`, `new`, `subject`, `dateline`, `message`, `delstatus` FROM cdb_pms)
复制代码
3,帖子表,6.0转X2,后面的分表数字自行修改。
  1. insert into x2.pre_forum_post (pid,fid,tid,first,author,authorid,subject,dateline,message,useip,invisible,anonymous,usesig,htmlon,bbcodeoff,smileyoff,parseurloff,attachment,rate,ratetimes,status) (select pid,fid,tid,first,author,authorid,subject,dateline,message,useip,invisible,anonymous,usesig,htmlon,bbcodeoff,smileyoff,parseurloff,attachment,rate,ratetimes,status from oldbbs.cdb_posts_1);
复制代码
  1. insert into pre_forum_post_tableid (select max(pid) from pre_forum_post);
  2. alter table pre_forum_pollvoter drop index(tid_2);
复制代码
4,主题表,6.0转X2。
  1. INSERT INTO x2.pre_forum_thread (tid,fid,typeid,sortid,readperm,price,author,authorid,subject,dateline,lastpost,lastposter,views,replies,displayorder,highlight,digest,rate,special,attachment,moderated,closed,recommends,recommend_add,recommend_sub,heats,status) (SELECT tid,fid,typeid,sortid,readperm,price,author,authorid,subject,dateline,lastpost,lastposter,views,replies,displayorder,highlight,digest,rate,special,attachment,moderated,closed,recommends,recommend_add,recommend_sub,heats,status FROM oldbbs.cdb_threads);
复制代码
5,附件表,6.0转X2。
  1. TRUNCATE pre_forum_attachment;
  2. TRUNCATE pre_forum_threadimage;
  3. TRUNCATE pre_forum_attachment_0;
  4. TRUNCATE pre_forum_attachment_1;
  5. TRUNCATE pre_forum_attachment_2;
  6. TRUNCATE pre_forum_attachment_3;
  7. TRUNCATE pre_forum_attachment_4;
  8. TRUNCATE pre_forum_attachment_5;
  9. TRUNCATE pre_forum_attachment_6;
  10. TRUNCATE pre_forum_attachment_7;
  11. TRUNCATE pre_forum_attachment_8;
  12. TRUNCATE pre_forum_attachment_9;
  13. INSERT INTO pre_forum_attachment (aid,tid,pid,uid,downloads)(SELECT aid,tid,pid,uid,downloads FROM oldbbs.cdb_attachments);
  14. UPDATE pre_forum_attachment SET tableid='0' where tid % 10 = 0;
  15. UPDATE pre_forum_attachment SET tableid='1' where tid % 10 = 1;
  16. UPDATE pre_forum_attachment SET tableid='2' where tid % 10 = 2;
  17. UPDATE pre_forum_attachment SET tableid='3' where tid % 10 = 3;
  18. UPDATE pre_forum_attachment SET tableid='4' where tid % 10 = 4;
  19. UPDATE pre_forum_attachment SET tableid='5' where tid % 10 = 5;
  20. UPDATE pre_forum_attachment SET tableid='6' where tid % 10 = 6;
  21. UPDATE pre_forum_attachment SET tableid='7' where tid % 10 = 7;
  22. UPDATE pre_forum_attachment SET tableid='8' where tid % 10 = 8;
  23. UPDATE pre_forum_attachment SET tableid='9' where tid % 10 = 9;
  24. INSERT INTO pre_forum_attachment_0 (aid,tid,pid,uid,dateline,filename,filesize,attachment,remote,readperm,price,isimage,width,thumb)(SELECT a.aid,a.tid,a.pid,a.uid,a.dateline,a.filename,a.filesize,a.attachment,a.remote,a.readperm,a.price,a.isimage,a.width,a.thumb FROM oldbbs.cdb_attachments a WHERE  a.tid % 10 = 0);
  25. INSERT INTO pre_forum_attachment_1 (aid,tid,pid,uid,dateline,filename,filesize,attachment,remote,readperm,price,isimage,width,thumb)(SELECT a.aid,a.tid,a.pid,a.uid,a.dateline,a.filename,a.filesize,a.attachment,a.remote,a.readperm,a.price,a.isimage,a.width,a.thumb FROM oldbbs.cdb_attachments a WHERE  a.tid % 10 = 1);
  26. INSERT INTO pre_forum_attachment_2 (aid,tid,pid,uid,dateline,filename,filesize,attachment,remote,readperm,price,isimage,width,thumb)(SELECT a.aid,a.tid,a.pid,a.uid,a.dateline,a.filename,a.filesize,a.attachment,a.remote,a.readperm,a.price,a.isimage,a.width,a.thumb FROM oldbbs.cdb_attachments a WHERE  a.tid % 10 = 2);
  27. INSERT INTO pre_forum_attachment_3 (aid,tid,pid,uid,dateline,filename,filesize,attachment,remote,readperm,price,isimage,width,thumb)(SELECT a.aid,a.tid,a.pid,a.uid,a.dateline,a.filename,a.filesize,a.attachment,a.remote,a.readperm,a.price,a.isimage,a.width,a.thumb FROM oldbbs.cdb_attachments a WHERE  a.tid % 10 = 3);
  28. INSERT INTO pre_forum_attachment_4 (aid,tid,pid,uid,dateline,filename,filesize,attachment,remote,readperm,price,isimage,width,thumb)(SELECT a.aid,a.tid,a.pid,a.uid,a.dateline,a.filename,a.filesize,a.attachment,a.remote,a.readperm,a.price,a.isimage,a.width,a.thumb FROM oldbbs.cdb_attachments a WHERE  a.tid % 10 = 4);
  29. INSERT INTO pre_forum_attachment_5 (aid,tid,pid,uid,dateline,filename,filesize,attachment,remote,readperm,price,isimage,width,thumb)(SELECT a.aid,a.tid,a.pid,a.uid,a.dateline,a.filename,a.filesize,a.attachment,a.remote,a.readperm,a.price,a.isimage,a.width,a.thumb FROM oldbbs.cdb_attachments a WHERE  a.tid % 10 = 5);
  30. INSERT INTO pre_forum_attachment_6 (aid,tid,pid,uid,dateline,filename,filesize,attachment,remote,readperm,price,isimage,width,thumb)(SELECT a.aid,a.tid,a.pid,a.uid,a.dateline,a.filename,a.filesize,a.attachment,a.remote,a.readperm,a.price,a.isimage,a.width,a.thumb FROM oldbbs.cdb_attachments a WHERE  a.tid % 10 = 6);
  31. INSERT INTO pre_forum_attachment_7 (aid,tid,pid,uid,dateline,filename,filesize,attachment,remote,readperm,price,isimage,width,thumb)(SELECT a.aid,a.tid,a.pid,a.uid,a.dateline,a.filename,a.filesize,a.attachment,a.remote,a.readperm,a.price,a.isimage,a.width,a.thumb FROM oldbbs.cdb_attachments a WHERE  a.tid % 10 = 7);
  32. INSERT INTO pre_forum_attachment_8 (aid,tid,pid,uid,dateline,filename,filesize,attachment,remote,readperm,price,isimage,width,thumb)(SELECT a.aid,a.tid,a.pid,a.uid,a.dateline,a.filename,a.filesize,a.attachment,a.remote,a.readperm,a.price,a.isimage,a.width,a.thumb FROM oldbbs.cdb_attachments a WHERE  a.tid % 10 = 8);
  33. INSERT INTO pre_forum_attachment_9 (aid,tid,pid,uid,dateline,filename,filesize,attachment,remote,readperm,price,isimage,width,thumb)(SELECT a.aid,a.tid,a.pid,a.uid,a.dateline,a.filename,a.filesize,a.attachment,a.remote,a.readperm,a.price,a.isimage,a.width,a.thumb FROM oldbbs.cdb_attachments a WHERE  a.tid % 10 = 9);
  34. (可以不做,数据调用附件图片的模块才用到)
复制代码
6,论坛会员表部分。
由于会员表涉及到一些运算,所以我们考虑使用脚本来处理,使用php命令执行脚本来避免超时。
用法 php [-q] [-h] [-s] [-v] [-i] [-f ] | { [args...]}

  -q 安静模式。不输出HTTP头。
  -s 将php程序文件用转化为彩色格式的HTML(比如保留字用绿色,函数和变量为蓝色,注释为黄色而字串则是红色等等。
  -f 读入并解释指明的文件。
  -c在中读入php.ini文件
  -a 交互式运行
  -d foo[=bar] 定义ini中的输入项 foo 的值为 bar
  -e 输出额外信息以便调试和性能分析
  -z 调入Zend扩展文件
  -i php的相关信息
  -h help本身。

$php -q 文件名.php

我们可以改造convert工具table文件夹里的脚本,改成可以使用php命令的。
改造方法如下:
1,由于convert都是通过index.php入口来引用table文件并已包含函数库和数据库初始化,而这儿只能运行脚本的绝对地址,所以头部都加入如下代码:
  1. require '../../../include/common.inc.php';
  2. $config = loadconfig();
  3. $db_source = new db_mysql($config['source']);
  4. $db_source->connect();

  5. $db_target = new db_mysql($config['target']);
  6. $db_target->connect();
复制代码
2,脚本单独运行,忽略$nextid,$start值,去掉limit限制,一次性执行完。
3,为了能在运行中事实监测到程序运行情况,可以在循环内即时输出处理行数据:
  1. echo $i . "\n";
复制代码
4,有些脚本要执行很长时间,为了防止session中断,要使用screen命令:
说明:
screen为多重视窗管理程序。此处所谓的视窗,是指一个全屏幕的文字模式画面。通常只有在使用telnet登入主机或是使用老式的终端机时,才有可能用到screen程序。

我们在screen下来执行php命令,如果当前的窗口中断了,就可以使用screen -ls来查看当前所有的session。
5,只使用一个窗口速度还是很慢,为了让速度加速,更有效地利用服务器资源,我们可以把脚本变成很多个,每个处理一定数量比如50W条,这样就可以有效提高效率。
首先统计用户数,如果有1KW用户,同时开10个窗口,那么则每个脚本处理100W。
在脚本中设置$start,比如0,1000000,2000000
在循环顶部加入截止数据语句:
  1. if ($row['uid'] >2000000) exit;
复制代码
关于这个脚本我们给了一个附件,是从6.0转X2的脚本,大家可以下载研究。
6,在处理用户之前首先去掉用户表的索引,否则每条数据插入都会修改索引影响速度:
  1. alter table pre_common_member change uid uid INT(11) unsigned NOT NULL, drop primary key,drop index username, drop index email ,drop index groupid, drop index conisbind;
复制代码
在脚本执行完毕后,再加入索引:
  1. alter table pre_common_member change uid uid INT(11) unsigned NOT NULL auto_increment,add primary key(uid),add unique index(username),add index(email),add index(groupid),add index(conisbind);
复制代码
12153556 发表于 2013-1-30 19:10:32 | 显示全部楼层
牛~!不过很少有超级论坛的吧?纯技术的!老大,支持你~!有机会了试试!
回复

使用道具 举报

baxter 发表于 2013-1-31 12:47:18 | 显示全部楼层
支持一下,现在千万级别的论坛也不少,有机会了试下这个
回复

使用道具 举报

vinsonwang 发表于 2013-2-5 11:01:17 | 显示全部楼层
权限放开了,顶一下
回复

使用道具 举报

 楼主| Luca. 发表于 2013-2-5 11:33:37 | 显示全部楼层
vinsonwang 发表于 2013-2-5 11:01
权限放开了,顶一下


其实要弄成脚本,这样估计还是没人看
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|Discuz! 官方站 ( 皖ICP备16010102号 )star

GMT+8, 2024-11-23 06:46 , Processed in 0.025396 second(s), 3 queries , Gzip On, Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表