我们通常说的双机热备是指两台机器都在运行,但并不是两台机器都同时在提供服务。当提供服务的一台出现故障的时候,另外一台会马上自动接管并且提供服务,而且切换的时间非常短。MySQL双主复制,即互为Master-Slave(只有一个Master提供写操作),可以实现数据库服务器的热备,但是一个Master宕机后不能实现动态切换。使用Keepalived,可以通过虚拟IP,实现双主对外的统一接口以及自动检查、失败切换机制,从而实现MySQL数据库的高可用方案。之前梳理了Mysql主从(从只读),下面说下Mysql+keeoalived双主热备高可用方案的实施。
keepalived介绍看另外博客:https://andblog.cn/?p=1365
1)先实施Master->Slave的主主同步。主主是数据双向同步,主从是数据单向同步。一般情况下,主库宕机后,需要手动将连接切换到从库上。(但是用keepalived就可以自动切换)
2)再结合Keepalived的使用,通过VIP实现Mysql双主对外连接的统一接口。即客户端通过Vip连接数据库;当其中一台宕机后,VIP会漂移到另一台上,这个过程对于客户端的数据连接来说几乎无感觉,从而实现高可用。
环境描述: mysql使用的是:mysql-5.7.20的rpm包,最新的可从mysql官网下载 keepalive服务:直接通过yum来进行安装 Centos6.9版本 Master1:192.168.220.70 安装mysql和keepalived Master2: 192.168.220.71 安装mysql和keepalived VIP:192.168.220.74 要实现主主同步,可以先实现主从同步,即master1->master2的主从同步,然后master2->master1的主从同步. 这样,双方就完成了主主同步。 注意下面几点: 1)要保证同步服务期间之间的网络联通。即能相互ping通,能使用对方授权信息连接到对方数据库(允许对方master以及客户机访问这两台机器的3306端口)。 将配置文件中的多播地址,防火墙放行 2)同步时间,关闭selinux。 3)同步前,双方数据库中需要同步的数据要保持一致。这样,同步环境实现后,再次更新的数据就会如期同步了。 4)如果数据目录直接从一台机器拷贝到另外一台机器,需要将mysql数据目录下面的auto.cnf文件删除,不然uuid相同会报错
mysql-5.7.20安装说明
新版本安装好后,修改配置文件,根据配置文件创建好需要的数据目录,日志目录,权限等操作 启动mysql服务,刚开始会进行数据初始化操作,初始化完成后,可以使用mysql命令连接服务 新版本会在日志文件中生成一个临时密码,使用临时密码登录,登录后必须修改密码,不然不能操作 关闭服务,在配置文件中添加:validate_password=off 选项,让系统可以接受弱密码,这时可以修改密码为常用的密码 mysql> set password = password("abcdef"); 上面的顺序不能错,刚开始不能添加validate_password选项,不然报错
Master1授权
[root@RTB-70 ~]#cat /etc/my.cnf [client] password = abcdefg port = 3306 socket = /data/mysql/mysql.sock default-character-set=utf8 [mysqld] port = 3306 socket = /data/mysql/mysql.sock datadir = /data/mysql user = mysql character-set-server=utf8 server-id = 70 skip-external-locking key_buffer_size = 256M max_allowed_packet = 100M table_open_cache = 256 sort_buffer_size = 1M read_buffer_size = 1M read_rnd_buffer_size = 4M myisam_sort_buffer_size = 64M thread_cache_size = 8 query_cache_size= 16M validate_password=off skip-name-resolve slow_query_log log_warnings=1 expire_logs_days = 30 auto-increment-increment = 2 auto-increment-offset = 1 slave-skip-errors = all log-bin=/data/mysql_binlog/mysql-bin binlog-ignore-db = mysql,information_schema binlog_format=mixed relay_log=/data/mysql_binlog/mysql-relay [mysqldump] quick max_allowed_packet = 100M [mysqld_safe] log-error=/var/log/mysqld/mysqld.log pid-file=/data/mysql/mysqld.pid [root@RTB-70 ~]#service mysqld restart Stopping mysqld: [ OK ] Starting mysqld: [ OK ] [root@RTB-70 ~]#mysql mysql> grant replication slave, replication client on *.* to 'rep_user'@'192.168.220.%' identified by '456789'; Query OK, 0 rows affected, 1 warning (0.01 sec) mysql> flush privileges; Query OK, 0 rows affected (0.02 sec) mysql> flush tables with read lock; Query OK, 0 rows affected (0.00 sec) mysql> show master status; +------------------+----------+--------------+--------------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+--------------------------+-------------------+ | mysql-bin.000003 | 884 | | mysql,information_schema | | +------------------+----------+--------------+--------------------------+-------------------+ 1 row in set (0.00 sec)
Master2授权
[root@RTB-71 ~]#cat /etc/my.cnf [client] password = abcdefg port = 3306 socket = /data/mysql/mysql.sock default-character-set=utf8 [mysqld] port = 3306 socket = /data/mysql/mysql.sock datadir = /data/mysql user = mysql character-set-server=utf8 server-id = 71 skip-external-locking key_buffer_size = 256M max_allowed_packet = 100M table_open_cache = 256 sort_buffer_size = 1M read_buffer_size = 1M read_rnd_buffer_size = 4M myisam_sort_buffer_size = 64M thread_cache_size = 8 query_cache_size= 16M validate_password=off skip-name-resolve slow_query_log log_warnings=1 expire_logs_days = 30 auto-increment-increment = 2 auto-increment-offset = 2 slave-skip-errors = all log-bin=/data/mysql_binlog/mysql-bin binlog-ignore-db = mysql,information_schema binlog_format=mixed relay_log=/data/mysql_binlog/mysql-relay [mysqldump] quick max_allowed_packet = 100M [mysqld_safe] log-error=/var/log/mysqld/mysqld.log pid-file=/data/mysql/mysqld.pid [root@RTB-71 ~]#service mysqld restart Stopping mysqld: [ OK ] Starting mysqld: [ OK ] [root@RTB-71 ~]#mysql mysql> grant replication slave, replication client on *.* to 'rep_user'@'192.168.220.%' identified by '456789'; Query OK, 0 rows affected, 1 warning (0.01 sec) mysql> flush privileges; Query OK, 0 rows affected (0.02 sec) mysql> flush tables with read lock; Query OK, 0 rows affected (0.00 sec) mysql> show master status; +------------------+----------+--------------+--------------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+--------------------------+-------------------+ | mysql-bin.000004 | 154 | | mysql,information_schema | | +------------------+----------+--------------+--------------------------+-------------------+ 1 row in set (0.00 sec)
Master1->Master2
[root@RTB-71 ~]#mysql mysql> unlock table; Query OK, 0 rows affected (0.00 sec) mysql> change master to master_host='192.168.220.70', master_user='rep_user', master_password='456789', master_log_file='mysql-bin.000003', master_log_pos=884; Query OK, 0 rows affected, 2 warnings (0.16 sec) mysql> start slave; Query OK, 0 rows affected (0.00 sec) mysql> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.220.70 Master_User: rep_user Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000003 Read_Master_Log_Pos: 884 Relay_Log_File: mysql-relay.000002 Relay_Log_Pos: 320 Relay_Master_Log_File: mysql-bin.000003 Slave_IO_Running: Yes Slave_SQL_Running: Yes
Master2->Master1
[root@RTB-70 ~]#mysql mysql> unlock table; Query OK, 0 rows affected (0.00 sec) mysql> change master to master_host='192.168.220.71', master_user='rep_user', master_password='456789', master_log_file='mysql-bin.000004', master_log_pos=154; Query OK, 0 rows affected, 2 warnings (0.16 sec) mysql> start slave; Query OK, 0 rows affected (0.00 sec) mysql> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.220.71 Master_User: rep_user Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000004 Read_Master_Log_Pos: 154 Relay_Log_File: mysql-relay.000002 Relay_Log_Pos: 320 Relay_Master_Log_File: mysql-bin.000004 Slave_IO_Running: Yes Slave_SQL_Running: Yes
还是有地方没搞明白,为什么我设置binlog忽略了mysql库,但是执行授权语句,binlog的位置还在增加
主主同步测试
在RTB-70机器测试 mysql> create database abc; Query OK, 1 row affected (0.01 sec) mysql> use abc; Database changed mysql> create table if not exists hello (id int(10) primary key auto_increment, name varchar(50) not null); Query OK, 0 rows affected (0.21 sec) mysql> insert into hello (name) values ('andy'); Query OK, 1 row affected (0.06 sec) mysql> show tables; +---------------+ | Tables_in_abc | +---------------+ | hello | +---------------+ 1 row in set (0.00 sec) mysql> select * from hello; +----+------+ | id | name | +----+------+ | 1 | andy | +----+------+ 1 row in set (0.00 sec) 在机器RTB-71上面测试 mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | abc | | mysql | | performance_schema | | sys | +--------------------+ 5 rows in set (0.00 sec) mysql> use abc; Database changed mysql> show tables; +---------------+ | Tables_in_abc | +---------------+ | hello | +---------------+ 1 row in set (0.00 sec) mysql> select * from hello; +----+------+ | id | name | +----+------+ | 1 | andy | +----+------+ 1 row in set (0.00 sec) mysql> insert into hello (name) values ('bob'); Query OK, 1 row affected (0.03 sec) mysql> insert into hello (name) values ('mary'); Query OK, 1 row affected (0.03 sec) mysql> select * from hello; +----+------+ | id | name | +----+------+ | 1 | andy | | 2 | bob | | 4 | mary | +----+------+ 3 rows in set (0.00 sec)
keepalived测试
[root@RTB-70 /etc/keepalived]#cat keepalived.conf ! Configuration File for keepalived global_defs { notification_email { root@localhost } notification_email_from keepalived@localhost smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id keep_mysql vrrp_mcast_group4 224.0.100.50 } vrrp_script chk_down { script "[[ -f /etc/keepalived/down ]] && exit 1 || exit 0" #down文件在,返回1。不在返回0 interval 1 #1秒钟调用一次,当上面的脚本执行返回1的时候会执行下面的操作 weight -20 #当down文件存在,这个vs的节点的优先级-20,如果这个节点的优先级低于其他的vs主机, #这个主机就会处于维护模式,ip被其他优先级高的主机夺走。 } vrrp_script chk_mysql { script "killall -0 mysqld && exit 0 || exit 1" #进程在,返回0,不执行下面的操作。否则1,执行下面的操作 interval 1 weight -20 #当nginx进程不存在了,表示这个节点处错了,将这个节点的优先级调低,让另外的节点来负责工作。 } vrrp_instance c.com { state MASTER interface eth0 virtual_router_id 20 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 2345 } virtual_ipaddress { 192.168.220.74/24 dev eth0 } track_script { chk_down chk_nginx } } [root@RTB-71 /etc/keepalived]#cat keepalived.conf ! Configuration File for keepalived global_defs { notification_email { root@localhost } notification_email_from keepalived@localhost smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id keep_mysql vrrp_mcast_group4 224.0.100.50 } vrrp_script chk_down { script "[[ -f /etc/keepalived/down ]] && exit 1 || exit 0" #down文件在,返回1。不在返回0 interval 1 #1秒钟调用一次,当上面的脚本执行返回1的时候会执行下面的操作 weight -20 #当down文件存在,这个vs的节点的优先级-20,如果这个节点的优先级低于其他的vs主机, #这个主机就会处于维护模式,ip被其他优先级高的主机夺走。 } vrrp_script chk_mysql { script "killall -0 mysqld && exit 0 || exit 1" #进程在,返回0,不执行下面的操作。否则1,执行下面的操作 interval 1 weight -20 #当nginx进程不存在了,表示这个节点处错了,将这个节点的优先级调低,让另外的节点来负责工作。 } vrrp_instance c.com { state BACKUP interface eth0 virtual_router_id 20 priority 90 advert_int 1 authentication { auth_type PASS auth_pass 2345 } virtual_ipaddress { 192.168.220.74/24 dev eth0 } track_script { chk_down chk_nginx } } [root@RTB-70 /etc/keepalived]#service keepalived start Starting keepalived: [ OK ] [root@RTB-71 /etc/keepalived]#service keepalived start Starting keepalived: [ OK ]
客户机测试
在RTB-70机器上面授权该网段访问 mysql> grant all on *.* to 'root'@'192.168.220.%' identified by '234567'; Query OK, 0 rows affected, 1 warning (0.01 sec) 在RTB-72上面测试 [root@rtb-72 ~]#mysql -uroot -h192.168.220.74 -p234567 MySQL [(none)]> insert into abc.hello (name) values('alix'); Query OK, 1 row affected (0.03 sec) MySQL [(none)]> select * from abc.hello; +----+-------+ | id | name | +----+-------+ | 1 | andy | | 2 | bob | | 4 | mary | | 5 | tom | | 7 | hello | | 9 | hi | | 11 | alix | +----+-------+ 7 rows in set (0.00 sec) 在RTB-70机器上面创建文件 [root@RTB-70 /etc/keepalived]#touch down vip漂移到71,正常操作
主主复制自增id说明
根据上面的主从环境部署,master和slave已经实现同步,即在master上写入新数据,自动同步到slave。而从库只能读不能写,一旦从库有写入数据,就会造成主从数据不一致! 下面就说下Mysql主主复制环境,在slave上更新数据时,master也能自动同步过来。 --------------------------------------------------------------------------- 温馨提示: 在做主主同步前,提醒下需要特别注意的一个问题: 主主复制和主从复制有一些区别,因为多主中都可以对服务器有写权限,所以设计到自增长重复问题,例如: 出现的问题(多主自增长ID重复) 1)首先在A和B两个库上创建test表结构; 2)停掉A,在B上对数据表test(存在自增长属性的ID字段)执行插入操作,返回插入ID为1; 3)然后停掉B,在A上对数据表test(存在自增长属性的ID字段)执行插入操作,返回的插入ID也是1; 4)然后 同时启动A,B,就会出现主键ID重复 解决方法: 只要保证两台服务器上的数据库里插入的自增长数据不同就可以了 如:A插入奇数ID,B插入偶数ID,当然如果服务器多的话,还可以自定义算法,只要不同就可以了 在下面例子中,在两台主主服务器上加入参数,以实现奇偶插入! 记住:在做主主同步时需要设置自增长的两个相关配置,如下: auto_increment_offset 表示自增长字段从那个数开始,取值范围是1 .. 65535。这个就是序号。如果有n台mysql机器,则从第一台开始分为设1,2...n auto_increment_increment 表示自增长字段每次递增的量,其默认值是1,取值范围是1 .. 65535。如果有n台mysql机器,这个值就设置为n。 在主主同步配置时,需要将两台服务器的: auto_increment_increment 增长量都配置为2 auto_increment_offset 分别配置为1和2。这是序号,第一台从1开始,第二台就是2,以此类推..... 这样才可以避免两台服务器同时做更新时自增长字段的值之间发生冲突。(针对的是有自增长属性的字段)
参考:http://www.cnblogs.com/kevingrace/p/6710136.html
–
–
–
评论前必须登录!
注册