因为一些内容审查方面的原因,一个运行了很久的论坛被要求限期迁移出现有机房。管制很严,要求在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_infouuid = 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提升为主。似乎写得太长了,数据库备份部分,就不再写了。
如果不想看文字,猛戳此处看视频,临场感更强。