概述
对于mariadb和redis2.8或更新版本,实现在两台位于不同机房的高可用性方案。涉及工具/程序:
1. keepalived
2. redis2.8
3. mysql
4. glusterfs
5. rails/sidekiq等
6. iptables
目前已有针对双机HA的配置脚本,可以无需手动配置如下项。注意:与rails和sidekiq相关的配置并未包含在脚本中。
双机HA脚本需要保证/etc/hosts中有server1.com、server2.com和haserver.com三个域名。初始设定可以均为127.0.0.1。
配置脚本点我下载 或见附件
1. keepalived
1. 要点:
1. VIP(虚拟IP)总是指向可用的服务器,并在主服务器宕掉以后可以自动将VIP实际指向的地址漂移到另一台可用的服务器
2. 旧master回复以后不抢占回VIP
3. 宕机服务器恢复后作为从机启动,并设置redis同步
4. 如果keepalived狂写系统日志,可能是某两个模块未加载,执行:sudo modprobe ip_vs && sudo modprobe ip_vs_wrr,并将其写入开机启动
2. 安装
1. 从源里安装: sudo apt-get install keepalived(1.1.20版),或
2. 或从https://github.com/acassen/keepalived/archive/master.zip 编译最新版源码(2014年7月最新版为1.2)。
3. 配置文件解释
1. 路径 /etc/keepalived/keepalived.conf
2. vrrp_instance VI_1 { ... }为VRRP协议的实例,VI_1为实例名字。每台机器都可以运行多个实例。每组实例会共同组成一个虚拟IP的集群。
3. state 可选角色为大写MASTER或BACKUP。如果这里指定角色为MASTER ,则该机器启动后会作为主机启动,如果已有其他主机,则会抢占控制权。如果指定角色为BACKUP,则该机器启动后如果优先级高于当前主机,则会抢占控制权。特殊地,如果角色为BACKUP且包含了nopremmpt选项,则该实例不会试图抢占控制权。
4. notify_master 和 notify_backup配置项分别指定本实例作为master或backup启动时,执行的脚本。
5. virtual_server 虚拟IP 80 { ... }指定该虚拟IP所对应的实际IP集群。这里的虚拟IP只能指定IP。
6. real_server server1.com 80 {...}指定一个实际IP或域名的配置。
4. 编写notify_master和notify_backup脚本文件。示例:
* notify_master.sh:
* #!/bin/bash echo [`date`]"作为master启动" >> /home/ewhine/keepalived.log /home/ewhine/redis-2.8.12/src/redis-cli slaveof NO ONE
kill -USR2 mqtt3d
* notify_backup.sh:
#!/bin/bash echo [`date`]"作为backup启动" >> /home/ewhine/keepalived.log du /home/ewhine/deploy/ewhine_NB/efiles >> /dev/null & echo "flush_all" | nc localhost 11211 -q5 /home/ewhine/redis-2.8.12/src/redis-cli slaveof anotherserver.com 6379
kill -USR1 mqtt3d
5. 配置好以后,使用sudo service keepalived start启动
6. 参考资料:http://zhangxugg-163-com.iteye.com/blog/1665419
2. redis
1. 要点:无需做过多配置,只要配置好持久化相关的选项以及daemon模式就好。主从相关的设置交由keepalived的脚本来做。监听IP设置为0.0.0.0。
2. 安装:源里的版本太旧,需要编译新版本。
1. 从http://redis.io/download下载最新版本redis
2. 解包后进入到redis-2.8.xxx/src目录,直接执行make。
3. 编译好的文件为redis-2.8.xx/src/redis-server和src/redis-cli。
4. 默认的配置文件在redis-2.8.xx/redis.conf中。
5. 监听IP设置为0.0.0.0。
6. 将其设置为开机启动,并取消自带redis的开机启动。
3. mysql
1. 要点:
1. 双主复制,实际上是互为对方的主机和从机
2. 配置复制前必须确保两台机器需要同步的库完全相同,推荐直接dump过去
3. 配置文件中的server-id必须不同
2. 步骤
1. 修改/etc/mysql/my.cnf
2. 添加配置:log-bin=MySQL-bin,以启用二进制日志
3. 找到server-id节,确保两台机器上的serverid为不同的整数
4. 绑定IP指定为0.0.0.0
5. 重启mysql服务
6. 保险起见,先在两台机器上执行停止同步的代码:mysql -uroot -pxxxxxx -e "stop slave; reset slave;"
7. dump其中一台机器的esns_production数据库,并在另一台机器上还原
8. 在两台机器上执行语句创建同步用户。假定同步用户名为slaveuser,密码为dehui123:
* grant replication slave on *.* to '同步用户名'@'同步IP或host' identified by '同步密码';flush privileges;
9. 在一台机器(A)上的mysql控制台中执行 show master status;查看其中的master_log_file 和 master_log_pos
10. 在另一台机器(B)上的mysql控制台中执行: change master to master_host='A的IP或域名', master_user='slaveuser', master_password='dehui123', master_log_file='查看到的master_log_file', master_log_pos=查看到的log_pos;start slave;
11. 执行show slave status\G,如果发现Slave_IO_Running和Slave_SQL_Running均为yes则说明主从同步成功。
12. 反过来再做一次,互为对方的主从。
13. 在配置文件里设置master是无效的,应在命令行里手动设置互相为对方的别动作slave。重启以后也可以恢复同步,无需重复指定。
3. 参考资料:
1. http://www.mike.org.cn/articles/mysql-master-slave-sync-conf-detail/
2. http://wenzhongxiang.blog.51cto.com/6370734/1264191
4. glusterfs
1. 要点:
1. 源里的版本比较旧(3.0.5),需要手动编译最新版(目前是3.5),但编译比较坑。具体注意事项如下:
1. configure的时候指定../configure --prefix=/usr否则path会有问题,导致service脚本无法启动。
2. 有资料说ubuntu8.04的fuse默认没有支持glusterfs,需要重新编译。在我们的debian6.0未发现此问题。
3. 两台机器都为(注意,不是“互为”)服务端和客户端,都需要配置/etc/glusterfs/glusterfs.vol (客户端)和glusterfsd.vol(服务端)。
4. 服务器端对外提供分布式文件存储服务,而客户端的作用是允许操作系统像本地驱动器一样透明地挂载和访问虚拟目录。
5. 挂载上的虚拟目录的权限,会根据文件实际所在的目录来映射,不能通过其他途径更改。
6. 挂载好以后,对虚拟目录的写入,实际上是通过glusterfs客户端来做的。
7. 推荐在fstab里写相应配置开机自动挂载。在我们的尝试中,必须在挂载选项里手动写明log-level=WARNING或INFO或其他合法值,如果不写的话默认为“NORMAL”是一个不合法值。
8. 有文章提到必须有_netdev选项,否则有可能在网络设备就绪前试图挂载从而死掉。
2. 安装
1. 源码安装。到http://download.gluster.org/pub/gluster/glusterfs/LATEST/下载tar.gz格式的源码包
2. 解压并进入目录。
3. ../configure --prefix=/usr && make && sudo make install安装。
4. 配置/etc/glusterfs/glusterfs.vol (客户端)和glusterfsd.vol(服务端)配置文件。
3. 配置glusterfs服务端。在两台机器上都执行下面操作:
1. 创建文件存储路径: mkdir -p /data/export /data/export-ns
2. 修改data目录的属主和属组: sudo chown user:group -R /data, user和group根据实际情况填写。
3. 修改服务端配置文件:sudo vim /etc/glusterfs/glusterfsd.vol。服务端仅仅提供服务,并不关心客户端是谁。
volume posix type storage/posix option directory /data/export end-volume volume locks type features/locks subvolumes posix end-volume volume brick type performance/io-threads option thread-count 8 subvolumes locks end-volume volume server type protocol/server option transport-type tcp option auth.addr.brick.allow 192.168.0.102 #只允许特定IP的客户端访问,如果想全部允许,这里写*,但不能不写;如果想用多个IP地址的话,可以在参数中添加逗号指定多个IP subvolumes brick end-volume
4. 启动glusterfs服务端:sudo service glusterfs-server start
4. 配置glusterfs客户端。
1. 创建挂载点。假设为/mnt/glusterfs: mkdir /mnt/glusterfs。
2. 修改配置文件:sudo vim /etc/glusterfs/glusterfs.vol
volume remote1 # 卷名自己指定 type protocol/client option transport-type tcp option remote-host server1.example.com #第一台服务器的IP或域名 option remote-subvolume brick end-volume volume remote2 # 卷名自己指定 type protocol/client option transport-type tcp option remote-host server2.example.com #第二台服务器的IP或域名 option remote-subvolume brick end-volume volume replicate type cluster/replicate subvolumes remote1 remote2 # remote1和remote2卷之间是复制关系 end-volume volume writebehind type performance/write-behind # replicate卷开启writebehind特性 option window-size 1MB subvolumes replicate end-volume volume cache type performance/io-cache option cache-size 512MB # writebehind卷开启读取缓存特性 subvolumes writebehind end-volume
* 挂载虚拟目录: glusterfs -f /etc/glusterfs/glusterfs.vol /mnt/glusterfs。可以执行df查看虚拟目录是否成功挂载。
3. 将自动挂载写入fstab: sudo vim /etc/fstab
* /etc/glusterfs/glusterfs.vol /mnt/glusterfs glusterfs defaults,_netdev,log-level=WARNING 0 0
* 这时重新启动后就会发现已经可以自动挂载了。
4. 这时,针对/mnt/glusterfs的读写操作实际上都会通过glusterfs客户端进行,会同步到两台机器上。
5. 参考资料: http://www.unixbar.net/linux/debian/1363.html
5. rails/sidekiq
1. 概要:将database.yml、sidekiq的配置文件等都修改为haserver.com;将文件存储路径设置为glusterfs的虚拟目录。
2. 注意:这一过程并没有包含在脚本里
6. iptables
* 概要:放行redis的6379端口、mysql的3306端口、glusterfs的端口、keepalived的端口。
* vim /etc/iptables.firewall.rules,在合适的地方加入以下规则。
# Allow gluster -A INPUT -m state --state NEW -m tcp -p tcp --dport 24007:24047 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 111 -j ACCEPT -A INPUT -m state --state NEW -m udp -p udp --dport 111 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 38465:38467 -j ACCEPT # Allow Keepalived -A INPUT -i eth0 -p 112 -j ACCEPT # Allow redis and mysql -A INPUT -m state --state NEW -m tcp -p tcp --dport 6379 -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT