轉自 運維開發_西瓜甜
https://www.jianshu.com/p/faf0127f1cb2
主從複製(也稱 AB 複製)容許未來自一個MySQL數據庫服務器(主服務器)的數據複製到一個或多個MySQL數據庫服務器(從服務器)。html
複製是異步的 從站不須要永久鏈接以接收來自主站的更新。
根據配置,您能夠複製數據庫中的全部數據庫,所選數據庫甚至選定的表。mysql
MySQL中複製的優勢包括:sql
前提是做爲主服務器角色的數據庫服務器必須開啓二進制日誌
Binary log
裏面。Realy log
(中繼日誌)裏面。Realy log
(這個文件也是二進制的),若是發現有更新當即把更新的內容在本機的數據庫上面執行一遍。每一個從服務器都會收到主服務器二進制日誌的所有內容的副本。shell
從服務器設備負責決定應該執行二進制日誌中的哪些語句。數據庫
除非另行指定,不然主從二進制日誌中的全部事件都在從站上執行。ubuntu
若是須要,您能夠將從服務器配置爲僅處理一些特定數據庫或表的事件。安全
重要: 您沒法將主服務器配置爲僅記錄特定事件。服務器
每一個從站(從服務器)都會記錄二進制日誌座標:網絡
因爲每一個從服務器都分別記錄了本身當前處理二進制日誌中的位置,所以能夠斷開從服務器的鏈接,從新鏈接而後恢復繼續處理。session
若是一主多從的話,這時主庫既要負責寫又要負責爲幾個從庫提供二進制日誌。此時能夠稍作調整,將二進制日誌只給某一從,這一從再開啓二進制日誌並將本身的二進制日誌再發給其它從。或者是乾脆這個從不記錄只負責將二進制日誌轉發給其它從,這樣架構起來性能可能要好得多,並且數據之間的延時應該也稍微要好一些。工做原理圖以下:
image.png
mysqld將數字擴展名附加到二進制日誌基本名稱以生成二進制日誌文件名。每次服務器建立新日誌文件時,該數字都會增長,從而建立一系列有序的文件。每次啓動或刷新日誌時,服務器都會在系列中建立一個新文件。服務器還會在當前日誌大小達到max_binlog_size
參數設置的大小後自動建立新的二進制日誌文件 。二進制日誌文件可能會比max_binlog_size
使用大型事務時更大, 由於事務是以一個部分寫入文件,而不是在文件之間分割。
爲了跟蹤已使用的二進制日誌文件, mysqld還建立了一個二進制日誌索引文件,其中包含全部使用的二進制日誌文件的名稱。默認狀況下,它具備與二進制日誌文件相同的基本名稱,並帶有擴展名'.index'
。在mysqld運行時,您不該手動編輯此文件。
術語二進制日誌文件
一般表示包含數據庫事件的單個編號文件。
術語 二進制日誌
表示含編號的二進制日誌文件集加上索引文件。
SUPER
權限的用戶可使用SET sql_log_bin=0
語句禁用其當前環境下本身的語句的二進制日誌記錄
編輯主服務器的配置文件 my.cnf
,添加以下內容
[mysqld] log-bin=/var/log/mysql/mysql-bin server-id=1
建立日誌目錄並賦予權限
shell> mkdir /var/log/mysql shell> chown mysql.mysql /var/log/mysql
重啓服務
shell> systemctl restart mysqld
注意:
若是省略server-id(或將其顯式設置爲默認值0),則主服務器拒絕來自從服務器的任何鏈接。
爲了在使用帶事務的InnoDB進行復制設置時儘量提升持久性和一致性,
您應該在master my.cnf文件中使用如下配置項:
innodb_flush_log_at_trx_commit = 1 sync_binlog = 1
確保在主服務器上 skip_networking
選項處於 OFF
關閉狀態, 這是默認值。
若是是啓用的,則從站沒法與主站通訊,而且複製失敗。
mysql> show variables like '%skip_networking%'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | skip_networking | OFF | +-----------------+-------+ 1 row in set (0.00 sec)
每一個從服務器須要使用MySQL 主服務器上的用戶名和密碼鏈接到主站。
例如,計劃使用用戶 repl
能夠從任何主機上鍊接到 master
上進行復制操做, 而且用戶 repl
僅可使用複製的權限。
在 主服務器
上執行以下操做
mysql> CREATE USER 'repl'@'%' mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%' identified by 'QFedu123!'; mysql>
從服務器
上使用剛纔的用戶進行測試鏈接shell> mysql -urepl -p'QFedu123!' -hmysql-master1
下面的操做根據以下狀況繼續
若是主數據庫包含現有數據,則必須將此數據複製到每一個從站。有多種方法能夠實現:
InnoDB
。shell> mysqldump -u用戶名 -p密碼 --all-databases --master-data=1 > dbdump.db
這裏的用戶是主服務器的用戶
若是不使用 --master-data
參數,則須要手動鎖定單獨會話中的全部表。
scp
或 rsync
等工具,把備份出來的數據傳輸到從服務器中。在主服務中執行以下命令
scp dbdump.db root@mysql-slave1:/root/
這裏的mysql-slave1
須要能被主服務器解析出 IP 地址,或者說能夠在主服務器中ping
通。
從服務器
上編輯其配置文件 my.cnf
並添加以下內容:// my.cnf 文件
[mysqld]
server-id=2
登陸到從服務器上,執行以下操做
/*導入數據*/ mysql> source /root/fulldb.dump
在從服務器配置鏈接到主服務器的相關信息
mysql> CHANGE MASTER TO MASTER_HOST='mysql-master1', -- 主服務器的主機名(也能夠是 IP) MASTER_USER='repl', -- 鏈接到主服務器的用戶 MASTER_PASSWORD='123'; == 到主服務器的密碼
mysql> start slave;
Query OK, 0 rows affected (0.09 sec)
檢查是否成功
在從服務上執行以下操做,加長從服務器端 IO線程和 SQL 線程是不是 OK
mysql> show slave status\G
輸出結果中應該看到 I/O 線程和 SQL 線程都是 YES
, 就表示成功。
執行此過程後,在主服務上操做的修改數據的操做都會在從服務器中執行一遍,這樣就保證了數據的一致性。
和上面的步驟同樣,可是新加入的服務器的server-id
的值不能和現有都服務器 server-id
的值同樣。
假如在新加入從服務器以前,主服務器執行了刪除庫的操做。
而且,刪除的庫恰好是在第一次mysqldump
備份時的數據中。
就會出現問題,在從服務器上提示報錯沒有這個數據庫;
主服務器中設置
my.cnf
配置文件[mysqld]
log-bin=/var/log/mysql/mysql-bin
server-id=1
設置log-bin
時必須同時設置server-id
建立日誌目錄並賦予權限
shell> mkdir /var/log/mysql shell> chown mysql.mysql /var/log/mysql
重啓服務
從服務器設置
my.cnf
配置文件[mysqld]
server-id=3
重啓服務
經過使用命令行客戶端鏈接到主服務器來啓動主服務器上的會話,並經過執行如下FLUSH TABLES WITH READ LOCK
語句來刷新全部表和阻止寫語句:
mysql> FLUSH TABLES WITH READ LOCK; mysql> show master status \G ****************** 1. row **************** File: mysql-bin.000001 Position: 0 Binlog_Do_DB: Binlog_Ignore_DB: Executed_Gtid_Set: 1 row in set (0.00 sec)
mysql> CHANGE MASTER TO
MASTER_HOST='mysql-master1',
MASTER_USER='repl',
MASTER_PASSWORD='123',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=0;
mysql> start slave;
在master上執行show binlog events命令,能夠看到第一個binlog文件的內容。
mysql> show binlog events\G *************************** 1. row *************************** Log_name: mysql-bin.000001 Pos: 4 Event_type: Format_desc Server_id: 1 End_log_pos: 107 Info: Server ver: 5.5.28-0ubuntu0.12.10.2-log, Binlog ver: 4 *************************** 2. row *************************** Log_name: mysql-bin.000001 Pos: 107 Event_type: Query Server_id: 1 End_log_pos: 181 Info: create user rep *************************** 3. row *************************** Log_name: mysql-bin.000001 Pos: 181 Event_type: Query Server_id: 1 End_log_pos: 316 Info: grant replication slave on *.* to rep identified by '123456' 3 rows in set (0.00 sec)
您可使用STOP SLAVE
和 START SLAVE
語句中止並啓動從站上的複製 。
要中止從主服務器處理二進制日誌,請使用 STOP SLAVE
:
mysql> STOP SLAVE;
當複製中止時,從I / O線程中止從主二進制日誌讀取事件並將它們寫入中繼日誌,而且SQL線程中止從中繼日誌讀取事件並執行它們。您能夠經過指定線程類型單獨暫停I / O或SQL線程:
mysql> STOP SLAVE IO_THREAD; mysql> STOP SLAVE SQL_THREAD;
要再次開始執行,請使用如下START SLAVE
語句:
mysql> START SLAVE;
要啓動特定線程,請指定線程類型:
mysql> START SLAVE IO_THREAD; mysql> START SLAVE SQL_THREAD;
MySQL複製功能使用三個線程實現,一個在主服務器上,兩個在從服務器上:
SHOW PROCESSLIST
在主服務器的輸出中將此線程標識爲Binlog Dump
線程。二進制日誌轉儲線程獲取主機二進制日誌上的鎖,用於讀取要發送到從機的每一個事件。一旦讀取了事件,即便在事件發送到從站以前,鎖也會被釋放。
START SLAVE
語句時,從屬服務器會建立一個 I/O 線程,該線程鏈接到主服務器並要求主服務器發送其在二進制日誌中的更新記錄。從屬 I/O線程讀取主Binlog Dump
線程發送的更新 (請參閱上一項)並將它們複製到包含從屬中繼日誌的本地文件。
此線程的狀態顯示爲 Slave_IO_running
輸出 SHOW SLAVE STATUS
或 Slave_running
輸出中的狀態SHOW STATUS
。
在前面的描述中,每一個主/從鏈接有三個線程。具備多個從站的主站爲每一個當前鏈接的從站建立一個二進制日誌轉儲線程,每一個從站都有本身的I / O和SQL線程。
從站使用兩個線程將讀取更新與主站分開並將它們執行到獨立任務中。所以,若是語句執行緩慢,則不會減慢讀取語句的任務。例如,若是從服務器還沒有運行一段時間,則當從服務器啓動時,其I / O線程能夠快速從主服務器獲取全部二進制日誌內容,即便SQL線程遠遠落後。若是從服務器在SQL線程執行了全部獲取的語句以前中止,則I / O線程至少已獲取全部內容,以便語句的安全副本本地存儲在從屬的中繼日誌中,準備在下次執行時執行奴隸開始。
該SHOW PROCESSLIST
語句提供的信息能夠告訴您主服務器和從服務器上有關複製的信息。有關主狀態的信息,請參見第8.14.4節「複製主線程狀態」。有關從站狀態,請參見第8.14.5節「複製從站I / O線程狀態」和 第8.14.6節「複製從站SQL線程狀態」。
如下示例說明了三個線程如何顯示在輸出中SHOW PROCESSLIST
。
在主服務器上,輸出SHOW PROCESSLIST
以下所示:
mysql> SHOW PROCESSLIST\G *************************** 1\. row *************************** Id: 2 User: root Host: localhost:32931 db: NULL Command: Binlog Dump Time: 94 State: Has sent all binlog to slave; waiting for binlog to be updated Info: NULL
這裏,線程2是Binlog Dump
爲鏈接的從屬服務的複製線程。該 State
信息代表全部未完成的更新已發送到從站,而且主站正在等待更多更新發生。若是Binlog Dump
在主服務器上看不到任何 線程,則表示複製未運行; 也就是說,目前沒有鏈接任何從站。
在從屬服務器上,輸出SHOW PROCESSLIST
以下所示:
mysql> SHOW PROCESSLIST\G *************************** 1\. row *************************** Id: 10 User: system user Host: db: NULL Command: Connect Time: 11 State: Waiting for master to send event Info: NULL *************************** 2\. row *************************** Id: 11 User: system user Host: db: NULL Command: Connect Time: 11 State: Has read all relay log; waiting for the slave I/O thread to update it Info: NULL
該State
信息指示線程10是與主服務器通訊的I / O線程,而且線程11是處理存儲在中繼日誌中的更新的SQL線程。在 SHOW PROCESSLIST
運行時,兩個線程都處於空閒狀態,等待進一步更新。
Time
列中 的值能夠顯示從站與主站進行比較的時間。請參見 第A.13節「MySQL 5.7 FAQ:複製」。若是主站側有足夠的時間在Binlog Dump
線程上沒有活動,則主站肯定從站再也不鏈接。對於任何其餘客戶端鏈接,這樣作的超時取決於的值 net_write_timeout
和 net_retry_count
; 有關這些的更多信息,請參見第5.1.7節「服務器系統變量」。
該SHOW SLAVE STATUS
語句提供有關從屬服務器上的複製處理的其餘信息。請參見 第16.1.7.1節「檢查複製狀態」。
就是利用 GTID 來實現的複製
GTID(全局事務標示符)最初由google實現,在MySQL 5.6中引入.GTID在事務提交時生成,由UUID和事務ID組成.uuid會在第一次啓動MySQL時生成,保存在數據目錄下的auto .CNF文件裏,事務ID則從1開始自增使用GTID的好處主要有兩點:
[mysqld] log-bin=/var/log/mysql/mysql-bin server-id=1 gtid_mode=ON enforce_gtid_consistency=1 # 強制執行GTID一致性。
重啓服務
其餘和以前的同樣
mysql> CREATE USER 'repl'@'%' IDENTIFIED BY '123';
mysql> GRANT REPLICATION SLAVE ON . TO 'repl'@'%';
mysql>
測試用戶有效性
shell> mysql -urepl -p'123' -hmysql-master1 [mysqld] server-id=2 gtid_mode=ON enforce_gtid_consistency=1 # 可選項, 把鏈接到 master 的信息存到數據庫中的表中 master-info-repository=TABLE relay-log-info-repository=TABLE
重啓服務
假若有數據,先導入數據
mysql> source dump.db
Mysql 終端執行鏈接信息
mysql> CHANGE MASTER TO MASTER_HOST='172.16.153.10', MASTER_USER='repl', MASTER_PASSWORD='123', MASTER_AUTO_POSITION=1; > start slave;
檢查 slave 狀態
mysql> show slave status\G
設置 從服務器只讀狀態
查看當前只讀的狀態
SHOW VARIABLES LIKE '%read_only%';設置普通用戶只讀
SET GLOBAL read_only=1;設置超級用戶只讀
SET GLOBAL super_read_only=1;
mysql> SHOW VARIABLES LIKE '%read_only%'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | innodb_read_only | OFF | | read_only | OFF | | super_read_only | OFF | | transaction_read_only | OFF | | tx_read_only | OFF | +-----------------------+-------+ 5 rows in set (0.01 sec) mysql> SET GLOBAL read_only=1; Query OK, 0 rows affected (0.00 sec) mysql> ; ERROR: No query specified mysql> SHOW VARIABLES LIKE '%read_only%'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | innodb_read_only | OFF | | read_only | ON | | super_read_only | OFF | | transaction_read_only | OFF | | tx_read_only | OFF | +-----------------------+-------+ 5 rows in set (0.00 sec) mysql> SET GLOBAL super_read_only=1; Query OK, 0 rows affected (0.00 sec) mysql> SHOW VARIABLES LIKE '%read_only%'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | innodb_read_only | OFF | | read_only | ON | | super_read_only | ON | | transaction_read_only | OFF | | tx_read_only | OFF | +-----------------------+-------+ 5 rows in set (0.00 sec) mysql> create database db1; ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement
Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF. To make a complete dump, pass --all-databases --triggers --routines --events
意思是: 當前數據庫實例中開啓了 GTID 功能, 在開啓有 GTID 功能的數據庫實例中, 導出其中任何一個庫, 若是沒有顯示地指定--set-gtid-purged參數, 都會提示這一行信息. 意思是默認狀況下, 導出的庫中含有 GTID 信息, 若是不想導出包含有 GTID 信息的數據庫, 須要顯示地添加--set-gtid-purged=OFF參數.
mysqldump -uroot -p --set-gtid-purged=OFF --all-databases > alldb.db
導入數據是就能夠相往常同樣導入了。
多線程複製在 5.6
中被引入,而且在 5.7
中獲得了進一步的完善。
5.7
中是基於邏輯時鐘的方式進行的多線程複製。
先在從庫上查看默認的多線程複製類型
mysql> show variables like "slave_parallel_type"; | |
---|---|
Variable_name | Value |
slave_parallel_type | DATABASE |
1 row in set (0.01 sec)
mysql>
中止以前能夠查看目前的線程數
show processlist; mysql> stop slave
mysql> set global slave_parallel_type = "logical_clock";
Query OK, 0 rows affected (0.00 sec)
配置併發數量
mysql> set global slave_parallel_workers = 4;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like "slave_parallel_workers"; | |
---|---|
Variable_name | Value |
slave_parallel_workers | 4 |
1 row in set (0.00 sec)
mysql> start slave
上圖中,Master-Master複製的兩臺服務器,既是master,又是另外一臺服務器的slave。這樣,任何一方所作的變動,都會經過複製應用到另一方的數據庫中。在這種複製架構中,各自上運行的不是同一db,好比左邊的是db1,右邊的是db2,db1的從在右邊反之db2的從在左邊,二者互爲主從,再輔助一些監控的服務還能夠實現必定程度上的高能夠用。
上圖中,這是由master-master結構變化而來的,它避免了M-M的缺點,實際上,這是一種具備容錯和高可用性的系統。它的不一樣點在於其中只有一個節點在提供讀寫服務,另一個節點時刻準備着,當主節點一旦故障立刻接替服務。好比經過corosync+pacemaker+drbd+MySQL就能夠提供這樣一組高可用服務,主備模式下再跟着slave服務器,也能夠實現讀寫分離。
這種結構的優勢就是提供了冗餘。在地理上分佈的複製結構,它不存在單一節點故障問題,並且還能夠將讀密集型的請求放到slave上。
MySQL-5.5 及以上支持半同步複製
早前的MySQL複製只能是基於異步來實現,從MySQL-5.5開始,支持半自動複製。在之前的異步(asynchronous)複製中,主庫在執行完一些事務後,是不會管備庫的進度的。若是備庫處於落後,而更不幸的是主庫此時又出現Crash(例如宕機),這時備庫中的數據就是不完整的。簡而言之,在主庫發生故障的時候,咱們沒法使用備庫來繼續提供數據一致的服務了。Semisynchronous Replication(半同步複製)則必定程度上保證提交的事務已經傳給了至少一個備庫。Semi synchronous中,僅僅保證事務的已經傳遞到備庫上,可是並不確保已經在備庫上執行完成了。
此外,還有一種狀況會致使主備數據不一致。在某個session中,主庫上提交一個事務後,會等待事務傳遞給至少一個備庫,若是在這個等待過程當中主庫Crash,那麼也可能備庫和主庫不一致,這是很致命的。若是主備網絡故障或者備庫掛了,主庫在事務提交後等待10秒(rpl_semi_sync_master_timeout的默認值)後,就會繼續。這時,主庫就會變回原來的異步狀態。
MySQL在加載並開啓Semi-sync插件後,每個事務需等待備庫接收日誌後才返回給客戶端。若是作的是小事務,兩臺主機的延遲又較小,則Semi-sync能夠實如今性能很小損失的狀況下的零數據丟失。
千鋒雲計算
mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so'; Query OK, 0 rows affected (0.08 sec) mysql> show global variables like '%semi%'; +-------------------------------------------+------------+ | Variable_name | Value | +-------------------------------------------+------------+ | rpl_semi_sync_master_enabled | OFF | | rpl_semi_sync_master_timeout | 10000 | | rpl_semi_sync_master_trace_level | 32 | | rpl_semi_sync_master_wait_for_slave_count | 1 | | rpl_semi_sync_master_wait_no_slave | ON | | rpl_semi_sync_master_wait_point | AFTER_SYNC | +-------------------------------------------+------------+ 6 rows in set (0.00 sec) mysql>
官網: https://dev.mysql.com/doc/refman/5.7/en/change-master-to.html
官網:https://dev.mysql.com/doc/refman/5.7/en/replication-solutions-encrypted-connections.html
主服務器
建立 CA 證書和私鑰 公鑰
shell> mysql_ssl_rsa_setup
My.cnf 文件配置項
如下的狀況是用 yum
安裝 mysql 的狀況
[mysqld] ssl-ca=/var/lib/mysql/ca.pem ssl-cert=/var/lib/mysql/server-cert.pem ssl-key=/var/lib/mysql/server-key.pem
選項以下:
--ssl-ca
:證書頒發機構(CA)證書文件的路徑名。(--ssl-capath
相似但指定CA證書文件目錄的路徑名。)
--ssl-cert
:服務器公鑰證書文件的路徑名。能夠將其發送到客戶端,並根據其擁有的CA證書進行身份驗證。--ssl-key
:服務器私鑰文件的路徑名。從服務器配置
首先要保證從服務器的 sql 線程和 io 線程處於關閉狀態
mysql> stop slave; mysql> stop slave sql_thread; mysql> CHANGE MASTER TO -> MASTER_HOST='master_hostname', -> MASTER_USER='repl', -> MASTER_PASSWORD='password', -> MASTER_SSL=1, -> MASTER_SSL_CA = 'ca_file_name', -> MASTER_SSL_CAPATH = 'ca_directory_name', -> MASTER_SSL_CERT = 'cert_file_name', -> MASTER_SSL_KEY = 'key_file_name'; mysql> START SLAVE;
關於複製用戶
全新建立
mysql> CREATE USER 'repl'@'%.example.com' IDENTIFIED BY 'password' -> REQUIRE SSL; mysql> GRANT REPLICATION SLAVE ON *.* -> TO 'repl'@'%.example.com';
給原來的用戶添加 REQUIRE SSL
mysql> ALTER USER 'repl'@'%.example.com' REQUIRE SSL;
Mysql 終端中設置
不用重啓服務
下面的命令是隻保留 10 天內的日誌,就是10天前的所有刪除
mysql> set global expire_logs_days = 10;
當二進制日誌的大小達到max_binlog_size
系統變量的值時,將刷新二進制日誌 。
屬性
值
命令行格式
--max-binlog-size=#
系統變量
max_binlog_size
範圍
全局
動態
是
類型
整數
默認值
1073741824
最低價值
4096
最大價值
1073741824
若是對二進制日誌的寫入致使當前日誌文件大小超過此變量的值,則服務器將輪轉二進制日誌(關閉當前文件並打開下一個文件)。最小值爲4096字節。最大值和默認值爲1GB。
事務在一個塊中寫入二進制日誌,所以它永遠不會在幾個二進制日誌之間拆分。所以,若是您有大事務,您可能會看到大於的二進制日誌文件max_binlog_size
。
若是max_relay_log_size
爲0,則該值也 max_binlog_size
適用於中繼日誌。
配置文件中設置
此方法須要重啓服務
[mysqld] expire_logs_days=10
在 MySQL 終端中手動刪除
--清除MySQL-bin.010日誌 mysql> PURGE MASTER LOGS TO 'MySQL-bin.010'; --清除2008-06-22 13:00:00前binlog日誌 mysql> PURGE MASTER LOGS BEFORE '2008-06-22 13:00:00'; --清除3天前binlog日誌BEFORE,變量的date自變量能夠爲'YYYY-MM-DD hh:mm:ss'格式。 mysql> PURGE MASTER LOGS BEFORE DATE_SUB( NOW(), INTERVAL 3 DAY);