一,mysql主从复制的原理

mysql支持单向、异步复制,复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。mysql复制基于主服务器在二进制日志中跟踪所有对数据库的更改(更新、删除等等)。因此,要进行复制,必须在主服务器上启用二进制日志。每个从服务器从主服务器接收主服务器已经记录到其二进制日志的保存的更新。当一个从服务器连接主服务器时,它通知主服务器从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,并在本机上执行相同的更新。然后封锁并等待主服务器通知新的更新。从服务器执行备份不会干扰主服务器,在备份过程中主服务器可以继续处理更新。 但是如果在从服务器对数据进行增删的话,主服务器数据不同步。

以下是通过该图的详解。

wKioL1dROMiDyDEhAAFinNBGNxU663.png-wh_50

通过show slave status\G和show master status可以查看复制线程状态。常见的线程状态有:
(1)主服务器Binlog Dump线程
Has sent all binlog to slave; waiting for binlog to be updated
线程已经从二进制日志读取所有主要的更新并已经发送到了从服务器。线程现在正空闲,等待由主服务器上新的更新导致的出现在二进制日志中的新事件。

(2)从服务器I/O线程状态
Waiting for master to send event
线程已经连接上主服务器,正等待二进制日志事件到达。如果主服务器正空闲,会持续较长的时间。如果等待持续slave_read_timeout秒,则发生超时。此时,线程认为连接被中断并企图重新连接。

(3)从服务器SQL线程状态
Reading event from the relay log
线程已经从中继日志读取一个事件,可以对事件进行处理了。
Has read all relay log; waiting for the slave I/O thread to update it
线程已经处理了中继日志文件中的所有事件,现在正等待I/O线程将新事件写入中继日志。

2.复制过程中使用的传递和状态文件
默认情况,中继日志使用host_name-relay-bin.nnnnnn形式的文件名,其中host_name是从服务器主机名,nnnnnn是序列号。中继日志与二进制日志的格式相同,并且可以用mysqlbinlog读取。
从服务器在data目录中另外创建两个小文件。这些状态文件默认名为主master.info和relay-log.info。状态文件保存在硬盘上,从服务器关闭时不会丢失。下次从服务器启动时,读取这些文件以确定它已经从主服务器读取了多少二进制日志,以及处理自己的中继日志的程度。


二,mysql主从复制配置的条件:

 1,确保主从版本兼容,从服务器至少与主服务器版本相同或更高。

 2,初始化表,并子后台启动mysql

 3,修改root密码


三,修改主服务器master:

1
2
3
4
     vi  /etc/my .cnf       
      [mysqld]       
        log-bin=mysql-bin    // [必须]启用二进制日志
        server- id =1       // [必须]服务器唯一ID,默认是1,一般取IP最后一段

备注:og-bin,server-id是配置文件中必须添加的内容。此时主服务器默认对所有数据库进行备份。如果需要特殊指明只对某个数据库进行备份或不备份,则可以加入binlog-do-db和binlog-ignore-db选项


四,修改从服务器slave:

1
2
3
4
#vi /etc/my.cnf
        [mysqld]
       #log-bin=mysql-bin   //[不是必须]启用二进制日志
       server- id =245         // [必须]服务器唯一ID,默认是1,一般取IP最后一段


五,分别重启两台服务器的mysql

1
# /etc/init.d/mysqld restart

六,在主服务器上建立账户并授权slave:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost ~] # mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection  id  is 3
Server version: 5.6.25-log Source distribution
Copyright (c) 2000, 2015, 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  'lqb' @ '%'  identified by  'abc123456' ;          
Query OK, 0 rows affected (0.00 sec)
mysql>
  1. 备注在主服务器上,必须为从服务器创建一个用来连接主服务器的用户,并设置replication slave权限。所用具体命令如下:一般不用root,只要账户和密码正确可用具体的客户端ip代替以加强安全。

  2. grant replication slave  

  3. on *.*  

  4. to '帐号' @ '从服务器IP或%' identified by '密码';  


七,登录主服务器的mysql,查询master的状态

1
2
3
4
5
6
7
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |     1192 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row  in  set  (0.00 sec)


八,配置从服务器slave:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
mysql> change master to master_host= '192.168.1.247' ,master_user= 'mysync' ,master_password= 'abc123456' ,master_log_file= 'mysql-bin.000001' ,master_log_pos=1192  \\注意不要断开,1192不需要引号。
mysql> start slave;                                              \\启动从服务器复制功能
Query OK, 0 rows affected, 1 warning (0.00 sec)
 
 
mysql> show slave status\G                           \\查看从服务器复制功能的状态
*************************** 1. row ***************************
                Slave_IO_State: Waiting  for  master to send event
                   Master_Host: 192.168.1.247
                   Master_User: mysync         // 授权账户名,尽量避免使用root
                   Master_Port: 3306
                 Connect_Retry: 60
               Master_Log_File: mysql-bin.000001
           Read_Master_Log_Pos: 1192
                Relay_Log_File: zabbix-relay-bin.000002
                 Relay_Log_Pos: 1155           
         Relay_Master_Log_File: mysql-bin.000001
              Slave_IO_Running: Yes               // 此状态必须为 yes
             Slave_SQL_Running: Yes            // 此状态必须为 yes ,有一个不为 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: 1192
               Relay_Log_Space: 1329
               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: 1
                   Master_UUID: e9139a38-289e-11e6-9bbd-005056892313
              Master_Info_File:  /data/mysql/master .info
                     SQL_Delay: 0
           SQL_Remaining_Delay: NULL
       Slave_SQL_Running_State: Slave has  read  all relay log; waiting  for  the slave I /O  thread to update it
            Master_Retry_Count: 86400
                   Master_Bind: 
       Last_IO_Error_Timestamp: 
      Last_SQL_Error_Timestamp: 
                Master_SSL_Crl: 
            Master_SSL_Crlpath: 
            Retrieved_Gtid_Set: 
             Executed_Gtid_Set: 
                 Auto_Position: 0
1 row  in  set  (0.00 sec)


九,处从服务器测试:

在主服务器的mysql,创建数据库和表,并向表中插入一条数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mysql> create database hello;
Query OK, 1 row affected (0.00 sec)
mysql> use lqb;
Database changed
mysql> create table  test ( id  int(4),name char(20));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into  test  values(1, 'abc' );
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hi_lqb             |
| lqb                |
| mysql              |
| performance_schema |
test                |
+--------------------+
6 rows  in  set  (0.00 sec)


在从服务器上mysql查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hello              |  // 刚刚创建的       |
| mysql              |        |
| performance_schema |
test                |         |
| zabbix             |
+--------------------+
9 rows  in  set  (0.00 sec)
mysql> use hello;
Database changed
mysql> show tables;
+-----------------+
| Tables_in_hello |
+-----------------+
test             |
+-----------------+
1 row  in  set  (0.01 sec)
mysql>  select  * from  test ;    \\查看服务器上新增的具体数据
+------+------+
id    | name |
+------+------+
|    1 | abc  |
+------+------+
1 row  in  set  (0.00 sec)

至此,mysql主从复制完成。



注意:关于log_bin日志 
my.conf 文件中的[mysqld]标签下的log_bin指定日志文件,如果不提供文件名,mysql将自己产生缺省文件名。mysql会在文件名后面自动添加数字引,每次启动服务时,都会重新生成一个新的二进制文件。此外,使用log-bin-index可以指定索引文件;使用binlog-do-db可以指定记录的数据库;使用binlog-ignore-db可以指定不记录的数据库。注意的是:binlog-do-db和binlog-ignore-db一次只指定一个数据库,指定多个数据库需要多个语句。而且,MySQL会将所有的数据库名称改成小写,在指定数据库时必须全部使用小写名字,否则不会起作用。以后对数据库每做的一次操作,都会在binlog中有所记录。



备注:以下脚本是用来检测mysql主从复制是否正常,如果两个都不为yes说明有问题了,可通过zabbix来进行监控。

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
port=` netstat  -anl| grep  3306 | sed  -n  '1p'  | awk  '{print $4}' | awk  -F:  '{ print $2}' `
array=($(mysql -uroot -p123 -e  "show slave status\G" | grep  "Running"  | awk  '{print $2}' ))
if  [ "$port"  ==  "3306" ]
then
   if  "${array[0]}"  ==  "Yes"  ] || [  "${array[1]}"  ==  "Yes" 
     then
       echo  "slave is OK"
     else
       echo  "slave is error"
   fi
fi