天天看點

MySql-主從複制

一、概述

1、原理

複制(Replication)是從一台MySQL資料庫伺服器(主伺服器master)複制資料到另一個伺服器(從伺服器slave)的一個程序。

主伺服器将更新寫入二進制日志檔案,并維護檔案的一個索引以跟蹤日志循環。這些日志可以記錄發送到從伺服器的更新。當一個從伺服器連接配接主伺服器時,它通知主伺服器從伺服器在日志中讀取的最後一次成功更新的位置。從伺服器接收從那時起發生的任何更新,然後封鎖并等待主伺服器通知新的更新。

當進行複制時,所有對複制中的表的更新必須在主伺服器上進行。否則,你必須要小心,以避免使用者對主伺服器上的表進行的更新與對從伺服器上的表所進行的更新之間的沖突。

2、mysql支援的複制類型

(1)基于語句的複制: 在主伺服器上執行的SQL語句,在從伺服器上執行同樣的語句。MySQL預設采用基于語句的複制,效率比較高。

一旦發現沒法精确複制時, 會自動選着基于行的複制。

(2)基于行的複制:把改變的内容複制過去,而不是把指令在從伺服器上執行一遍. 從mysql5.0開始支援

(3)混合類型的複制: 預設采用基于語句的複制,一旦發現基于語句的無法精确的複制時,就會采用基于行的複制。

3、MySQL複制技術的一些特點:

(1)資料分布 (Data distribution )

(2)負載平衡(load balancing)

(3)備份(Backups)

(4)高可用性和容錯行 High availability and failover

4、工作方式

主要分三個步驟

(1)master将改變記錄到二進制日志(binary log)中(這些記錄叫做二進制日志事件,binary log events);

(2)slave将master的binary log events拷貝到它的中繼日志(relay log);

(3)slave重做中繼日志中的事件,将改變反映它自己的資料。

MySql-主從複制

該過程的第一部分就是master記錄二進制日志。在每個事務更新資料完成之前,master在二日志記錄這些改變。MySQL将事務串行的寫入二進制日志,即使事務中的語句都是交叉執行的。在事件寫入二進制日志完成後,master通知存儲引擎送出事務。

下一步就是slave将master的binary log拷貝到它自己的中繼日志。首先,slave開始一個工作線程——I/O線程。I/O線程在master上打開一個普通的連接配接,然後開始binlog dump process(可以使用 show processlist 檢視 Binlog Dump線程)。從伺服器I/O線程讀取主伺服器Binlog Dump線程發送的内容,Binlog dump process從master的二進制日志中讀取事件,如果已經跟上master,它會睡眠并等待master産生新的事件,I/O線程将這些事件寫入中繼日志。

SQL slave thread(SQL從線程)處理該過程的最後一步。SQL線程從中繼日志讀取事件,并重放其中的事件而更新slave的資料,使其與master中的資料一緻。隻要該線程與I/O線程保持一緻,中繼日志通常會位于OS的緩存中,是以中繼日志的開銷很小。

此外,在master中也有一個工作線程:和其它MySQL的連接配接一樣,slave在master中打開一個連接配接也會使得master開始一個線程。複制過程有一個很重要的限制——複制在slave上是串行化的,也就是說master上的并行更新操作不能在slave上并行操作。

二、實踐

以下基于 CentOS x86_64 使用 mariadb-10.1.11.tar.gz 進行配置,首先在主從節點安裝好mariadb

主節點:192.168.1.106  CentOS6.6  x86_64
從節點:192.168.1.113  CentOS6.6  x86_64
           
[root@localhost ~]# wget https://downloads.mariadb.org/interstitial/mariadb-10.1.11/source/mariadb-10.1.11.tar.gz
[root@localhost ~]# yum -y install gcc gcc-c++ make cmake ncurses-devel ncurses libxml2 libxml2-devel openssl-devel bison bison-devel   #安裝編譯環境
[root@localhost ~]# tar xf mariadb-10.1.11.tar.gz  -C /usr/local/
[root@localhost ~]# cd /usr/local/
[root@localhost local]# ln -s mariadb-10.1.11/ mysql
[root@localhost local]# cd  mysql
[root@localhost mysql]# cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DMYSQL_DATADIR=/data/mydata  -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_ARCHIVE_STPRAGE_ENGINE=1 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 -DWIYH_READLINE=1 -DWIYH_SSL=system -DVITH_ZLIB=system -DWITH_LOBWRAP=0 -DMYSQL_UNIX_ADDR=/tmp/mysql.sock -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci
[root@localhost mysql]# make && make install
           

剩餘步驟與mysql編譯安裝方法相同,此處不再詳寫

配置過程:
版本:
、雙方的MySQL版本要一緻;
、如果不一緻:主的要低于從的;

主伺服器:
、改server-id
、啟用二進制日志
、建立有複制權限的帳号

從伺服器:
、改server-id
、啟用中繼日志
、連接配接主伺服器
、啟動複制線程

複制開始的位置:
、都從開始:
、若主伺服器已經運作一段時間,并且存在不小的資料集,此時需要先将主伺服器資料庫進行備份,然後在從服務恢複,從主伺服器上複制時從主伺服器所處的位置開始複制;
           

(1)從0開始複制

配置主伺服器:

安裝好後配置檔案中預設已經啟用二進制日志,主節點server-id可以先不用修改,但是兩個節點的server-id不能相同,二進制日志檔案不要和資料檔案放在一塊,然後開始建立有複制權限的帳号:

MariaDB [(none)]> grant replication slave,replication client on *.* to 'repluser'@'192.168.%.%' identified by 'replpass';      
Query OK,  rows affected (. sec)

MariaDB [(none)]> flush privileges;
           

配置從伺服器:

[[email protected] ~]# vim /etc/my.cnf     #隻需修改以下幾項

#log-bin=mysql-bin
#關閉二進制日志
server-id       = 11
#修改server-id
relay-log       = /mydata/relaylogs/relay-bin
#啟用中繼日志

[[email protected] ~]# mkdir /mydata/relaylogs   #建立目錄

[[email protected] ~]# chown -R mysql.mysql /mydata/


MariaDB [(none)]> show global variables like '%relay%';
+-----------------------+-----------------------------------+
| Variable_name         | Value                             |
+-----------------------+-----------------------------------+
| max_relay_log_size    | 1073741824                        |
| relay_log             | /mydata/relaylogs/relay-bin       |
| relay_log_basename    | /mydata/relaylogs/relay-bin       |
| relay_log_index       | /mydata/relaylogs/relay-bin.index |
| relay_log_info_file   | relay-log.info                    |
| relay_log_purge       | ON                                |
| relay_log_recovery    | OFF                               |
| relay_log_space_limit | 0                                 |
| sync_relay_log        | 10000                             |
| sync_relay_log_info   | 10000                             |
+-----------------------+-----------------------------------+
10 rows in set (0.05 sec)
           

然後啟動複制功能:

MariaDB [(none)]> change master to master_host='192.168.1.106',master_user='repluser',master_password='replpass';  
Query OK,  rows affected ( sec)
           
MariaDB [(none)]> start slave;  #啟動slave
Query OK,  rows affected ( sec)
           
MySql-主從複制
[root@localhost data]# tail -f  localhost.localdomain.err  #檢視日志檔案
--  ::  [Note] InnoDB: Waiting for purge to start
--  ::  [Note] InnoDB:  Percona XtraDB (http://www.percona.com) .- started; log sequence number 
--  ::  [Note] Plugin 'FEEDBACK' is disabled.
--  ::  [Note] InnoDB: Dumping buffer pool(s) not yet started
--  ::  [Note] Server socket created on IP: '::'.
--  ::  [Note] /usr/local/mysql/bin/mysqld: ready for connections.
Version: '10.1.11-MariaDB'  socket: '/tmp/mysql.sock'  port:   Source distribution
--  ::  [Note] 'CHANGE MASTER TO executed'. Previous state master_host='', master_port='3306', master_log_file='', master_log_pos='4'. New state master_host='192.168.1.106', master_port='3306', master_log_file='', master_log_pos='4'.
--  ::  [Note] Slave SQL thread initialized, starting replication in log 'FIRST' at position , relay log '/mydata/relaylogs/relay-bin.000001' position: 
--  ::  [Note] Slave I/O thread: connected to master '[email protected]:3306',replication started in log 'FIRST' at position 
           

在這裡主要是看:

Slave_IO_Running=Yes

Slave_SQL_Running=Yes

在主伺服器插入資料:

MariaDB [(none)]> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |      641 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

MariaDB [(none)]> create database mydb;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> show  databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydb               |
| mysql              |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.00 sec)

MariaDB [(none)]> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |      762 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
           

檢視從伺服器,已經收到資料了:

MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydb               |
| mysql              |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.01 sec)

MariaDB [(none)]> stop slave;    #停止從伺服器服務
Query OK, 0 rows affected (0.01 sec) 

[[email protected] ~]# service mysqld stop  #停止伺服器重新啟動後,slave會自動啟動
Shutting down MySQL.. SUCCESS! 
[[email protected] ~]# service mysqld start
Starting MySQL. SUCCESS! 
[[email protected] ~]# mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 5
Server version: 10.1.11-MariaDB Source distribution

Copyright (c) 2000, 2015, Oracle, MariaDB Corporation Ab and others.

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

MariaDB [(none)]> start slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)

MariaDB [(none)]> show warnings;
+-------+------+--------------------------+
| Level | Code | Message                  |
+-------+------+--------------------------+
| Note  | 1254 | Slave is already running |
+-------+------+--------------------------+
1 row in set (0.00 sec)
           

(2)從半道複制

主伺服器:

MariaDB [(none)]> drop database mydb;       #首先在主從節點先删除資料庫
Query OK, 0 rows affected (0.01 sec)

[[email protected] mydata]# mysql < hellodb.sql     #導入自定義的資料庫
[[email protected] mydata]# mysqldump --all-databases --flush-logs --master-data=2 --lock-all-tables > all.sql  #先備份
-- Warning: Skipping the data of table mysql.event. Specify the --events option explicitly.

[[email protected] mydata]# scp all.sql  [email protected]:~  #将資料複制到從伺服器

MariaDB [(none)]> show  master status;
+-------------------+----------+--------------+------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-bin.000002 |      366 |              |                  |
+-------------------+----------+--------------+------------------+
1 row in set (0.00 sec) 
           

從伺服器:

[root@localhost ~]# mysql < all.sql 

 MariaDB [(none)]> stop slave;   #確定slave功能關閉
 MariaDB [(none)]> change master to master_host='192.168.1.106',master_user='repluser',master_password='replpass',master_log_file='mysql-bin.000002',master_log_pos=;  
Query OK,  rows affected (. sec)

MariaDB [(none)]> start slave;
Query OK,  rows affected (. sec)
           

在主伺服器端插入資料進行MariaDB [(none)]> create database mydb;

Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> show databases;

+——————–+

| Database |

+——————–+

| hellodb |

| information_schema |

| mydb |

| mysql |

| performance_schema |

| test |

+——————–+

6 rows in set (0.00 sec)器:

MariaDB [(none)]> show  databases;
+--------------------+
| Database           |
+--------------------+
| hellodb            |
| information_schema |
| mydb               |
| mysql              |
| performance_schema |
| test               |
+--------------------+
6 rows in set (0.00 sec)
           

可以看到兩邊資料一緻,說明複制已經沒有問題了。

從半道複制和從0複制其實差别不大,隻是在從伺服器中連接配接主伺服器時需要指定二進制日志檔案及其位置即可。

三、更多知識

、主從伺服器時間要同步(ntp):
  */ * * * * /usr/sbin/ntpdate .

、如何限制從伺服器隻讀?
  read-only=ON (在/etc/my.cnf 中定義)
  注意:僅能限制那不具有SUPER權限使用者無法執行寫操作;
  想限制所有使用者:
  mysql> FLUSH TABLES WITH READ LOCK;

、如何主從複制時的事務安全?
  在主伺服器上配置:
  sync_binlog= #每次送出立即将緩沖去内容同步到日志,需要關閉自動送出功能

、複制過濾器:為了節約資源并提高伺服器的性能,可以設定過濾器隻複制希望備份的資料庫,在配置的檔案 my.cnf 中的 [mysqld] 塊中使用以下配置進行過濾:
master上把事件從二進制日志中過濾:
    binlog_do_db= #複制哪些資料庫,白名單
    binlog_ignore_db= #相反的,黑名單

slave上事件從中繼日志中過濾:
    replicate_do_db= #資料庫的白名單
    replicate_ignore_db= #資料庫的黑名單
    replicate_do_table= db_name.table_name #表的白名單
    replicate_ignore_table= #表的黑名單
    replicate_wild_do_table= #支援通配符的白名單
    replicate_wild_ignore_table= #支援通配符的黑名單
MySQL 以上,下面的這些表都建議過濾掉,隻複制生産環境資料。
    replicate-wild-ignore-table =mysql.%
    replicate-wild-ignore-table =test.%
    replicate-wild-ignore-table =log.%
    replicate-wild-ignore-table =information_schema.%
    replicate-wild-ignore-table =performance_schema.%
           

四、配置過程的問題

1)設定 Replication 完成後, start slave後出現 “Could not initialize master info structure”

MariaDB [(none)]> reset slave; # 重點就是這行
MariaDB [(none)]> CHANGE MASTER TO MASTER_LOG_FILE=’mysql-bin′, MASTER_LOG_POS=; # 請依照自行環境設定
MariaDB [(none)]> start slave; # 就正常了.

重新設定 slave, MASTER_LOG_FILE 和 MASTER_LOG_POS 會被清空, 是以需要重新設定.
           

2)mysql 主從同步失敗 Last_IO_Error: Got fatal error 1236 from master

先進入slave中執行:”slave stop;”來停止從庫同步;
再去master中執行:”flush logs;”來清空日志;
然後在master中執行:”show master status;”檢視下主庫的狀态,主要是日志的檔案和position;
然後回到slave中,執行:”CHANGE MASTER TO MASTER_LOG_FILE=’log-bin.′,MASTER_LOG_POS=;”,檔案和位置對應master中的;
最後在slave中執行:”slave start;”來啟動同步。