----本文大綱
-
簡介
-
資源配置
-
拓撲圖
-
實現過程
一、簡介
MMM 即Master-Master Replication Manager for MySQL(mysql主主復制管理器)關於mysql主主復制配置的監控、故障轉移和管理的一套可伸縮的腳本套件(在任何時候只有一個節點可以被寫 入),這個套件也能對居於標准的主從配置的任意數量的從服務器進行讀負載均衡,所以你可以用它來在一組居於復制的服務器啟動虛擬ip,除此之外,它還有實 現數據備份、節點之間重新同步功能的腳本。MySQL本身沒有提供replication failover的解決方案,通過MMM方案能實現服務器的故障轉移,從而實現mysql的高可用。MMM不僅能提供浮動IP的功能,更可貴的是如果當前 的主服務器掛掉后,會將你后端的從服務器自動轉向新的主服務器進行同步復制,不用手工更改同步配置。這個方案是目前比較成熟的解決方案。
優點:安全性、穩定性高,可擴展性好,高可用,當主服務器掛掉以后,另一個主立即接管,其他的從服務器能自動切換,不用人工干預。
缺點:至少三個節點,對主機的數量有要求,需要實現讀寫分離,對程序來說是個挑戰。
主從復制原理:
第一步是在主庫上記錄二進制日志(稍后介紹如何設置)。在每次准備提交事務完成數 據更新前,主庫將數據更新的事件記錄到二進制日志中。MySQL會按事務提交的順序 而非每條語句的執行順序來記錄二進制日志。在記錄二進制日志后,主庫會告訴存儲引 擎可以提交事務了。 _
下一步,備庫將主庫的二進制日志復制到其本地的中繼日志中。首先,備庫會啟動一個 工作線程,稱為I/O線程,I/O線程跟主庫建立一個普通的客戶端連接,然后在主庫上啟 動一個特殊的二進制轉儲(binhg dump、線程(該線程沒有對應的SQL命令),這個二 進制轉儲線程會讀取主庫上二進制日志中的事件。它不會對事件進行輪詢。如果該線程 追趕上了主庫,它將進入睡眠狀態,直到主庫發送信號量通知其有新的事件產生時才會 被喚醒,備庫I/O線程會將接收到的事件記錄到中繼日志中。
備庫的SQL線程執行最后一步,該線程從中繼日志中讀取事件並在備庫執行,從而實現 備庫數據的更新。當SQL線程追趕上I/O線程時,中繼日志通常已經在系統緩存中,所 以中繼日志的開銷很低。SQL線程執行的事件也可以通過配置選項來決定是否寫入其自 己的二進制日志中,它對於我們稍后提到的場景非常有用。這種復制架構實現了獲取事件和重放事件的解耦,允許這兩個過程異步進行。也就是說 I/o線程能夠獨立於SQL線程之外工作。但這種架構也限制了復制的過程,其中最重要 的一點是在主庫上並發運行的査詢在備庫只能串行化執行,因為只有一個SQL線程來重 放中繼日志中的事件。后面我們將會看到,這是很多工作負載的性能瓶頸所在。雖然有 一些針對該問題的解決方案,但大多數用戶仍然受制於單線程。
二、資源配置
-
主機屬性
系統 | 名字 | 角色 | 主機名 | ip地址 | 關系 |
Centos6.5x86_64 | DB1 | Master | essun.mariadb1.com | 192.168.1.109 | 與DB2互為主從 |
Centos6.5x86_64 | DB2 | Master | essun.mariadb2.com | 192.168.1.112 | 與DB1互為主從 |
Centos6.5x86_64 | DB3 | Slave | essun.mariadb3.com | 192.168.1.113 | DB1的從庫 |
Centos6.5x86_64 | Monitor | Monitor | essun.monitor.com | 192.168.1.116 | 監控所有主機 |
-
虛擬ip(VIP)
DB1 192.168.1.109 192.168.1.24
DB2 192.168.1.112 192.168.1.24,192.168.1.22
DB3 192.168.1.113 192.168.1.23
三、拓撲圖
要在MySQL 5.6中使用復制功能,其服務配置段[mysqld]中於少應該定義如下選項:
binlog-format:二進制日志的格式,有row、statement和mixed幾種類型;以下binlog-format的詳細介紹: 從 MySQL 5.1.12 開始,可以用以下三種模式來實現:基於SQL語句的復制(statement-based replication, SBR),基於行的復制(row-based replication, RBR),混合模式復制(mixed-based replication, MBR)。相應地,binlog的格式也有三種:STATEMENT,ROW,MIXED。MBR 模式中,SBR 模式是默認的。 在運行時可以動態低改變binlog的格式,除了以下幾種情況: 存儲過程或者觸發器中間 啟用了NDB 當前會話試用 RBR 模式,並且已打開了臨時表 如果binlog采用了 MIXED 模式,那么在以下幾種情況下會自動將binlog的模式由 SBR 模式改成 RBR 模式。 當DML語句更新一個NDB表時 當函數中包含 UUID() 時 2個及以上包含 AUTO_INCREMENT 字段的表被更新時 行任何 INSERT DELAYED 語句時 用 UDF 時 視圖中必須要求使用 RBR 時,例如創建視圖是使用了 UUID() 函數 設定主從復制模式的方法非常簡單,只要在以前設定復制配置的基礎上,再加一個參數: binlog_format="STATEMENT" #binlog_format="ROW" #binlog_format="MIXED" 當然了,也可以在運行時動態修改binlog的格式。例如 mysql> SET SESSION binlog_format = 'STATEMENT'; mysql> SET SESSION binlog_format = 'ROW'; mysql> SET SESSION binlog_format = 'MIXED'; mysql> SET GLOBAL binlog_format = 'STATEMENT'; mysql> SET GLOBAL binlog_format = 'ROW'; mysql> SET GLOBAL binlog_format = 'MIXED'; 現在來比較以下 SBR 和 RBR 2中模式各自的優缺點: SBR 的優點: 歷史悠久,技術成熟 binlog文件較小 binlog中包含了所有數據庫更改信息,可以據此來審核數據庫的安全等情況 binlog可以用於實時的還原,而不僅僅用於復制 主從版本可以不一樣,從服務器版本可以比主服務器版本高 SBR 的缺點: 不是所有的UPDATE語句都能被復制,尤其是包含不確定操作的時候。 調用具有不確定因素的 UDF 時復制也可能出問題 使用以下函數的語句也無法被復制: * LOAD_FILE() * UUID() * USER() * FOUND_ROWS() * SYSDATE() (除非啟動時啟用了 --sysdate-is-now 選項) INSERT ... SELECT 會產生比 RBR 更多的行級鎖 復制需要進行全表掃描(WHERE 語句中沒有使用到索引)的 UPDATE 時,需要比 RBR 請求更多的行級鎖 對於有 AUTO_INCREMENT 字段的 InnoDB表而言,INSERT 語句會阻塞其他 INSERT 語句 對於一些復雜的語句,在從服務器上的耗資源情況會更嚴重,而 RBR 模式下,只會對那個發生變化的記錄產生影響 存儲函數(不是存儲過程)在被調用的同時也會執行一次 NOW() 函數,這個可以說是壞事也可能是好事 確定了的 UDF 也需要在從服務器上執行 數據表必須幾乎和主服務器保持一致才行,否則可能會導致復制出錯 執行復雜語句如果出錯的話,會消耗更多資源 RBR 的優點: 任何情況都可以被復制,這對復制來說是最安全可靠的 和其他大多數數據庫系統的復制技術一樣 多數情況下,從服務器上的表如果有主鍵的話,復制就會快了很多 復制以下幾種語句時的行鎖更少: * INSERT ... SELECT * 包含 AUTO_INCREMENT 字段的 INSERT * 沒有附帶條件或者並沒有修改很多記錄的 UPDATE 或 DELETE 語句 執行 INSERT,UPDATE,DELETE 語句時鎖更少 從服務器上采用多線程來執行復制成為可能 RBR 的缺點: binlog 大了很多 復雜的回滾時 binlog 中會包含大量的數據 主服務器上執行 UPDATE 語句時,所有發生變化的記錄都會寫到 binlog 中,而 SBR 只會寫一次,這會導致頻繁發生 binlog 的並發寫問題 UDF 產生的大 BLOB 值會導致復制變慢 無法從 binlog 中看到都復制了寫什么語句 當在非事務表上執行一段堆積的SQL語句時,最好采用 SBR 模式,否則很容易導致主從服務器的數據不一致情況發生 另外,針對系統庫 mysql 里面的表發生變化時的處理規則如下: 如果是采用 INSERT,UPDATE,DELETE 直接操作表的情況,則日志格式根據 binlog_format 的設定而記錄 如果是采用 GRANT,REVOKE,SET PASSWORD 等管理語句來做的話,那么無論如何都采用 SBR 模式記錄 注:采用 RBR 模式后,能解決很多原先出現的主鍵重復問題。 需要注意的是:當設置隔離級別為READ-COMMITED必須設置二進制日志格式為ROW,現在MySQL官方認為STATEMENT這個已經不再適合繼續使用;但mixed類型在默認的事務隔離級別下,可能會導致主從數據不一致; log-slave-updates、gtid-mode、enforce-gtid-consistency、report-port和report-host:用於啟動GTID及滿足附屬的其它需求; master-info-repository和relay-log-info-repository:啟用此兩項,可用於實現在崩潰時保證二進制及從服務器安全的功能; sync-master-info:啟用之可確保無信息丟失; slave-paralles-workers:設定從服務器的SQL線程數;0表示關閉多線程復制功能; binlog-checksum、master-verify-checksum和slave-sql-verify-checksum:啟用復制有關的所有校驗功能; binlog-rows-query-log-events:啟用之可用於在二進制日志記錄事件相關的信息,可降低故障排除的復雜度; log-bin:啟用二進制日志,這是保證復制功能的基本前提;如果主服務器運行時沒有啟用--logs-bin,SHOW MASTER STATUS或mysqldump --master-data顯示的日 志名和位置值為空。在這種情況下,當以后指定從服務器的日志文件和位置時需要使用的值為空字符串('') server-id:同一個復制拓撲中的所有服務器的id號必須唯一;這些ID值能唯一識別復制服務器群集中的每個服務器實例
四、實現過程
1、配置DB1
修改配置文件/etc/my.cnf,添加如下語句
server-id=1 log_bin=/mariadb/data/mysql-bin binlog_format=row log-slave-updates sync_binlog=1 auto_increment_increment=2 # 默認地,AUTO_INCREMENT 的開始值是 1,每條新記錄遞增 1。 auto_increment_offset=1
授權用戶
MariaDB [(none)]> grant replication slave,replication client on *.* to 'repluser'@'192.168.1.112' identified by 'replpass'; Query OK, 0 rows affected (0.12 sec) MariaDB [(none)]> grant replication slave,replication client on *.* to 'repluser'@'192.168.1.113' identified by 'replpass'; Query OK, 0 rows affected (0.00 sec)
查看binlog日志標記
MariaDB [(none)]> show master status; +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000003 | 756 | | | +------------------+----------+--------------+------------------+ 1 row in set (0.00 sec)
2、配置DB2
修改配置文件/etc/my.cnf,添加如下語句
log-bin=mysql-bin binlog_format=ROW log-slave-updates sync_binlog=1 auto_increment_increment=2 auto_increment_offset=2 server-id=2
授權用戶
MariaDB [(none)]> grant replication slave,replication client on *.* to 'repluser'@'192.168.1.109' identified by 'replpass'; Query OK, 0 rows affected (0.15 sec)
查看binlog日志標記
MariaDB [(none)]> show master status; +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000007 | 548 | | | +------------------+----------+--------------+------------------+ 1 row in set (0.00 sec)
連接DB1
MariaDB [(none)]> show master status; +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000007 | 548 | | | +------------------+----------+--------------+------------------+ 1 row in set (0.00 sec)
3、配置DB3
修改配置文件/etc/my.cnf添加如下語句
server-id=3 log-bin=mysql-bin log-slave-updates
relay-log=relay-log-bin
連接DB1
MariaDB [(none)]> change master to master_host='192.168.1.109',master_user='repluser',master_password='replpass',master_log_file='mysql-bin.000003',master_log_pos=756; Query OK, 0 rows affected (0.03 sec) MariaDB [(none)]> start slave; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.1.109 Master_User: repluser Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000003 Read_Master_Log_Pos: 756 Relay_Log_File: relay-log-bin.000002 Relay_Log_Pos: 535 Relay_Master_Log_File: mysql-bin.000003 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: 756 Relay_Log_Space: 830 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: Yes Master_SSL_CA_File: /etc/slave/cacert.pem Master_SSL_CA_Path: Master_SSL_Cert: /etc/slave/mysql.crt Master_SSL_Cipher: Master_SSL_Key: /etc/slave/mysql.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_SSL_Crl: /etc/slave/cacert.pem Master_SSL_Crlpath: Using_Gtid: No Gtid_IO_Pos: 1 row in set (0.00 sec)
DB1連接DB2
MariaDB [(none)]> change master to master_host='192.168.1.112',master_user='repluser',master_password='replpass',master_log_file='mysql-bin.000007',master_log_pos=548; Query OK, 0 rows affected (0.03 sec) MariaDB [(none)]> start slave; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.1.112 Master_User: repluser Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000007 Read_Master_Log_Pos: 548 Relay_Log_File: essun-relay-bin.000002 Relay_Log_Pos: 535 Relay_Master_Log_File: mysql-bin.000007 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: 548 Relay_Log_Space: 832 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_SSL_Crl: Master_SSL_Crlpath: Using_Gtid: No Gtid_IO_Pos: 1 row in set (0.00 sec)
4、測試
在DB2中建立一個數據庫testdb
MariaDB [(none)]> change master to master_host='192.168.1.112',master_user='repluser',master_password='replpass',master_log_file='mysql-bin.000007',master_log_pos=548; Query OK, 0 rows affected (0.03 sec) MariaDB [(none)]> start slave; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.1.112 Master_User: repluser Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000007 Read_Master_Log_Pos: 548 Relay_Log_File: essun-relay-bin.000002 Relay_Log_Pos: 535 Relay_Master_Log_File: mysql-bin.000007 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: 548 Relay_Log_Space: 832 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_SSL_Crl: Master_SSL_Crlpath: Using_Gtid: No Gtid_IO_Pos: 1 row in set (0.00 sec)
在DB1中對testdb,插入一條數據
MariaDB [testdb]> insert t1 values ('tom',24); Query OK, 1 row affected (0.01 sec)
在DB3中查看結果
MariaDB [(none)]> select * from testdb.t1; +------+-----+ | name | age | +------+-----+ | tom | 24 | | king | 24 | +------+-----+ 2 rows in set (0.00 sec) MariaDB [(none)]>
5、安裝mysql-mmm-agent
在DB1~3上安裝mysql-mmmo-agent
注:mysql-mmm-agent是在epel源中,所以要下載EPEL源安裝包即可http://download.fedoraproject.org/pub/epel/6/i386/repoview/epel-release.html
下載對應的版本就可以的。
#rpm -ivh epel-release-6-8.noarch.rpm yum -y install mysql-mmm-agent
每一個節點都要安裝
在每一個節點上要給Monitor授權用戶
MariaDB [(none)]> GRANT SUPER, REPLICATION CLIENT, PROCESS ON *.* TO 'mmm_agent'@'192.168.1.116' IDENTIFIED BY '123456'; Query OK, 0 rows affected (0.01 sec) MariaDB [(none)]> GRANT REPLICATION CLIENT ON *.* TO 'mmm_monitor'@'192.168.1.116' IDENTIFIED BY '123456'; Query OK, 0 rows affected (0.01 sec) MariaDB [(none)]> GRANT REPLICATION CLIENT ON *.* TO 'repluser'@'192.168.1.116' IDENTIFIED BY 'replpass'; Query OK, 0 rows affected (0.01 sec)
6、在Monitor節點上要安裝
#yum -y install mysql-mmm*
此包同樣也在epel源中
7、在Monitor端的設置/etc/mysql-mmm/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 repluser #復制用戶 replication_password replpass #復制密碼 agent_user mmm_agent #代理用戶 agent_password 123456 #代理用戶的密碼 </host> <host db1> ip 192.168.1.109 mode master peer db2 </host> <host db2> ip 192.168.1.112 mode master peer db1 </host> <host db3> ip 192.168.1.113 mode slave </host> <role writer> hosts db1, db2 ips 192.168.1.24 mode exclusive #排它 </role> <role reader> hosts db2, db3 ips 192.168.1.22, 192.168.1.23 mode balanced #均衡 </role>
將此文件分發到各DB1~3中的/etc/mysql-mmm/下
8、每一個DB中都會有mmm_agent的配置文件,編輯mmm_agent.conf
在數據庫服務器上,還有一個mmm_agent.conf需要修改,其內容是:
include mmm_common.conf # The 'this' variable refers to this server. Proper operation requires # that 'this' server (db1 by default), as well as all other servers, have the # proper IP addresses set in mmm_common.conf. this db2
第一行表示:將之前Monitor中的mmm_common.conf文件載入到此文件中,供此文件中的參數設用。
最后一行標記此主機的角色(引用mmm_common.conf中的host段)在不同的數據庫服務器上要分別改為db1和db3否則代理就會無法啟動。
9、編輯mmm_mon.confg
在Monitor上,修改mmm_mon.conf文件,修改后內容為:
include mmm_common.conf <monitor> ip 192.168.1.116 #當前monitor主機地址 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.109, 192.168.1.112 #真實DB地址 auto_set_online 10 # The kill_host_bin does not exist by default, though the monitor will # throw a warning about it missing. See the section 5.10 "Kill Host # Functionality" in the PDF documentation. # # kill_host_bin /usr/libexec/mysql-mmm/monitor/kill_host # </monitor> <host default> monitor_user mmm_monitor #監控DB的用戶名 monitor_password 123456 #密碼 </host> debug 0 #關閉debug功能,如果程序無法監控得到,可以使用debug 1查錯
10、啟動MMM
在各DB端啟動mmm-agent
#cd /etc/init.d/ # chkconfig mysql-mmm-monitor on # service mysql-mmm-monitor start
在Monitor端啟動監控程序
#cd /etc/init.d/ # chkconfig mysql-mmm-monitor on # service mysql-mmm-monitor start
過幾秒鍾,就可以使用mmm_control show查看在線監控端(DB)了
[root@essun ~]# service mysql-mmm-monitor status mmm_mond (pid 5395) is running... [root@essun ~]# mmm_control show db1(192.168.1.109) master/ONLINE. Roles: db2(192.168.1.112) master/ONLINE. Roles: reader(192.168.1.22), writer(192.168.1.24) db3(192.168.1.113) slave/ONLINE. Roles: reader(192.168.1.23)
注:可以使用
[root@essun ~]# mmm_control --help Invalid command '--help' Valid commands are: help - show this message ping - ping monitor show - show status checks [<host>|all [<check>|all]] - show checks status set_online <host> - set host <host> online set_offline <host> - set host <host> offline mode - print current mode. set_active - switch into active mode. set_manual - switch into manual mode. set_passive - switch into passive mode. move_role [--force] <role> <host> - move exclusive role <role> to host <host> (Only use --force if you know what you are doing!) set_ip <ip> <host> - set role with ip <ip> to host <host>
查看mmm_control的可用參數
11、模擬DB2下線
Monitor當前狀態
讓DB2下線,當前可寫主機是db1,db3
db2沒有下線之前還可以讀寫,當下線之后,可寫的切換到DB1上了,所有讀的都到了db3上了
當DB2重新上線后的情況如下
注:DB1、DB同時只能一有個寫,一個讀!
========================================== Mariadb高可用演示完畢========================