1、主從複製的工做原理
mysql
Mysql在Master與slave之間實現整個複製的過程由3個線程來完成的,
linux
其中兩個線程(SQL線程和IO線程)在 Slave端,
sql
另一個線程(IO)在Master端
數據庫
要實現Mysql的複製必須首先打開Master端的binary log(也就是二進制日誌)不然沒法實現.vim
Mysql複製基本過程以下:緩存
(1)Slave上面的IO 線程連接上Master,而且請求指定日誌文件的位置(或者 從開始的日誌以後的日誌內容)
服務器
(2)Master接收到來自Slave的IO線程請求後,經過負責複製的IO線程根據這個請求信息指定日誌的位置後,
多線程
把這個信息返回給Slave的IO線程(返回的信心當中除了日誌所包含的信息外,還包括了Master端的二進制文件名稱和 二進文件的位置)架構
(3)Slave的IO線程接收到Master端的返回信息以後,將日誌內容一次寫入slave端的Relay log文件,(mysql-relay-bin.xxx)當中,而且讀取到Master端的bin-log文件和位置記錄, 記錄到master-info文件當中,以便下一次可以清楚的告訴Master我須要從某個bin-log的哪一個位置開始日後的內容,請發給我。
(4)、Slave的SQL線程檢測Relay log中心增長了內容後,立刻解析Master二進制文件中的內容,而且執行裏面的Query語句. 數據的更新 只能從主服務器向從服務器更新,而不能反過來進行。
socket
當master主服務器中數據有更新時,會先將數據的更新寫入本身的數據庫中,
將更新的語句寫入二進制日誌文件裏面。
對於從服務器,首先啓動IO線程 向主服務器進行二進制日誌的複製到本身的中繼日誌裏面,
從服務器複製了二進制日誌內容以後並不會直接更新本身的數據庫,要首先寫入本身的中繼Relay log日誌裏面,
而後從服務器使用SQL線程從中繼日誌裏面解析二進制日誌去更新本身的數據庫。
注意:1. 從服務器必須啓動兩個線程
2. 不會直接更新本身的數據庫,而是寫入本身的中繼日誌
3. 單向更新
2、Mysql的優勢
1.若是主服務器出現問題,能夠快速切換到從服務器提供的服務
2.能夠在從服務器上執行查詢操做,下降主服務器的訪問壓力
3.能夠在從服務器上執行備份,以免備份期間影響主服務器的服務
==============================================
注意error:
(1)進行主從複製,主從服務器的時間要同步
# date -s '2015-07-22'
# date
(2) 關閉防火牆
# iptables -F
# vim /etc/selinux/config
(3) 初始化可能會遇到錯誤。不要懼怕。把數據庫文件下的全部文件都刪除掉。datadir=/database/mydata
從新初始化
(4)當啓動mysql時,出現without PID時,cat /etc/my.cnf --> 錯誤日誌的位置 -->查看錯誤日誌
# ps -ef | grep mysqld
# kill -p PID
(5 )不能受權了一次沒有成功,又繼續受權,會混亂的。要把第一次受權的用戶刪掉
再從新受權用戶。
=================================
爲何MySQL要作主從複製(讀寫分離)?
通俗來說,若是對數據庫的讀和寫都在同一個數據庫服務器中操做,業務系統性能會下降。
爲了提高業務系統性能,優化用戶體驗,能夠經過作主從複製(讀寫分離)來減輕主數據庫的負載。
並且若是主數據庫宕機,可快速將業務系統切換到從數據庫上,可避免數據丟失。
主從複製有兩種方式:
基於日誌(binlog)
基於GTID(全局事務標示符)
======================================
一、基於日誌的主從複製
主服務器:10.0.199.1
從服務器:10.0.199.2
(1)主服務器配置
[client]
port = 3306
socket = /tmp/mysql.sock
[mysqld]
user = mysql
innodb_buffer_pool_size = 128M
log_bin = master-log
max_binlog_size = 64M
binlog_format = mixed
basedir = /usr/local/mysql
datadir = /database/mydata
port = 3306
server_id = 1
socket = /tmp/mysql.sock
log_error = /database/mydata/server1.err
character_set_server = utf8
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
數據庫初始化
# service mysqld stop
# cd /usr/local/mysql
# ./scripts/mysql_install_db --user=mysql --datadir=/database/mydata
# service mysqld start
給從服務器受權
mysql> grant replication slave on *.* to 'admin'@'10.0.199.2' identified by 'aixocm';
mysql> flush privileges;
mysql> show master status\G
mysql> select user,host,password from mysql.user;
(2)從服務器配置
[client]
port = 3306
socket = /tmp/mysql.sock
[mysqld]
user = mysql
innodb_buffer_pool_size = 128M
log_bin = slave-log
max_binlog_size = 64M
log_slave_updates = on
binlog_format = mixed
relay_log = relay-bin
basedir = /usr/local/mysql
datadir = /database/mydata
port = 3306
server_id = 2
socket = /tmp/mysql.sock
log_error = /database/mydata/server1.err
character_set_server = utf8
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
數據庫初始化
# service mysqld stop
# cd /usr/local/mysql
# ./scripts/mysql_install_db --user=mysql --datadir=/database/mydata
注意:初始化可能會遇到錯誤。不要懼怕。把數據庫文件下的全部文件都刪除掉。datadir=/database/mydata
從新初始化
# service mysqld start
設置主服務器相關信息
mysql> show master status\G; (在主服務器端)
mysql> change master to master_host='10.0.199.1',master_user='admin',master_password='aixocm',master_log_file='m aster-log.000011',master_log_pos=565,master_port=3306;
# master_log_pos=565 //意思把565之後的日誌都同步到從服務器上。也能夠設置爲1 或者其餘數字位置。
mysql> start slave;
mysql> show slave status\G
線程都必須爲yes,同步數據纔會成功。
若是主服務器 進行了增刪改操做,在從服務器上show slave status\G出現了以下錯誤:
解決辦法:mysql> reset master; (在主服務器上刪除全部的日誌datadir=/database/mydata)
mysql> stop slave;
(3)二進制日誌操做
mysql日誌分爲4種:
(1)二進制日誌
(2)錯誤日誌
(3)慢 查詢日誌
(4)通用查詢日誌
# vim /etc/profile
export PATH=$PATH:/usr/local/mysql/bin
由於:全部和mysql有關的命令都在mysql安裝目錄下的bin下 (mysqlbinlog命令)
# source /etc/profile
# mysqlbinlog master-log.000001
# mysqlbinlog --start-datetime='2015-07-13 7:10:0' master-log.000003
# mysqlbinlog --start-datetime='2015-07-13 7:10:0' --stop-datetime='2015-07-13 7:33:0' master-log.000003
# mysqlbinlog --start-position=330 master-log.000003
# mysqlbinlog --start-position=330 --stop-position=1100 master-log.000003
# mysqlbinlog --start-position=330 --stop-position=1100 master-log.000003 | mysql -u root
\\恢復指定二進制日誌的 內容
mysql> show master logs;
mysql> show binary logs;
mysql> show binlog events in 'master-log.000003' limit 20;
mysql> show binlog events in 'master-log.000003' from 409 limit 10;
mysql> purge master logs to 'master-log.000002'; \\刪除指定編號以前的日誌
mysql> purge master logs before '2015-07-22 08:00:00';
(4)設置忽略的數據庫
注意:修改了配置文件以後,必需要像上面同樣都要進行數據初始化,主服務器受權刷新 從服務器change
主服務器設置
binlog_do_db = sxjy \\記錄二進制日誌的數據庫
binlog_ignore_db = test \\不記錄二進制日誌的數據庫
binlog_ignore_db = teach
從服務器設置
replicate_do_db = sxjy \\設置默認進行二進制日誌複製的數據庫
replicate_ignore_db = test \\不對test數據庫進行二進制日誌複製
replicate_ignore_db = teach
replicate_ignore_db = mysql
replicate_ignore_db = information_schema
replicate_do_table = sxjy.stu \\設置進行更新的表
replicate_ignore_table = sxjy.class \\不進行更新的表
從服務器建議設置
replicate_ignore_db = test \\不對test數據庫進行二進制日誌複製
replicate_ignore_db = mysql
replicate_ignore_db = information_schema
replicate_wild_do_table = sxjy.stu \\複製指定的數據庫或表的二進制日誌
replicate_wild_do_table = sxkj.%
replicate_wild_ignore_table = sxjy.class \\不復制指定的數據庫或表的二進制日誌
練習:先搭建一臺mysql數據庫服務器,不啓用二進制日誌,而後啓動服務器,先建立一個sxjy數據庫,
在sxjy數據庫下建立stu和teach兩個表,字段本身添加3-4個,而後插入4-5個記錄。而後將
服務器改成主從結構,要求原先的服務器作主服務器,且在從服務器上要有主服務器上原來的數
主從結構搭建好後,之後添加的數據可以自動同步到從服務器,主從服務器數據要徹底一致。
解析: 主服務器:# mysqldump -uroot --opt --database sxjy > sxjy.sql
將新建的sxjy數據庫導出。而後創建了主從複製以後,再將sxjy.sql導入到從服務器內。
二、基於GTID的mysql主從複製
(1) TID:Transaction ID,事務的ID號:也就是說在mysql複製中每個事務都有本身的ID號(隨機數)
(2) GTID:Global Transaction ID,全局事務ID
在整個事務架構中每個事務ID號是全局惟一的,
不止是在一個節點上而是整個主從複製架構中每任何兩個事務的ID號都不會相同。
(3) 全局事務ID是怎麼生成的?
簡 單來說是由mysql服務器自動管理的,在mysql5.6之後每個mysql服務器都有一個全局惟一的ID號叫作uuid,通用惟 一識別碼 (Universally Unique Identifier),而GTID就是由當前節點的UUID(一個128位的隨機數)和爲當前節點生成的隨機數(TID)組成的,所以只要UUID不一樣 再在此基礎上保證事務ID不一樣就保證全局不同了。
(4) 全局事務ID有何用處?
簡單來說GTID可以保證讓一個從服務器到其餘的從服務器那裏實現數據複製並且可以實現數據整合的。GTID在分佈式架構中能夠保證數據的一致性。從而也實現了mysql的高可用性。
(5) GTID相關操做:
默認狀況下將一個事務記錄進二進制文件時將首先記錄它的GTID並且GTID和事務相關信息一併要發送給從服務器由從服務器在在本地應用認證可是絕對不會改變原來的事務ID號。
(6) GTID的組成部分:
前面是server_uuid:後面是一個序列號
例如:server_uuid:sequence number
7800a22c-95ae-11e4-983d-080027de205a:10
UUID:每一個mysql實例的惟一ID,因爲會傳遞到slave,因此也能夠理解爲源ID。
Sequence number:在每臺MySQL服務器上都是從1開始自增加的序列,一個數值對應一個事務。
(7) GTID的工做原理:
一、master更新數據時,會在事務前產生GTID,一同記錄到binlog日誌中。
二、slave端的i/o 線程將變動的binlog,寫入到本地的relay log中。
三、sql線程從relay log中獲取GTID,而後對比slave端的binlog是否有記錄。
四、若是有記錄,說明該GTID的事務已經執行,slave會忽略。
五、若是沒有記錄,slave就會從relay log中執行該GTID的事務,並記錄到binlog。
六、在解析過程當中會判斷是否有主鍵,若是沒有就用二級索引,若是沒有就用所有掃描。
要點:
一、slave在接受master的binlog時,會校驗master的GTID是否已經執行過(一個服務器只能執行一次)。
二、爲了保證主從數據的一致性,多線程只能同時執行一個GTID。
(1)可以基於數據庫進行多線程複製(要求2個或2個以上的數據庫進行同步)
(2)可以自動判斷要複製的位置
注意:修改了配置文件以後,必需要像上面同樣都要進行數據初始化,主服務器受權刷新 從服務器change
注意:初始化可能會遇到錯誤。不要懼怕。把數據庫文件下的全部文件都刪除掉。datadir=/database/mydata
從新初始化
binlog-format:二進制日誌的格式,有row、statement和mixed
在上面的基於日誌的主從複製配置文件中再加入如下內容:
主服務器配置
bin_log = master-log
log_slave_updates = on
gtid_mode = on \\開啓GTID模式
enforce_gtid_consistency = on \\強制GTID的一致性
master_info_repository =TABLE \\主服務器信息的記錄方式(TABLE或FILE)
relay_log_info_repository = TABLE \\中繼日誌信息的記錄方式
sync_master_info = 1 \\同步主數據庫信息, 確保服務器崩潰時無信息丟失
slave_parallel_workers = 4 \\從服務器的sql線程數,和要複製的數據庫的個數 相同
binlog_checksum =CRC32 \\二進制日誌的校驗方式
master_verify_checksum = 1 \\主服務器啓用校驗
slave_sql_verify_checksum = 1 \\從服務器啓用校驗
binlog_rows_query_log_events = 1 \\二進制日誌詳細記錄事件 ,可下降故障排除的複雜度
report_port = 3306 \\提夠複製的報告端口,和數據庫端口一致
report_host = 10.0.199.1 \\提供複製報告的主機,設爲本機地址
mysql> grant replication slave on *.* to 'admin'@'10.0.199.2' identified by 'aixocm';
mysql> flush privileges;
mysql> show master status\G
從服務器配置
bin_log = master-log
log_slave_updates = on
gtid_mode = on \\開啓GTID模式
enforce_gtid_consistency = on \\強制GTID的一致性
master_info_repository =TABLE \\主服務器信息的記錄方式(TABLE或FILE)
relay_log_info_repository = TABLE \\中繼日誌信息的記錄方式
sync_master_info = 1 \\同步主數據庫信息
slave_parallel_workers = 4 \\從服務器的sql線程數,和要複製的數據庫的個數 相同
binlog_checksum =CRC32 \\二進制日誌的校驗方式
master_verify_checksum = 1 \\主服務器啓用校驗
slave_sql_verify_checksum = 1 \\從服務器啓用校驗
binlog_rows_query_log_events = 1 \\二進制日誌詳細記錄事件
report_port = 3306 \\提夠複製的報告端口,和數據庫端口一致
report_host = 10.0.199.2 \\提供複製報告的主機,設爲本機地址
slave_skip_errors = all
\\若是在主服務器的某個表中插入4,'張三','man' ,而又在從插入4,'王五','woman' 相沖突。
跳過此error,從而不影響下面數據的同步
(或slave_skip_errors = 1062,1756,2003)
mysql> change master to master_host='10.0.199.1',master_user='admin',
master_password='aixocm',master_auto_position=1;
mysql> start slave;
必須所有爲yes纔會成功
mysql> show processlist\G
mysql> show status like 'thread%';
三、雙主複製
注意:互爲主從。兩邊都要相互進行數據初始化受權刷新change
在基於日誌的主從複製配置文件上添加如下內容:
第一臺服務器設置(10.0.199.1)
auto_increment_increment = 2 # 數據表記錄的自增量,通常等於服務器的數量
auto_increment_offset = 1 # 數據表記錄每次的遞增量,第一臺爲1,第二臺爲2,...
sync_binlog = 0 # 二進制日誌寫入磁盤的方式(1表示當即寫入磁盤 0表示先緩存再寫入磁盤)
replicate_same_server_id = 0 # 防止mysql循環更新
數據庫初始化
# service mysqld stop
# cd /usr/local/mysql
# ./scripts/mysql_install_db --user=mysql --datadir=/database/mydata
# service mysqld start
第二臺服務器設置(10.0.199.2)
auto_increment_increment = 2 # 數據表記錄的自增量,通常等於服務器的數量
auto_increment_offset = 2 # 數據表記錄每次的遞增量,第一臺爲1,第二臺爲2,...
sync_binlog = 0 # 二進制日誌寫入磁盤的方式(1表示當即寫入磁盤 0表示先緩存再寫入磁盤)
replicate_same_server_id = 0 # 防止mysql循環更新
數據庫初始化
# service mysqld stop
# cd /usr/local/mysql
# ./scripts/mysql_install_db --user=mysql --datadir=/database/mydata
# service mysqld start
10.0.199.1做主服務器 :
主:mysql> grant replication slave on *.* to 'repuser'@'10.0.199.2' identified by 'aix ocm';
mysql> flush privileges;
從:mysql> change master to master_host='10.0.199.1',master_user='repuser',
master_password='aixocm',master_auto_position=1;
mysql> start slave;
mysql> show slave status\G
10.0.199.2做主服務器:
主:mysql> grant replication slave on *.* to 'admin'@'10.0.199.1' identified by 'aixocm';
mysql> flush privileges;
從:mysql> change master to master_host='10.0.199.2',master_user='admin',
master_password='aixocm',master_auto_position=1;
mysql> start slave;
mysql> show slave status\G
測試:雙服務器上都插入數據或者更新數據,查看對方服務器數據是否有改變。