數據庫在任何業務中都是最重要的環節之一,這就對數據庫架構提出的較高的要求。單點數據庫永遠不該該出如今生產環境,咱們已經目擊過太多因爲單點、備份缺失形成的損失,因此,搭建高可用 MySQL 集羣是很是有必要的。mysql
搭建集羣有如下幾點好處:sql
要說缺點,有如下幾點:數據庫
總的說,集羣是必定要搭建的,誰敢把本身的數據跑在一個隨時會有風險的數據庫上呢。接下來我會以幾篇文章介紹怎麼從簡單地主備模式到高可用架構。本節主要介紹如何搭建 MySQL 主備,注重操做,不會有太多理論講解。segmentfault
在兩臺機器分別啓動 MySQL 實例, MySQL 搭建方式能夠參考 MySQL 安裝(二進制版)服務器
IP | 系統 | 端口 | MySQL版本 | 節點 |
---|---|---|---|---|
192.168.41.83 | Centos6.8 | 3306 | 5.7.20 | Master |
192.168.41.72 | Centos6.8 | 3306 | 5.7.20 | Salve |
關鍵配置:架構
Master:socket
[client] port = 3306 default-character-set=utf8mb4 socket = /data/mysql_db/mysql_seg_3306/mysql.sock [mysqld] datadir = /data/mysql_db/mysql_seg_3306 basedir = /usr/local/mysql57 tmpdir = /tmp socket = /data/mysql_db/mysql_seg_3306/mysql.sock pid-file = /data/mysql_db/mysql_seg_3306/mysql.pid skip-external-locking = 1 skip-name-resolve = 1 port = 3306 server_id = 833306 default-storage-engine = InnoDB character-set-server = utf8mb4 default_password_lifetime=0 #### log #### log_timestamps=system log_bin = /data/mysql_log/mysql_seg_3306/mysql-bin log_bin_index = /data/mysql_log/mysql_seg_3306/mysql-bin.index binlog_format = row relay_log_recovery=ON relay_log=/data/mysql_log/mysql_seg_3306/mysql-relay-bin relay_log_index=/data/mysql_log/mysql_seg_3306/mysql-relay-bin.index log_error = /data/mysql_log/mysql_seg_3306/mysql-error.log #### replication #### replicate_wild_ignore_table = information_schema.%,performance_schema.%,sys.% #### semi sync replication settings ##### plugin_dir=/usr/local/mysql57/lib/plugin plugin_load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so" loose_rpl_semi_sync_master_enabled = 1 loose_rpl_semi_sync_slave_enabled = 1 loose_rpl_semi_sync_master_timeout = 5000
Salve函數
[client] port = 3306 default-character-set=utf8mb4 socket = /data/mysql_db/mysql_seg_3306/mysql.sock [mysqld] datadir = /data/mysql_db/mysql_seg_3306 basedir = /usr/local/mysql57 tmpdir = /tmp socket = /data/mysql_db/mysql_seg_3306/mysql.sock pid-file = /data/mysql_db/mysql_seg_3306/mysql.pid skip-external-locking = 1 skip-name-resolve = 1 port = 3306 server_id = 723306 read_only=1 default-storage-engine = InnoDB character-set-server = utf8mb4 default_password_lifetime=0 #### log #### log_timestamps=system log_bin = /data/mysql_log/mysql_seg_3306/mysql-bin log_bin_index = /data/mysql_log/mysql_seg_3306/mysql-bin.index binlog_format = row relay_log_recovery=ON relay_log=/data/mysql_log/mysql_seg_3306/mysql-relay-bin relay_log_index=/data/mysql_log/mysql_seg_3306/mysql-relay-bin.index log_error = /data/mysql_log/mysql_seg_3306/mysql-error.log #### replication #### replicate_wild_ignore_table = information_schema.%,performance_schema.%,sys.% #### semi sync replication settings ##### plugin_dir=/usr/local/mysql57/lib/plugin plugin_load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so" loose_rpl_semi_sync_master_enabled = 1 loose_rpl_semi_sync_slave_enabled = 1 loose_rpl_semi_sync_master_timeout = 5000
配置解析性能
datadir
, basedir
, tmpdir
分別爲數據文件位置、數據庫程序安裝位置、臨時文件位置server_id
實例id,注意,同一集羣機器的 server_id 不能相同read_only
是否只讀, 通常在備庫設置log_bin
, log_bin_index
二進制日誌位置、二進制日誌索引文件位置binlog_format
二進制日誌格式,row
表示記錄每條數據變化狀況、statement
表示記錄相關 sql 語句、mixed
表示兩種混用,在搭建集羣的時候建議使用 row
格式,若是是用 sql 語句來同步數據很容易出現數據不一致的狀況relay_log_recovery
slave 宕機後,假如中繼日誌損壞,則從新拉取日誌,爲了保證中繼日誌完整性,建議開啓relay_log
, relay_log_index
中繼日誌以及中繼日誌索引文件位置log_error
錯誤日誌位置replicate_wild_ignore_table
同步時須要忽略的表,這裏咱們忽略了系通通計表,若是出現奇怪的同步失敗狀況,能夠嘗試開啓plugin_dir
插件位置plugin_load
啓動時須要加載的插件loose_rpl_semi_sync_master_enabled
是否開啓無損半同步複製-主庫(建議主備都開啓,方便主備切換)loose_rpl_semi_sync_slave_enabled
是否開啓無損半同步複製-備庫(建議主備都開啓,方便主備切換)咱們假設 Master 是正在使用的數據庫,如今要在線搭建備庫,咱們往 Master 節點插入一些測試數據測試
[mysql@mysql-test-83 ~]$ mydb-test_seg Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 29 Server version: 5.7.21-log MySQL Community Server (GPL) Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. db83-3306>>show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 4 rows in set (0.00 sec) db83-3306>>create database mytest; Query OK, 1 row affected (0.00 sec) db83-3306>>use mytest; Database changed db83-3306>>create table test1( -> id int not null primary key auto_increment, -> name varchar(16) not null default '', -> age int not null default 0 -> ) engine = InnoDb charset = utf8; Query OK, 0 rows affected (0.01 sec) db83-3306>>insert into test1 values (0, 'a', 16), (0, 'b', 17), (0, 'c', 18), (0, 'd', 19); Query OK, 4 rows affected (0.00 sec) Records: 4 Duplicates: 0 Warnings: 0 db83-3306>>select * from test1; +----+------+-----+ | id | name | age | +----+------+-----+ | 1 | a | 16 | | 2 | b | 17 | | 3 | c | 18 | | 4 | d | 19 | +----+------+-----+ 4 rows in set (0.00 sec)
如今咱們的環境以下
咱們建立一個用戶名爲 repl
的用戶,授予 REPLICATION SLAVE
權限專門用來同步
db83-3306>>CREATE USER 'repl'@'%' IDENTIFIED BY 'repl'; Query OK, 0 rows affected (5.01 sec) db83-3306>>GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; Query OK, 0 rows affected (0.00 sec) db83-3306>>flush privileges; Query OK, 0 rows affected (0.00 sec)
經常使用的備份數據的方式有 innobackupex
和 mysqldump
,這裏數據量少,咱們用 mysqldump
進行全備
[mysql@mysql-test-83 ~]$ /usr/local/mysql57/bin/mysqldump -S /data/mysql_db/mysql_seg_3306/mysql.sock -F --opt -R --single-transaction --master-data=2 --default-character-set=utf8 -A > mysql_backup_full.sql
參數解析:
-S
選擇 socket 文件,本機鏈接數據庫能夠用這種方法,也能夠指定 ip、端口進行鏈接-F
開始導出以前刷新日誌--opt
若是有這個參數表示同時激活了 mysqldump 命令的 quick,add-drop-table,add-locks,extended-insert,lock-tables 參數
--quick
表明忽略緩衝輸出,mysqldump 命令直接將數據導出到指定的SQL文件--add-drop-table
就是在每一個 CREATE TABEL
命令以前增長 DROP-TABLE IF EXISTS
語句,防止數據表重名--add-locks
在INSERT數據以前和以後鎖定和解鎖對應的數據表--extended-insert
表示能夠多行插入-R
導出存儲過程以及自定義函數, 若是有用到存儲過程, 須要加這個參數--single-transaction
(innodb)設置事務的隔離級別爲可重複讀,即 REPEATABLE READ
,這樣能保證在一個事務中全部相同的查詢讀取到一樣的數據, 若是所有表都爲 InnoDB 就帶上這個參數,保證數據一致性,備份時不會鎖表。若是有 MyISAM 的表,須要鎖表備份才能保證數據的一致性--lock-all-tables
備份過程加讀鎖, single-transaction
選項和 lock-all-tables
選項是二選一的--master-data=2
記錄當前二進制日誌位置, master_data
取1和取2的區別,只是後者把 change master ...
命令註釋起來了--default-character-set
選擇編碼, 這個選項很是重要, 編碼選不對或者沒有設置很容易形成亂碼-A
表明備份全部的庫數據備份完畢後,把數據文件直接傳輸到 Slave 機器上
[mysql@mysql-test-83 ~]$ ll total 772 -rw-rw-r-- 1 mysql mysql 786921 Nov 17 10:38 mysql_backup_full.sql [mysql@mysql-test-83 ~]$ rsync -avzP mysql_backup_full.sql 192.168.41.72:/home/mysql/
在 Slave 機器上直接執行 sql 文件導入數據
[mysql@mysql-test-72 ~]$ ll mysql_backup_full.sql -rw-rw-r-- 1 mysql mysql 786921 Nov 17 10:38 mysql_backup_full.sql [mysql@mysql-test-72 ~]$ /usr/local/mysql57/bin/mysql -S /data/mysql_db/mysql_seg_3306/mysql.sock < mysql_backup_full.sql
導入完畢,咱們能夠看到數據和 Master 的備份數據一致
db72-3306>>show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | mytest | | performance_schema | | sys | +--------------------+ 5 rows in set (0.00 sec) db72-3306>>use mytest; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed db72-3306>>show tables; +------------------+ | Tables_in_mytest | +------------------+ | test1 | +------------------+ 1 row in set (0.00 sec) db72-3306>>select * from test1; +----+------+-----+ | id | name | age | +----+------+-----+ | 1 | a | 16 | | 2 | b | 17 | | 3 | c | 18 | | 4 | d | 19 | +----+------+-----+ 4 rows in set (0.00 sec)
回到備份文件,咱們從頭部找到 Master 備份時間點的二進制日誌位置
[mysql@mysql-test-72 ~]$ head -30 mysql_backup_full.sql | grep 'CHANGE MASTER TO MASTER_LOG_FILE' -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=154;
MASTER_LOG_FILE
和 MASTER_LOG_POS
就是在 Master 執行 show master status
獲得的二進制位置信息。如今,咱們執行同步命令
-- 重置複製 -- reset slave; -- 同步配置 CHANGE MASTER TO MASTER_HOST='192.168.41.83', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='repl', MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=154; -- 開啓同步 start slave
實際執行結果以下
db72-3306>>CHANGE MASTER TO -> MASTER_HOST='192.168.41.83', -> MASTER_PORT=3306, -> MASTER_USER='repl', -> MASTER_PASSWORD='repl', -> MASTER_LOG_FILE='mysql-bin.000004', -> MASTER_LOG_POS=154; Query OK, 0 rows affected, 2 warnings (0.20 sec) db72-3306>>start slave; Query OK, 0 rows affected (0.01 sec)
查看同步狀態
db72-3306>>show slave status \G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.41.83 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000004 Read_Master_Log_Pos: 154 Relay_Log_File: mysql-relay-bin.000002 Relay_Log_Pos: 320 Relay_Master_Log_File: mysql-bin.000004 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: 154 Relay_Log_Space: 527 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: 833306 Master_UUID: 15958368-e9a0-11e8-a98c-ecb1d77febe4 Master_Info_File: /data/mysql_db/mysql_seg_3306/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates 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 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec) ERROR: No query specified
咱們能夠從 Slave_IO_Running
, Slave_SQL_Running
, Seconds_Behind_Master
這三個參數能夠判斷出同步狀態是否正常
Slave_IO_Running
取 Master 日誌的線程, Yes
爲正在運行Slave_SQL_Running
從日誌恢復數據的線程, Yes
爲正在運行Seconds_Behind_Master
當前數據庫相對於主庫的數據延遲, 這個值是根據二進制日誌的時間戳計算獲得的(秒)從輸出結果能夠看到咱們的同步是正常的,下面咱們來測試一下
2.5 同步測試
在 Master 節點插入新數據
db83-3306>>insert into test1 values(0, 'chengqm', 24); Query OK, 1 row affected (0.00 sec) db83-3306>>select * from test1; +----+---------+-----+ | id | name | age | +----+---------+-----+ | 1 | a | 16 | | 2 | b | 17 | | 3 | c | 18 | | 4 | d | 19 | | 5 | chengqm | 24 | +----+---------+-----+ 5 rows in set (0.00 sec)
備節點檢查數據同步狀態
db72-3306>>select * from test1; +----+---------+-----+ | id | name | age | +----+---------+-----+ | 1 | a | 16 | | 2 | b | 17 | | 3 | c | 18 | | 4 | d | 19 | | 5 | chengqm | 24 | +----+---------+-----+ 5 rows in set (0.00 sec)
能夠看到數據已經同步到備節點,本次主備搭建完成