前提条件:对于mariadb和redis2.8或更新版本,实现在两台位于不同机房的高可用性方案。
要求:对客户端透明,自动切换。
考虑了几个方案,最后决定都使用keepalived方案来进行failover。这样的话,有以下几个问题需要解决:
- 配置keepalived,使VIP总是指向可用的服务器,并在某台服务器宕掉以后可以自动将VIP实际指向的地址漂移到另一台可用的服务器
- 双向同步mysql和redis,使得宕机切换以后,新的服务器上的redis和mysql的数据与原来宕掉的服务器相同
- 旧master恢复以后抢占回VIP
- 抢占回VIP以后,redis会直接作为master启动,另一台作为backup启动。因此master脚本需要首先从backup机复制回数据,等待5秒,然后再slaveof no one,以便继承宕机时产生的新数据
- 如果可以的话,最好额外写脚本,检测mysql和redis进程是否宕掉,宕掉要重启(尚未实现)
- 试着做读写分离:只要有一台机器活着,那么IP1的指向总是可读可写;IP2的指向总是可读的,而客户端不关心它们究竟在哪台服务器上;切换时对客户端透明,且不会丢失数据
因此,最终配置服务器时需要有以下几个要点:
配置文件见附件或点击这里:
redis:
- 防火墙要放行相应端口:6379;
- 不使用sentinel机制;
- 使用redis自身的主从同步机制;
- 在keepalived的配置文件里将两台机器都作为BACKUP角色,但优先度一高一低,高优先度的指明nopreempt属性;
- 指明当某台机器作为master加入时,调用脚本A,作为backup加入时,调用脚本B。A脚本指示redis:slaveof NO ONE。B脚本指示slaveof 另一台服务器 端口号。
- 如果keepalived狂写系统日志,可能是某两个模块未加载,执行:sudo modprobe ip_vs && sudo modprobe ip_vs_wrr,并将其写入开机启动
- redis的配置文件中,双方都指定自己为对方的slave。这样如果是redis进程宕掉又启动成功后,redis会读取配置文件自动成为新master的slave。
mysql:
- 不使用drbd,使用mysql自身的replica机制。
- 在my.cnf里配置相应选项:保证server_id不同。
- 同步前必定保证两台服务器的数据库完全相同,推荐直接dump过去。
- 设置好要忽略的数据库和要启用的数据库:
- 设置记录二进制日志:在mysql配置文件的[mysqld]节中设置log-bin=MySQL-bin,server-id两台机器为不同的整数值;
- 设置两台机器的auto_increment_offset分别为1和2,auto_increment_increment都为2,以避免主键冲突;
- 配置文件里的binlog_do_db和binlog_ignore_db的选项按照文档的意思,是指只针对use xxdatabase;之后的操作有效,而对跨表操作无效;如果需要指定多个表,只需多次指定此选项,而不是使用逗号分隔;
- 但是我在配置文件里没有填写这一项,似乎可以允许跨表同步。待进一步测试。
- 配置文件修改好后重启mysql服务;
- 在两台服务器上分别执行SQL语句授权对方允许同步自己: grant replication slave on *.* to 'username'@'%' identified by 'password';
- 执行show master status;查看现在自身的状态;状态的File和Position用于另一台机器设置同步
- 另一台机器上执行: change master to master_host='host_ip', master_user='username', master_password='password', master_log_file='上一步查到的文件名',master_log_pos=上一步查到的postion值;start slave;
- 使用show slave status\G查看slave进程状态,如果slave io_threads和slave sql_threads两个都是YES就表示同步线程运行中。
- 在配置文件里设置master是无效的,应在命令行里手动设置互相为对方的别动作slave。重启以后也可以恢复同步,无需重复指定。
- 用同样的步骤设置另一台服务器的主从结构。
- 这样mysql就应该是双向同步了。如果运行正确的话,即使服务器或mysql服务宕掉以后,中途执行的语句也可以被同步。
读写分离的试作方案:
- 使用keepalived另建立一个实例2,实例2的虚拟IP和实例1的虚拟IP互为不同主机;
- 不论哪台机器宕机时,都需要切换到另一台机器上,并在回复后抢占回来;
- 保证VIP1永远是可读可写的,而VIP2永远至少是可读的,但客户端不关心它们是不是同一台服务器,也不关心VIP2是否可写。
- rails上使用这个gem:db-charmer的github主页;这里是使用文档
迁移最好不用它的机制,而是在迁移完毕以后通过mysqldump实现比较稳妥