因为一些内容审查方面的原因,一个运行了很久的论坛被要求限期迁移出现有机房。管制很严,要求在1-2天内完成。论坛的文件(主要是图片及附件)100多G,数据库有80G。我评估了一下,导出数据,部署新环境,导入数据,调试到能正常访问,1-2天可能有点紧张,万一迁移不顺利,还得花费更多的时间。但没办法拒绝,先答应下来再说。
跟其它技术人员讨论了一下,先临时采取投机取巧方式,应付检查,其措施如下:
1、在其它不受内容审核的地区,部署一个代理,用nginx就行。
2、修改现论坛web的监听端口(由80改成8989),暂时先不改,配好nginx反向代理以后,绑定本地hosts,域名指向新部署服务器的ip地址,访问确认没问题,再修改到8989端口。同时代理nginx转发端口也对应改成8989。
3、修改dns,把域名解析到代理web服务器的ip。
这样处理,避开了审查,为迁移赢得了时间。
安排异地机房的技术给我们部署系统,因为经验以及其它方面的原因,花了将近一天的时间才交付过来(幸亏采取了前边的临时措施)。为了加快进度,我们自己做了分工,一人负责新系统部署php、nginx和mysql运行环境,而我负责导出数据。导出数据分两部分:论坛数据本身压缩打包、数据库数据导出再压缩打包。
开始,我习惯性的用mysqldump --all-databases 全库导出,过程很顺利,导出后打包再复制到别的地方,大概2个小时。新系统那边,环境已经部署好了,我试着进行导入,进行了几十分钟,报错,因为中文字符的问题,尝试了几种方式,还是一样,只得放弃。重新回源服务器,换成innobackup导出。悲催的是,这个服务器的系统太老了,为centos 5.8,安装xtrabackup有依赖问题,需要使用yum来处理一些依赖,但系统自带的yum源没有了,只好重新构造了一个Centos-Base.repo,其内容如下:
[base] name=CentOS-$releasever - Base #mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os #baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/ baseurl=http://vault.centos.org/5.11/os/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5 #released updates [updates] name=CentOS-$releasever - Updates #mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates #baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/ baseurl=http://vault.centos.org/5.11/updates/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5 #additional packages that may be useful [extras] name=CentOS-$releasever - Extras #mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras #baseurl=http://mirror.centos.org/centos/$releasever/extras/$basearch/ baseurl=http://vault.centos.org/5.11/extras/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5 #additional packages that extend functionality of existing packages [centosplus] name=CentOS-$releasever - Plus #mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus #baseurl=http://mirror.centos.org/centos/$releasever/centosplus/$basearch/ baseurl=http://vault.centos.org/5.11/centosplus/$basearch/ gpgcheck=1 enabled=0 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5 #contrib - packages by Centos Users [contrib] name=CentOS-$releasever - Contrib #mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=contrib #baseurl=http://mirror.centos.org/centos/$releasever/contrib/$basearch/ baseurl=http://vault.centos.org/5.11/contrib/$basearch/ gpgcheck=1 enabled=0 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5 |
再测试 yum install lrzsz 正常。
从网上下载备份的安装包percona-xtrabackup-2.3.10.tar.gz,用yum 安装libaio-devel、gcc,vim-comm等几个依赖包。另外,在编译该软件是,会提示cmake的版本过低,需要替换一下。
下载cmake-3.9.6.tar.gz,tar开以后,执行 ./configure --prefix=/usr/local/cmake ;make ;make install 把新版本限定到目录/usr/local/cmake,这样就不用处理旧版本,也不会与其产生冲突。编译安装时,带上cmake的全路径:
/usr/local/cmake/bin/cmake -DBUILD_CONFIG=xtrabackup_release && make -j4 |
如果出现“CMake Error at cmake/libev.cmake:23 (MESSAGE)”报错信息,手动安装包libev-3.7.tar.gz(yum不到的),步骤为:
tar zxvf libev-3.7.tar.gz cd libev-3.7 ./configure make;make install |
这个不需要指定安装路径,方便cmake执行的时候找得到。
费了好大一通时间,才把这个备份软件安装好,虽然描述得有些啰嗦,但可能对其它人排错会有帮助。
现在,开始切入正题.
执行备份
1、确保源数据库处于启动状态
2、执行指令
innobackupex --user=root --password=MaGiCdB1 --defaults-file=/etc/my.cnf /data1/dumpdir
备份目录是任意足够大的分区
3、检查备份目录,是否产生数据
4、执行 innobackupex --apply-log /data1/dumpdir/2018-03-30_11-10-53
压缩和传输文件(论坛数据文件与此步骤相同,不再说明)
tar czvf 2018-03-30_11-10-53.tgz 2018-03-30_11-10-53 rsync -avz -e "ssh -p 2222 " 2018-03-30_11-10-53.tgz 120.189.55.109:/data1/ |
特别值得注意的是,由于数据量比较大,避免shell中断导致任务终止,尽量在screen下进行操作,就算shell退出,也不会受到影响。
到此为止,源服务器的操作暂告一段落。
数据量相对来说比较大,因此传输过程花了好长一段时间。在这同时,在目的服务器,把安装好的环境配置成与源站基本一致(操作系统版本、php、ngnix、mysql做了升级):相同的目录结构、相同的内网ip、相同的用户帐号。这样就可以直接把源站nginx配置、mysql配置、php原样同步过来。目前因为没有数据库数据导入及论坛文件,我先试着在nginx配置的站点根文档写一个php测试脚本test.php,内容为:<? phpinfo(); ?>.把nginx及php服务都启动起来,浏览器访问该url,检查一下php都有哪些模块被加载,与源站是不是差不多的情形。测试完记得删掉它,这个是安全隐患哟!
nginx的主配置文件nginx.conf如下(节录):
user www www; worker_processes 8; #dso { # load ngx_http_cache_purge_module.so; #} worker_rlimit_nofile 51200; events { use epoll; #use kqueue; #FreeBSD system worker_connections 51200; } http { include mime.types; ....................此处省略............................. map $request_method $limit { default ""; POST $binary_remote_addr; } limit_conn_zone $binary_remote_addr zone=one_limit:10m; limit_req_zone $limit zone=zone_limit_post:10m rate=10r/m; log_format post '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$host $request_time $proxy_add_x_forwarded_for $request_body'; access_log /data/logs/http.a.log; error_log /data/logs/http.e.log; #include vhosts/test.conf; include vhosts/default.conf; include vhosts/bbs.formyz.net.conf; include vhosts/file.formyz.net.conf; } |
某个站点的配置文件 bbs.formyz.net.conf
server { listen 80; server_name bbs.formyz.net; error_page 404 http://bbs.formyz.net;
access_log /data/logs/bbs.formyz.net-access; error_log /data/logs/bbs.formyz.net-error; limit_conn one_limit 5;
root /data/html/bbs.formyz.net; index index.html index.htm forum.php index.php; if ($host != 'bbs.formyz.net' ) { rewrite ^/(.*)$ http://bbs.formyz.net/$1 permanent; } if (-d $request_filename) { rewrite ^/(.*)([^/])$ http://$host:$server_port/$1$2/ permanent; } location ^~ /config { deny all; } location ^~ /.git { deny all; } location ~ /(data|static|template|images|uc_server/data)/.*\.(php|php5|html)?$ { deny all; location ~ .*\.(php|php5)$ { limit_req zone=zone_limit_post burst=5; if ($request_method = "POST") { access_log /data/logs/bbs.formyz.net-post post; } root /data/html/bbs.formyz.net; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi_params; } location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { expires 30d; } location ~ .*\.(js|css)?$ { expires 1h; } location / { limit_conn one_limit 5; rewrite ^(.*)/topic-(.+)\.html$ $1/portal.php?mod=topic&topic=$2 last; rewrite ^(.*)/article-([0-9]+)\.html$ $1/portal.php?mod=article&articleid=$2 last; rewrite ^(.*)/forum-(\w+)-([0-9]+)\.html$ $1/forum.php?mod=forum display&fid=$2&page=$3 last; rewrite ^(.*)/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ $1/forum.php?mod=viewthread&tid=$2&extra=page%3D$4&page=$3 last; rewrite ^(.*)/group-([0-9]+)-([0-9]+)\.html$ $1/forum.php?mod=group&fid=$2&page=$3 last; rewrite ^(.*)/space-(username|uid)-(.+)\.html$ $1/home.php?mod=space&$2=$3 last; rewrite ^(.*)/([a-z]+)-(.+)\.html$ $1/$2.php?rewrite=$3 last; break; } } |
这里是每一个站点,用一行include 显示的包含。偏偏有不少人,至少我碰到不少,喜欢用 include *.conf把所有的站点都包含进去,我不太赞同这种做法,配置的时候你是方便了,可是到了要维护的时候,就不是那么方便了。为什么这样说?假设现在做维护,我打开nginx.conf大概就可以看到有哪些站点(当然文件命名也要规划好,能望文生义);特别是在一个nginx下站点多的场景,对某个站点进行临时维护,只要在主配置文件nginx.conf注释掉与它关联的include行,重载nginx即可。
接下来给出php-fpm.conf文件的部分内容:
[global] error_log = log/php-fpm.log process.max = 5000 rlimit_files = 10240 [www] user = www group = www listen = 127.0.0.1:9000 pm = dynamic pm.max_children = 5000 pm.start_servers = 50 pm.min_spare_servers = 20 pm.max_spare_servers = 80 pm.max_requests = 5000 access.log = log/php.access.log slowlog = log/php.log.slow request_slowlog_timeout = 3 |
与nginx相对应,php也以普通用户www来运行,同时所有站点目录,都授权属主、属组为www,保证正确与合理的权限。一些经验不足的人,不注意程序权限与目录权限的对应关系,运行服务,只要提示权限不够,就立马执行 chmod -R 777 dir ,你这是在方便别人进入系统呢!另外,php开启了慢查询日志,在运行中排错或者排查性能问题会很有帮助,不过我自己不懂php,一般都是让开发人员自己看这个日志了,他懂的。
把论坛源站复制来的数据文件,tar解包后,放置在nginx指定的目录,然后用chown -R www:www /data/html 及chmod -R 755 赋权,这个过程比较容易完成,不再赘述。
前边用mysqldump出来的文件,导入失败,这次换成innobackup,根据以往的经验,不应该有问题。注意,用此工具导入时,mysql不要初始化,也不要启动(这个是废话了,没初始化当然不能启动)。为方便大家了解全过程,顺便把mysql的选项文件my.cnf(不叫配置文件哟)贴出来,供大家参考:
[client] port=3306 socket=/tmp/mysql.sock [mysqld] character-set-server=utf8 collation-server=utf8_general_ci skip-external-locking skip-name-resolve user=mysql port=3306 datadir=/data/mysql_db open_files_limit=10240 back_log=600 max_connections=500 max_connect_errors=6000 wait_timeout=605800 #open_tables=600 #table_cache = 650 #opened_tables = 630 max_allowed_packet=32M sort_buffer_size=4M join_buffer_size=4M thread_cache_size=300 query_cache_type=1 query_cache_size=256M query_cache_limit=2M query_cache_min_res_unit=16k tmp_table_size=256M max_heap_table_size=256M key_buffer_size=256M read_buffer_size=1M read_rnd_buffer_size=16M bulk_insert_buffer_size=64M lower_case_table_names=1 default-storage-engine=INNODB innodb_buffer_pool_size=2G innodb_log_buffer_size=32M innodb_log_file_size=128M innodb_flush_method=O_DIRECT thread_concurrency=32 long_query_time=2 slow-query-log=on slow-query-log-file=/data/mysql_db/mysql-slow.log [mysqldump] quick max_allowed_packet=32M |
按my.cnf指定的"datadir=/data/mysql_db",创建好目录/data/mysql_db,并执行chown -R mysql:mysql /data/mysql 授权。这时,/data/mysql_db目录是空的。如果担心出错,坐好姿势,深呼吸,庄重地敲入screen,然后再执行如下命令行(2018-03-30_11-10-53为源数据库文件解包后的目录):
innobackupex --defaults-file=/etc/my.cnf --copy-back /data/2018-03-30_11-10-53 |
这个过程同样比较耗时,没事的话,可以另外再开一个终端,进入目录/data/mysql_db,可以看到不断有目录和文件自动生成。执行完毕且没有报错,基本上就大功告成了。由于安全的原因,mysql对连接帐户有访问限制,迁移到新系统以后,也一样要遵循这个规则。前边已经启动了nginx 和php服务,这里把mysql服务也启动起来。在个人的电脑,绑定windows的hosts文件,把域名与服务器的ip地址临时关联起来,再在浏览器输入域名,提示网页无法访问。已经检查php等配置正确,那么问题就在连接数据库这个上边了。进入论坛根文档(nginx.conf里边root指定的那个),查看连数据库相关的脚本,有好几个呢,其中一个 config_global.php 部分内容为:
.............部分省略.................... $_config = array(); // ---------------------------- CONFIG DB ---------------------------- - // $_config['db']['1']['dbhost'] = '172.16.28.94'; $_config['db']['1']['dbuser'] = 'bbs_formyz_net'; $_config['db']['1']['dbpw'] = '5O333EvbY'; $_config['db']['1']['dbcharset'] = 'gbk'; $_config['db']['1']['pconnect'] = '0'; $_config['db']['1']['dbname'] = 'bbs_formyz_net'; $_config['db']['1']['tablepre'] = 'pre_'; $_config['db']['common']['slave_except_table'] = ''; $_config['db']['slave'] = ''; ..................................余下省略........................ |
要解决问题,有两个办法:
(1)跟程序员协作,重新对每一个帐号授权(grant all ...);
(2)在系统上再配置一个 172.16.28.94的ip地址。
搞几天时间了,大家都很累,因此为了省事,我自己做主,在系统的另一个空闲网卡配置了上述私有ip地址。陪完重启网络服务,论坛可以打开,可以登录了。
经过多人多测测试,确认没问题以后,正式做域名解析到新的服务器ip。
还有些工作需要继续完善,包括同步这几天的新数据、开启新的数据备份等。论坛数据用rysnc -e 'ssh -p 20002' -avz src dist同步;数据库稍微麻烦一点,需要临时把论坛停一会,启用主从同步功能。由于源站用innobackup导出数据时,已经记录了主从同步需要的信息(xtrabackup_info),因此同步过程就不需要再执行费时的导出操作,只需按偏移量执行同步就行。
more xtrabackup_info uuid = 188600e0-33cc-11e8-986b-90b11c180978 name = tool_name = innobackupex tool_command = --defaults-file=/etc/my.cnf --user=root --password=... /data/databk/db_back tool_version = 2.3.10 ibbackup_version = 2.3.10 server_version = 5.5.29-log start_time = 2018-03-30 11:10:53 end_time = 2018-03-30 11:40:31 lock_time = 0 binlog_pos = filename 'mysql-bin.001258', position '571444300' innodb_from_lsn = 0 innodb_to_lsn = 79320170996 partial = N incremental = N format = file compact = N compressed = N encrypted = N |
数据库主从同步完成以后,把slave提升为主。似乎写得太长了,数据库备份部分,就不再写了。