復制的體系結構有以下一些基本原則:
(1) 每個slave只能有一個master;
(2) 每個slave只能有一個唯一的服務器ID;
(3) 每個master可以有很多slave;
(4) 如果你設置log_slave_updates,slave可以是其它slave的master,從而擴散master的更新。
MySQL不支持多主服務器復制(Multimaster Replication)——即一個slave可以有多個master。但是,通過一些簡單的組合,我們卻可以建立靈活而強大的復制體系結構。
在實際應用場景中,MySQL復制90%以上都是一個Master復制到一個或者多個Slave的架構模式,主要用於讀壓力比較大的應用的數據庫端廉價擴展解決方案。因為只要Master和Slave的壓力不是太大(尤其是Slave端壓力)的話,異步復制的延時一般都很少很少。尤其是自從Slave端的復制方式改成兩個線程處理之後,更是減小了Slave端的延時問題。
當slave增加到一定數量時,slave對master的負載以及網絡帶寬都會成為一個嚴重的問題
這種結構雖然簡單,但是,它卻非常靈活,足夠滿足大多數應用需求。一些建議:
(1) 不同的slave扮演不同的作用(例如使用不同的索引,或者不同的存儲引擎);
(2) 用一個slave作為備用master,只進行復制;
(3) 用一個遠程的slave,用於災難恢復;
這樣搭建復制環境之後,難道不會造成兩台MySQL之間的循環復制麼?實際上MySQL自己早就想到了這一點,所以在MySQL的BinaryLog中記錄了當前MySQL的server-id,而且這個參數也是我們搭建MySQLReplication的時候必須明確指定,而且Master和Slave的server-id參數值比需要不一致才能使MySQLReplication搭建成功。一旦有了server-id的值之後,MySQL就很容易判斷某個變更是從哪一個MySQLServer最初產生的,所以就很容易避免出現循環復制的情況。
主動的Master-Master復制有一些特殊的用處。例如,地理上分布的兩個部分都需要自己的可寫的數據副本。這種結構最大的問題就是更新沖突。假設一個表只有一行(一列)的數據,其值為1,如果兩個服務器分別同時執行如下語句:
在第一個服務器上執行:
mysql> UPDATE tbl SET col=col + 1;
在第二個服務器上執行:
mysql> UPDATE tbl SET col=col * 2;
那麼結果是多少呢?一台服務器是4,另一個服務器是3,但是,這並不會產生錯誤。
實際上,MySQL並不支持其它一些DBMS支持的多主服務器復制(Multimaster Replication),這是MySQL的復制功能很大的一個限制(多主服務器的難點在於解決更新沖突),但是,如果你實在有這種需求,你可以采用MySQL Cluster,以及將Cluster和Replication結合起來,可以建立強大的高性能的數據庫平台。但是,可以通過其它一些方式來模擬這種多主服務器的復制。
在有些應用場景中,可能讀寫壓力差別比較大,讀壓力特別的大,一個Master可能需要上10台甚至更多的Slave才能夠支撐注讀的壓力。這時候,Master就會比較吃力了,因為僅僅連上來的SlaveIO線程就比較多了,這樣寫的壓力稍微大一點的時候,Master端因為復制就會消耗較多的資源,很容易造成復制的延時。
遇到這種情況如何解決呢?這時候我們就可以利用MySQL可以在Slave端記錄復制所產生變更的BinaryLog信息的功能,也就是打開—log-slave-update選項。然後,通過二級(或者是更多級別)復制來減少Master端因為復制所帶來的壓力。也就是說,我們首先通過少數幾台MySQL從Master來進行復制,這幾台機器我們姑且稱之為第一級Slave集群,然後其他的Slave再從第一級Slave集群來進行復制。從第一級Slave進行復制的Slave,我稱之為第二級Slave集群。如果有需要,我們可以繼續往下增加更多層次的復制。這樣,我們很容易就控制了每一台MySQL上面所附屬Slave的數量。這種架構我稱之為Master-Slaves-Slaves架構
這種多層級聯復制的架構,很容易就解決了Master端因為附屬Slave太多而成為瓶頸的風險,當然,如果條件允許,我更傾向於建議大家通過拆分成多個Replication集群來解決
上述瓶頸問題。畢竟Slave並沒有減少寫的量,所有Slave實際上仍然還是應用了所有的數據變更操作,沒有減少任何寫IO。相反,Slave越多,整個集群的寫IO總量也就會越多,我們沒有非常明顯的感覺,僅僅只是因為分散到了多台機器上面,所以不是很容易表現出來。
此外,增加復制的級聯層次,同一個變更傳到最底層的Slave所需要經過的MySQL也會更多,同樣可能造成延時較長的風險。
而如果我們通過分拆集群的方式來解決的話,可能就會要好很多了,分拆集群也需要更復雜的技術和更復雜的應用系統架構。
級聯復制在一定程度上面確實解決了Master因為所附屬的Slave過多而成為瓶頸的問題,但是他並不能解決人工維護和出現異常需要切換後可能存在重新搭建Replication的問題。這樣就很自然的引申出了DualMaster與級聯復制結合的Replication架構,我稱之為Master-Master-Slaves架構
和Master-Slaves-Slaves架構相比,區別僅僅只是將第一級Slave集群換成了一台單獨的Master,作為備用Master,然後再從這個備用的Master進行復制到一個Slave集群。
這種DualMaster與級聯復制結合的架構,最大的好處就是既可以避免主Master的寫入操作不會受到Slave集群的復制所帶來的影響,同時主Master需要切換的時候也基本上不會出現重搭Replication的情況。但是,這個架構也有一個弊端,那就是備用的Master有可能成為瓶頸,因為如果後面的Slave集群比較大的話,備用Master可能會因為過多的SlaveIO線程請求而成為瓶頸。當然,該備用Master不提供任何的讀服務的時候,瓶頸出現的可能性並不是特別高,如果出現瓶頸,也可以在備用Master後面再次進行級聯復制,架設多層Slave集群。當然,級聯復制的級別越多,Slave集群可能出現的數據延時也會更為明顯,所以考慮使用多層級聯復制之前,也需要評估數據延時對應用系統的影響。
分為同步復制和異步復制,實際復制架構中大部分為異步復制。 復制的基本過程如下:
1).Slave上面的IO進程連接上Master,並請求從指定日志文件的指定位置(或者從最開始的日志)之後的日志內容;
2).Master接收到來自Slave的IO進程的請求後,通過負責復制的IO進程根據請求信息讀取制定日志指定位置之後的日志信息,返回給Slave 的IO進程。返回信息中除了日志所包含的信息之外,還包括本次返回的信息已經到Master端的bin-log文件的名稱以及bin-log的位置;
3).Slave的IO進程接收到信息後,將接收到的日志內容依次添加到Slave端的relay-log文件的最末端,並將讀取到的Master端的 bin-log的文件名和位置記錄到master-info文件中,以便在下一次讀取的時候能夠清楚的告訴Master“我需要從某個bin-log的哪個位置開始往後的日志內容,請發給我”;
4).Slave的Sql進程檢測到relay-log中新增加了內容後,會馬上解析relay-log的內容成為在Master端真實執行時候的那些可執行的內容,然後回放。
主服務器master:192.168.1.30
從服務器slave:192.168.1.25
my.cnf
#bin_log binlog_format=mixed max_binlog_size=200M log_bin=/data/logs/mysql/binarylog/mysql_bin expire_logs_days=7 binlog-ignore-db = mysql,information_schema,performance_schema server_id=1 binlog-do-db=abc
授權
GRANT REPLICATION SLAVE ON abc.* to 'sync'@'192.168.1.30' identified by '123456'
server-id=131 #從服務器ID號,不要和主ID相同 master-host=192.168.1.30 #指定主服務器IP地址 master-user=sync #指定在主服務器上可以進行同步的用戶名 master-password=123456 #密碼 master-port=3306 # 同步所用端口 master-connect-retry=60 #斷點從新連接時間 replicate-ignore-db=information_schema,mysql,performance_schema #屏蔽對mysql庫的同步 replicate-do-db=abc #同步的數據庫的名稱 replicate_do_table = tt #同步的數據表的名稱
授權
change master to master_host='192.168.1.30', master_port=3306, master_user='sync', master_password='123456', master_log_file='mysql_bin.000041', master_log_pos=538;
啟動slave
mysql> start slave; mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.1.30 Master_User: sync Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql_bin.000042 Read_Master_Log_Pos: 120 Relay_Log_File: mysql-relay-bin.000004 Relay_Log_Pos: 283 Relay_Master_Log_File: mysql_bin.000042 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: 120 Relay_Log_Space: 710 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: 7789d104-20d3-11e5-a394-0050563accdf 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 replication單表或多表復制時需注意的幾個問題
1.主庫和從庫的數據庫名必須相同;
2.主庫和從庫的復制可以精確到表,但是在需要更改主庫或從庫的數據結構時需要立刻重啟slave;
3.不能在mysql配置文件裡直接寫入master的配置信息,需要用change master命令來完成;
4.指定replicate_do_db必須在my.cnf裡配置,不能用change master命令來完成;
5.如果不及時清理,日積月累二進制日志文件可能會把磁盤空間占滿,可以在配置文件裡加上expire_logs_days=7,只保留最近7天的日志,建議當slave不再使用時,通過reset slave來取消relaylog;
最後,編寫一shell腳本,用nagios監控slave的兩個“yes”,如發現只有一個或零個“yes”,就表明主從有問題了,發報警短信
MMM(Master-Master replication managerfor Mysql,Mysql主主復制管理器)是一套靈活的腳本程序,基於perl實現,用來對mysql replication進行監控和故障遷移,並能管理mysql Master-Master復制的配置(同一時間只有一個節點是可寫的)。
mmm_mond:監控進程,負責所有的監控工作,決定和處理所有節點角色活動。此腳本需要在監管機上運行
mmm_agentd:運行在每個mysql服務器上的代理進程,完成監控的探針工作和執行簡單的遠端服務設置。此腳本需要在被監管機上運行
mmm_control:一個簡單的腳本,提供管理mmm_mond進程的命令
mysql-mmm的監管端會提供多個虛擬IP(VIP),包括一個可寫VIP,多個可讀VIP,通過監管的管理,這些IP會綁定在可用mysql之上,當某一台mysql宕機時,監管會將VIP遷移至其他mysql。
在整個監管過程中,需要在mysql中添加相關授權用戶,以便讓mysql可以支持監理機的維護。授權的用戶包括一個mmm_monitor用戶和一個mmm_agent用戶,如果想使用mmm的備份工具則還要添加一個mmm_tools用戶。
優點:高可用性,擴展性好,出現故障自動切換,對於主主同步,在同一時間只提供一台數據庫寫操作,保證的數據的一致性
缺點:Monitor節點是單點,可以結合Keepalived實現高可用
monitor 192.168.1.29 master-1 192.168.1.25 master-2 192.168.1.26 slave 1 192.168.1.27 slave 2 192.168.1.28 VIP writer 192.168.0.31 reader 192.168.0.32 reader 192.168.0.33
GRANT REPLICATION SLAVE ON *.* TO 'replication'@'192.168.1.%' IDENTIFIED BY 'replication';
[mysqld] #bin_log binlog_format=mixed max_binlog_size=200M log_bin=/data/logs/mysql/binarylog/mysql_bin expire_logs_days=0 log_slave_updates #當一個主故障,另一個立即接管 sync-binlog=1 #每條自動更新,安全性高,默認是0 #relay_log relay_log = mysql-relay-bin #replicate server_id=1 binlog-do-db=abc #需要記錄二進制日志的數據庫,多個用逗號隔開 binlog-ignore-db=mysql,information_schema,performance_schema #不需要記錄二進制日志的數據庫,多個用逗號隔開 auto_increment_increment=1 #字段一次遞增多少 auto_increment_offset=1 #自增字段的起始值,值設置不同 replicate-do-db=abc #同步的數據庫,多個寫多行 replicate-ignore-db = information_schema #不同步的數據庫,多個寫多行 replicate-ignore-db = mysql #不同步的數據庫,多個寫多行
change master to master_host='192.168.1.26', master_user='replication', master_password='replication', master_log_file='mysql-bin.000006', master_log_pos=120;
[mysqld] #bin_log binlog_format=mixed max_binlog_size=200M log_bin=/data/logs/mysql/binarylog/mysql_bin expire_logs_days=0 log_slave_updates #當一個主故障,另一個立即接管 sync-binlog=1 #每條自動更新,安全性高,默認是0 #relay_log relay_log = mysql-relay-bin #replicate server_id=2 binlog-do-db=abc #需要記錄二進制日志的數據庫,多個用逗號隔開 binlog-ignore-db=mysql,information_schema,performance_schema #不需要記錄二進制日志的數據庫,多個用逗號隔開 auto_increment_increment=1 #字段一次遞增多少 auto_increment_offset=1 #自增字段的起始值,值設置不同 replicate-do-db=abc #同步的數據庫,多個寫多行 replicate-ignore-db = information_schema #不同步的數據庫,多個寫多行 replicate-ignore-db = mysql #不同步的數據庫,多個寫多行
授權
change master to master_host='192.168.1.25', master_user='replication', master_password='replication', master_log_file='mysql-bin.000009', master_log_pos=220;
可能會出現的問題
1、Slave_IO_Running = NO ,Slave I/O: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file', Error_code: 1236
2、Slave_SQL_Running=NO ,Error 'Can't create database 'abc'; database exists' on query. Default database: 'abc'. Query: 'create database abc'
3、授權失敗
主主同步配置完畢,查看同步狀態Slave_IO和Slave_SQL是YES說明主主同步成功
change master to master_host='192.168.1.25', master_user='replication', master_password='replication', master_log_file='mysql-bin.000002', master_log_pos=434;
在slave1和slave2查看如下說明主從復制成功。但是數據沒過來,這是因為主從復制原理只同步配置完後的增刪改記錄,以前的數據是不能同步的,我們可以把主的數據庫備份了,然後再還原
mysql> show slave status \G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.1.25 Master_User: replication Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql_bin.000009 Read_Master_Log_Pos: 410 Relay_Log_File: mysql-relay-bin.000012 Relay_Log_Pos: 283 Relay_Master_Log_File: mysql_bin.000009 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: abc Replicate_Ignore_DB: information_schema,mysql 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: 410 Relay_Log_Space: 725 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: 2 Master_UUID: fc4e74ed-563f-11e5-bff1-000c29ee3b5c 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
CentOS 默認沒有 mysql-mmm 軟件包,官方推薦使用 epel 的網絡源,五台都安裝epel:
rpm -ivh http://mirrors.ustc.edu.cn/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
monitor節點安裝
yum -y install mysql-mmm-monitor
db節點安裝
yum -y install mysql-mmm-agent
db節點授權monitor訪問
GRANT REPLICATIONCLIENT ON *.* TO 'mmm_monitor'@'192.168.1.%' IDENTIFIED BY '123456'; GRANT SUPER,REPLICATION CLIENT, PROCESS ON *.* TO 'mmm_agent'@'192.168.1.%' IDENTIFIED BY '123456';
mmm_common.conf文件(五台相同)
active_master_role writer <host default> cluster_interface eth0 pid_path /var/run/mysql-mmm/mmm_agentd.pid bin_path /usr/libexec/mysql-mmm/ replication_user replication replication_password replication agent_user mmm_agent agent_password agent </host> <host db1> ip 192.168.1.25 mode master peer db2 </host> <host db2> ip 192.168.0.26 mode master peer db1 </host> <host db3> ip 192.168.0.27 mode slave </host> <host db4> ip 192.168.0.28 mode slave </host> <role writer> hosts db1, db2 ips 192.168.1.31 mode exclusive #只有一個host可以writer </role> <role reader> hosts db3, db4 ips 192.168.1.32,192.168.1.33 mode balanced #多個host可以reader </role>
db端 mmm_agent.conf
include mmm_common.conf this db1 #分別修改為本機的主機名,即db1、db2、db3和db4
管理端mmm_mon.conf文件
include mmm_common.conf <monitor> ip 127.0.0.1 pid_path /var/run/mysql-mmm/mmm_mond.pid bin_path /usr/libexec/mysql-mmm status_path /var/lib/mysql-mmm/mmm_mond.status ping_ips 192.168.1.25,192.168.1.26,192.168.1.27,192.168.0.28 #真實數據庫IP,來檢測網絡是否正常 auto_set_online 10 #恢復後自動設置在線的時間 </monitor> <host default> monitor_user mmm_monitor monitor_password monitor </host> debug 0
db代理端啟動
/etc/init.d/mysql-mmm-agent start chkconfigmysql-mmm-agent on
monitor管理端啟動
/etc/init.d/mysql-mmm-monitor start chkconfigmysql-mmm-monitor on
[root@localhost ~]# mmm_control show
參考文章
《MMM 之 MySQL》
《從零開始配置 MySQL MMM》