<服务>MySQL主从同步

时间:Jan. 6, 2017 分类:

目录:

MySQL主从同步

MySQL主从同步有利于提高架构提供数据服务,提升访问速度和易于维护管理。MySQL支持单向,双向,链式,实时和异步复制,一台充当主服务器,一台或者多台充当从服务器。可以进行单向或者双向的复制甚至环形同步。

MySQL主从同步方式

  1. 异步binlog同步(会丢数据)
  2. 双写
  3. 通过外部程序记录
  4. 实时同步
  5. google半同步机制

读写分离

通过主服务器写入,从服务器提供读取服务,进而实现对写入少,去读多的网站架构。 读写分离一般会在通过程序来进行实现。 测试环境一般用过代理软件来实现mysql-proxy或amoeba。

主从同步原理

前提:在主库需要开启binlog,建立用于从库同步的用户和密码,先在一个备份点,在从库导入备份数据,从库设定master信息并进行开启slave同步。

主从同步在主库端启用一个IO线程,从库启用一个IO线程和一个SQL线程,从库端的IO线程向主库发送请求,主库端负责复制的IO线程根据slave端的IO线程请求查找到对应POS点的binlog日志和这些binlog日志后一个位置点进行发送给客户端,在客户端把binlog追加到relay-log(中继日志)的末尾,并把后一个位置点更新master.info文件中的binlog日志名称并更新位置点,于此同时SQL线程在发现relay-log中的更新就会通过日志写入从库数据库中,然后从库客户端从matser.info中获取位置点继续向主库进行请求数据,进行循环获取,写入。不过在第一次提交的时候交给主进程用户名密码进行确认步骤,其他都是一致的。

另外从库复制过来后写入数据库文件并不写入log-bin(默认情况下),可以修改log_slave_updates和binlog参数写入log-bin,就可以通过从库继续同步到从库。

通过主主同步,主从同步和级联同步即可以完成mysql官网的几种同步方式。

配置MySQL主从同步

我这边使用的是单机多实例的形式实现主从同步,也可以通过两台服务器进行操作,原理相同。 多实例配置可以参考<服务>数据库和MySQL服务多实例配置

环境准备

[root@why ~]# mysqld_safe --defaults-file=/data/3306/my.cnf 2>&1 > /dev/null &
[1] 10637
[root@why ~]# mysqld_safe --defaults-file=/data/3307/my.cnf 2>&1 > /dev/null &
[2] 11377
[root@why ~]#  ss -nlput | grep 330
tcp    LISTEN     0      128                    *:3307                  *:*      users:(("mysqld",12075,11))
tcp    LISTEN     0      128                    *:3306                  *:*      users:(("mysqld",11359,12))

我这边以3306作为主库,3307作为从库进行实践

检查配置

[root@why ~]# egrep "log-bin|server-id" /data/3306/my.cnf 
log-bin = /data/3306/mysql-bin
server-id = 1
[root@why ~]# egrep "log-bin|server-id" /data/3307/my.cnf 
#log-bin = /data/3307/mysql-bin
server-id = 3
[root@why ~]# mysql -S /data/3306/mysql.sock -e "show variables like 'log_bin'" 
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+

建立用于从库同步的用户和密码

[root@why ~]# mysql -S /data/3306/mysql.sock 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.5.32-log Source distribution

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> grant replication slave on *.* to 'why'@'192.168.0.130' identified by '123456';
Query OK, 0 rows affected (0.09 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)

mysql> flush table with read lock;      #锁表
Query OK, 0 rows affected (0.00 sec)

锁表参数

  • interactive_timeout = 60
  • wait_timeout = 60

备份数据

查看当前数据

[root@why ~]# mysql -S /data/3306/mysql.sock -e "select * from why.student;"
+----+--------+-----+------+
| id | name   | age | dept |
+----+--------+-----+------+
|  1 | why    |  12 | dba  |
|  2 | mabiao |  13 | dev  |
|  3 | yanwei |  15 | dev  |
+----+--------+-----+------+
[root@why ~]# mysqldump -S /data/3306/mysql.sock -A -B --events --master-data=2> why.sql



md5-d7178abe4eda6076e0f16c124fead753



[root@why ~]# vi why.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=1335;



md5-4cc4e4f94247e56c15df9bbe8ba526ba



mysql> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000002 |     1335 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)



md5-b96ef8722f4e8932e64b15e631e7c506



mysql> unlock tables;           #解除锁表
Query OK, 0 rows affected (0.00 sec)



md5-e8e81778ed5c42c8726a5e585c421548



[root@why ~]# mysql -S /data/3307/mysql.sock < why.sql
[root@why ~]# mysql -S /data/3304/mysql.sock -e "select * from why.student;"
+----+--------+-----+------+
| id | name   | age | dept |
+----+--------+-----+------+
|  1 | why    |  12 | dba  |
|  2 | mabiao |  13 | dev  |
|  3 | yanwei |  15 | dev  |
+----+--------+-----+------+



md5-6cb32c2931670234e2582313330d22db



[root@why ~]# mysql -S /data/3307/mysql.sock
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.5.32 Source distribution

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> CHANGE MASTER TO 
    -> MASTER_HOST='192.168.0.130',
    -> MASTER_PORT=3306,
    -> MASTER_USER='why',
    -> MASTER_PASSWORD='123465',
    -> MASTER_LOG_FILE='mysql-bin.000002',
    -> MASTER_LOG_POS=1335;
Query OK, 0 rows affected (0.04 sec)



md5-f8e86b4df331fde5245a6327dfe6877c



[root@why ~]# cat /data/3307/data/master.info 
18
mysql-bin.000002
1335
192.168.0.130
why
123465
3306
60
0





0
1800.000

0



md5-2a445ed7b1e6a4662311c80eee9f53de



mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> show slave status\G;
             Slave_IO_Running: Yes          负责读取主库的BIN_LOG日志并写入中继日志中
            Slave_SQL_Running: Yes          负责读取并执行中继日志的BIN_LOG,转换成SQL语句应用到数据库
        Seconds_Behind_Master: 0            主从复制延迟时间



md5-132a05f8f219df2765810f2768c575fd



show processlist;
mysql> show processlist;
+----+------+---------------------+------+-------------+------+-----------------------------------------------------------------------+------------------+
| Id | User | Host                | db   | Command     | Time | State                                                                 | Info             |
+----+------+---------------------+------+-------------+------+-----------------------------------------------------------------------+------------------+
|  3 | root | localhost           | NULL | Sleep       |  684 |                                                                       | NULL             |
|  7 | why  | 192.168.0.182:39273 | NULL | Binlog Dump |  672 | Master has sent all binlog to slave; waiting for binlog to be updated | NULL             |
|  8 | root | localhost           | NULL | Query       |    0 | NULL                                                                  | show processlist |
+----+------+---------------------+------+-------------+------+-----------------------------------------------------------------------+------------------+
3 rows in set (0.00 sec)



md5-3ba00015155bbdc43bc61a109e4b1eca



mysql> show processlist;
+----+-------------+-----------+----------+---------+------+-----------------------------------------------------------------------+------------------+
| Id | User        | Host      | db       | Command | Time | State                                                                 | Info             |
+----+-------------+-----------+----------+---------+------+-----------------------------------------------------------------------+------------------+
|  1 | root        | localhost | why_utf8 | Sleep   |  999 |                                                                       | NULL             |
|  2 | system user |           | NULL     | Connect | 1038 | Waiting for master to send event                                      | NULL             |
|  3 | system user |           | NULL     | Connect | 1038 | Has read all relay log; waiting for the slave I/O thread to update it | NULL             |
|  6 | root        | localhost | NULL     | Query   |    0 | NULL                                                                  | show processlist |
+----+-------------+-----------+----------+---------+------+-----------------------------------------------------------------------+------------------+
4 rows in set (0.09 sec)



md5-4e37b095ba207fc01f70378e420e1411



binlog-ignore-db=mysql,performance_schema,information_schem



md5-f5b151b903ab1d624f04ba2003a621a4



replicate-ignore-db=mysql,performance_schema,information_schem



md5-b3b0aa5f7aee5fa7ff17e740abb662de



binlog-ignore-db
replicate-ignore-db



md5-92225ced907efbde7c48bf0de808a7e0



stop slave
set global sql_slave_skip_counter=1
start slave



md5-b5da43a6fab15aa6d6288ddfb9b67734



auto_increment_increment = 2 自增id间隔
auto_increment_offset = 1 #id初始位置
log-bin = mysql-bin
log-slave-updates



md5-32e0dee7481991782ae2c267125750ff



auto_increment_increment = 2 自增id间隔
auto_increment_offset = 2 #id初始位置
log-bin = mysql-bin
log-slave-updates



md5-f67c13a75dcd37c9a70b07d3e913b438



[root@why ~]# service mysqld restart
Shutting down MySQL.....                                   [确定]
Starting MySQL.....                                        [确定]



md5-f0573096480c11f6dcd8bc3b6935f218



[root@mysql why]# mysqldump -uroot -p123456 -A -B --master-data=1 -x --events > 182bak.sql



md5-c17003a7c21374ff47548465a0b4e0ec



[root@why ~]# mysql -uroot -p123456 < 182bak.sql 



md5-a078391f724c93583fc2a9a0611f1da8



mysql> CHANGE MASTER TO 
    -> MASTER_HOST='192.168.0.182',
    -> MASTER_PORT=3306,
    -> MASTER_USER='why',
    -> MASTER_PASSWORD='oldboy123'
    -> ;
Query OK, 0 rows affected (0.21 sec)

mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.0.182
                  Master_User: why
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 1138145
               Relay_Log_File: why-relay-bin.000002
                Relay_Log_Pos: 1000
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1138145
              Relay_Log_Space: 1154
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 3
1 row in set (0.00 sec)

ERROR: 
No query specified



md5-27103baeaaddbf6920c823c95f59dc26



mysql> create database testtwomaster;
Query OK, 1 row affected (0.01 sec)

mysql> use testtwomaster;
Database changed
mysql> create table test(id int(4) not null AUTO_INCREMENT,name char(20) not null,primary key(id));
Query OK, 0 rows affected (0.12 sec)

mysql> insert into test(name) values('masterone2');
Query OK, 1 row affected (0.05 sec)

mysql> select * from test;
+----+------------+
| id | name       |
+----+------------+
|  1 | masterone1 |
|  3 | masterone2 |
+----+------------+
2 rows in set (0.01 sec)



md5-bf50c459d1b1ba04b3f902b29d30c1ec



mysql> use testtwomaster;
Database changed
mysql> select * from test;
+----+------------+
| id | name       |
+----+------------+
|  1 | masterone1 |
|  3 | masterone2 |
+----+------------+
2 rows in set (0.00 sec)

mysql> insert into test(name) values('mastertwo1');
Query OK, 1 row affected (0.02 sec)

mysql> insert into test(name) values('mastertwo2');
Query OK, 1 row affected (0.01 sec)

mysql> select * from test;
+----+------------+
| id | name       |
+----+------------+
|  1 | masterone1 |
|  3 | masterone2 |
|  4 | mastertwo1 |
|  6 | mastertwo2 |
+----+------------+
4 rows in set (0.00 sec)



md5-52440a9d63013c3b464469f1e913009a



mysql> insert into test(name) values('masterone3');
Query OK, 1 row affected (0.05 sec)

mysql> insert into test(name) values('masterone4');
Query OK, 1 row affected (0.04 sec)

mysql> select * from test;
+----+------------+
| id | name       |
+----+------------+
|  1 | masterone1 |
|  3 | masterone2 |
|  4 | mastertwo1 |
|  6 | mastertwo2 |
|  7 | masterone3 |
|  9 | masterone4 |
+----+------------+
6 rows in set (0.00 sec)

有关备份周期和恢复

  • 按天备份,恢复时间短,运维成本高,占用空间大
  • 按周备份,恢复麻烦

中小型公司,全量备份一天一次,在业务低估的时候执行全备,备份锁表,而大公司周备,通过binlog做增量

恢复流程

恢复数据最好不要有数据写入,例如iptable只允许当前我登录的客户端写入,或者负载均衡器停止往这边发送数据,或者锁表;如果不允许,就在导入之前切一下binlog,再进行全量恢复和增量恢复,增量恢复的时候记得把binlog中的错误的操作删除,最后把这些切后的binlog导入

如果mysql没有数据写入,关闭sql_log_bin参数,如果关闭,mysql binlog恢复就不会记录binlog,用户写的也不记录。这样可以防止恢复的数据写入binlog

能否锁表等主要是看公司的量化目标是多少。允许宕机多久还是保证数据不丢失,一般公司提供的硬件以及人力所决定,如果不够就需要申请,或者调整量化目标。

服务和数据,就是鱼和熊掌的关系,不可兼得,不停服务,就会有数据的丢失,我倾向于停服务,保数据。当然运维的存在是避免这种事情的发生,而并不是说去救火。