为什么我这么做

一切的起因,还要回到几天前的突发奇想:

由于学业和其他的诸多原因,之后一段时间很可能没有什么时间来维护站点,而目前的服务器明年四月份就要到期,所以产生了购置新的一套服务器+重构目前站点的想法

于是购进了一台服务器,结果

买来的第一天,它 崩 了......

直到昨天(25号)才恢复,并且是以我换到另外一个节点上告终的,使我充分认识到对数据进行备份的重要性......

之前的备份方式主要是冷备份,每天凌晨四点把所有网站数据传到对象存储和我一台北京服务器上,这次事故后突然发现这种备份方式没什么大用,主服务器故障还是需要人来手动重新用冷备份的数据重新在另一台服务器上部署站点,且考虑到之后可能没时间的问题,最适合的方式还是热备份,实现系统本身的高可靠性与高SLA

这种方式之前也实践过一次,使用宝塔专业版的几个插件验证过热备份的可行性,不过宝塔专业版太贵了...... 一年699,有这钱我都可以买好几台不错的服务器,再说目前几个服务器用的面板都是1Panel,所以只能考虑手动配置了

实现

一个wordpress网站总共拆开来就几部分:运行环境,数据库,文件

要实现多台机器运行同一个网站,实际上只要保证上面三项完全相同就可以了

运行环境最简单,数据库个人采用的是MySQL的主从同步(实际上好像也只有这一招),文件同步则是lsyncd(可以实时作为系统进程监控本机目录下的变化并实时同步)

文件同步上选择其实很多,rsync + inotify,sersync,以及本文使用的lsyncd都可以实现这个效果,不过上述前两个都有一定缺陷且配置起来极为复杂,综合个人技术水平和能力最后还是选择了lsyncd

由于个人财力问题,最终的方案是一台源服务器与一台目标服务器进行一主一从的备份,如果有能力可以扩大从机的数量

Lsyncd

SSH

首先自然是给服务器都安装上rsync和lsyncd:

 sudo apt-get install rsync lsyncd

由于本文用的是debian12系统,软件源里自带这两个所以直接apt安装就可以,而对于centos系:

sudo yum install epel-release
sudo yum install lsyncd
sudo yum install rsync

则就需要先安装epel软件源,再从epel安装lsyncd了

lsync文件同步有两种方式:远程shell程序(如rsh,ssh) 与 后台进程(daemon),这里选择的是ssh

首先需要为两台机器建立ssh互信:

ssh-keygen -t rsa

一般地一路回车下去就可以,直到看见如下的界面

生成的公钥文件会在/root/.ssh/id_rsa这个文件里,可以选择手动将他导入目标机同目录的authorized_keys中,或者在源服务器里使用这个命令自动导入:

ssh-copy-id -i /root/.ssh/id_rsa.pub $IP

把其中的$IP换成你自己的目标服务器IP即可,其中可能需要输入目标服务器的密码

出现这个界面就完成了

之后可以使用

ssh $IP

来测试,如果配置正确就可以直接登录到目标服务器,不需要密码,到这一步两机ssh的配置就完成了,之后还有lsyncd的配置

配置

lsyncd的默认配置文件在/etc/rsyncd.conf中,编辑源主机中的这个文件并添加以下配置:

settings {
        logfile = "/var/log/lsyncd/lsyncd.log",
        statusFile = "/var/log/lsyncd/lsyncd.status"
}
sync {
    default.rsyncssh,
    source = "/www/wwwroot", --源目录
    host = "$IP", --目标主机
    targetdir = "/www/wwwroot", --远程目录
    delete = true,
    delay = 0,
    exclude={},
    rsync = {
           binary = "/usr/bin/rsync",
           archive = true,
           compress = true,
           verbose = true, 
           owner = true,
           perms = true,
           _extra = {"--bwlimit=2000"},
           },
        ssh = {
            port = 22
            }
}

保存,启动lsyncd并添加开机自启:

systemctl start lsyncd
systemctl enable lsyncd
lsyncd /etc/lsyncd.conf

lsyncd的日志文件是/var/log/lsyncd/lsyncd.log,如果有报错可以去康康原因,第一次同步根据两台服务器之间的路由和带宽与同步文件大小可能需要几分钟的时间,成功同步就大功告成了

第一次可能会报错找不到日志文件/var/log/lsyncd/lsyncd.log,此时手动创建这个目录并再次

lsyncd /etc/lsyncd.conf

就可以了

接下来是MySQL的主从同步

Mysql

由于1panel使用的是容器化部署,所以需要从软件商店里进入MySQL安装目录中的conf目录:

编辑my.cnf,为源服务器添加以下配置:

log-bin=mysql-bin
server-id=example

目标服务器添加以下配置:

server_id = example
relay_log = relay-bin
log_bin = bin-log

其中server-id需要把example替换成一串数字且两台服务器必须不同,一般地说可用服务器ip的一部分,不过也一样要确定唯一性

在源服务器上创建复制用户并授予权限:

create user 'repuser'@'$IP' identified  by '$PASSWORD';
grant replication slave on *.* to 'repuser'@'$IP';

其中$IP是目标服务器的IP,$PASSWORD是你想设置的密码

同时要注意服务器的mysql服务必须是公开的,如果之前安装时设置的不公开须把容器绑定的ip从127.0.0.1变为0.0.0.0,同时打开系统防火墙,如果要避免扫描等风险可设置仅允许目标服务器访问3306端口(mysql服务端口)

大多数情况下在建立主从时主库都不是空的,所以需要先手动同步两个数据库

执行这两个语句:

flush tables with read lock;
show master status;

第一句会阻止所有的数据库变更,第二句显示当前的日志名称和位置,记录下来,这个就是复制的起点

手动通过1Panel的备份功能导入目前所有的数据库:

在从库里执行:

change master to
master_host = '$IP',
master_user='repuser',
master_password='$PASSWORD',
master_log_file='example',
master_log_pos=example;

其中$IP是主库IP,repuser是主库复制的用户,如果按上面步骤执行就不用动,$PASSWORD是这个用户的密码而最后的两个example是之前使用

show master status;

获得到的位置信息,填好这些信息之后在从库里执行,如果没问题的话,登录从库的phpmyadmin就能看到这样的信息:

主从同步就成功了

其中Slave_IO_Running 和 Slave_SQL_Running 都必须是Yes

到这一步就MySQL的主从同步成功了,接下来需要的只有在两个服务器上都配置同样的网站服务器,SSL证书,这里就不再赘述了

个人建议在完成上述配置后,进一步给数据库设置上只读以避免主从服务器数据不同步导致主从链接断开:

set global read_only=1;

实现服务器的自动切换/负载均衡

这里有两种思路:一种是通过DNS,如果在使用CDN的情况下就需要从CDN处配置源站服务器了

这里不考虑DNS解析到一台服务器通过这台服务器作为负载均衡服务器的形式,完全丧失了这套方案的本来目的——增加网站的稳健性与SLA,因为网关服务器实际上和原来源站的地位一样,一旦异常整套服务就会完全不可用,增加从服务器根本就没意义

个人使用的是DNSPOD与cdnfly系统,所以下面就用这两套来作为实例了,实际上都大差不差

DNSPOD

针对于DNSPOD也有两种选择,一种是D监控一种是新上的负载均衡,我目前还在用D监控

最下面的线路详情就是配置到这个域名上的A记录与CNAME记录

通过这里的切换规则就能实现自动切换了,如果需要负载均衡直接添加解析即可

CDNFLY

小站目前国内走的是一套cdnfly系统的cdn,国外则走的是cloudflare

由于小站主要面向国内访客,且攻击主要来源于国外,所以我在cloudflare上只加了主服务器的IP没加从服务器而是使用always online作为下位替代,只在面向国内的cdnfly上加了从服务器的IP

这样就可以了

写在最后

小站建站这么久,这可能还是第一篇也是最后一篇正经的长文

由于诸多原因,个人接下来很长一段时间可能就没什么精力捣鼓网站了,这次的主要目的也是能让这个小站在无人维护的情况下实现高可靠性和容错性,尽可能提升SLA

不过等下还计划写一篇关于我买过vps的长文,所以这可能也不是最后一篇就是了,vps写完就只考虑更新说说一类了

感谢长时间以来的支持₍ᐢ..ᐢ₎♡