MySQL主從複製架構使用方法
一. 單個數據庫伺服器的缺點
資料庫伺服器存在單點問題
資料庫伺服器資源無法滿足增長的讀寫請求
高峰時資料庫連線數經常超過上限
二. 如何解決單點問題
增加額外的資料庫伺服器,組建資料庫叢集
同一叢集中的資料庫伺服器需要具有相同的資料
叢集中的任一伺服器宕機後,其它伺服器可以取代宕機伺服器
三. MySQL主從複製架構
1. 主庫將變更寫入到主庫的binlog中
一些MySQL版本並不會開啟二進位制日誌,所以一定要檢查是否開啟
如果剛開始沒有開啟,後面再進行開啟的話,需要重啟資料庫才能生效,而且資料庫的重啟往往會對業務造成很大的影響
儘管二進位制日誌對效能有稍許的影響,所以還是建議大家無論是否使用複製功能,都要開啟Mysql二進位制日誌,因為增量備份也需要二進位制日誌
2. 從庫的IO執行緒在指定位置讀取主庫binlog內容儲存到本地的中繼日誌(Relay Log)中
要完成二進位制日誌的傳輸過程,MySQL會在從伺服器上啟動一個工作執行緒,稱為IO執行緒,這個IO執行緒會跟主資料庫建立一個普通的客戶端連線,然後在主伺服器上啟動一個特殊的二進位制轉儲執行緒稱為binlogdown執行緒
從庫上的IO執行緒通過這個二進位制轉儲執行緒來讀取主庫上的二進位制事件,如果該事件追趕上主庫,則會進入sleep狀態,直到主庫發起訊號通知有新事件產生時,才會被喚醒,relay log的格式和binlog格式是完全相同的,
可以使用mysqlbinlog 來讀取relay log中的內容
3. 從庫的SQL執行緒讀取Relay Log日誌中的內容,並在從庫中重放
sql執行緒所執行的事件,我們可以通過配置選項來決定是否要寫入到從伺服器的二進位制日誌中
目前mysql支援兩種複製型別
- 基於二進位制日誌點的複製
- 基於GTID的複製(Mysql>=5.7推薦使用)
四. MySQL主從配置步驟
1. 配置主從資料庫伺服器引數
有些引數配置後需要資料庫重啟才能生效,為了不影響資料庫的正常使用,我們最好在伺服器上線的同時就把引數都配置好
特別是master伺服器的引數,更應該作為伺服器初始引數來進行配置
master伺服器
log_bin = /data/mysql/sql_log/mysql-bin # 指定mysql的binlog的存放路徑 /data/mysql/sql_log,以及日誌檔名字首mysql-bin , # 如果只是為了啟用binlog,可以不指定存放路徑,預設會存放到mysql的data目錄下,也就是會把日誌和資料檔案存放在一起 # 之所以指定路徑分開存放,是為了提高IO效能,所以還是建議日誌檔案和資料檔案分開存放 server_id = 100 # mysql的複製叢集中通過server_id的值區分不同的伺服器,建議使用伺服器ip的後一段或後兩段的值進行配置,比如192.168.2.100,就設定為100或2100
slave 伺服器
log_bin = /data/mysql/sql_log/mysql-bin
server_id = 101
relay_log = /data/mysql/sql_log/relay-bin # 指定relay_log日誌的存放路徑和檔案字首 ,不指定的話預設以主機名作為字首
read_only = on # 使所有沒有server許可權的使用者,在從伺服器上不能執行寫操作,不論這個使用者是否擁有寫許可權 (mysql5.7 可以使用 super_read_only = on ,限制super使用者也不能在從伺服器上執行寫操作)
skip_slave_start = on # 在slave伺服器重啟時,不會自動啟動複製鏈路。預設情況下slave伺服器重啟後,mysql會自動啟動複製鏈路,如果這個時候存在問題,則主從鏈路會中斷,所以正常情況下,我們應該在伺服器重啟後檢查是否存在問題,然後再手動啟動複製鏈路
# 下面兩個引數是把主從複製資訊儲存到innodb表中,預設情況下主從複製資訊是儲存到檔案系統中的,如果從伺服器宕機,很容易出現檔案記錄和實際同步資訊不同的情況,儲存到表中則可以通過innodb的崩潰恢復機制來保證資料記錄的一致性
master_info_repository = TABLE
relay_log_info_repository = TABLE
2. 在master伺服器上建立用於複製的資料庫賬號
用於IO執行緒連線master伺服器獲取binlog日誌
需要* REPLICATION SLAVE** 許可權
create user 'repl'@'ip段' identified by 'password';
grant replication slave on *.* to 'repl'@'ip段';
3. 備份master伺服器上的資料並初始化 slave伺服器資料
建議主從資料庫伺服器採用相同的MySQL版本
建議使用全庫備份的方式初始化slave資料
採用相同版本的好處
我們可以使用全備的方式來初始化slave資料,還可以避免不同版本之間的差異造成資料庫同步失敗的問題
如果我們使用的主從複製的伺服器mysql版本不同,則一定要注意master上的版本一定要低於slave伺服器,不然同步的時候就可能出現錯誤
由於我們演示過程中的mysql伺服器都是使用的mysql5.7
所以我們可以使用全備的方式進行
mysqldump --master-data=2 -uroot -p -A --single-transaction -R --triggers
4. 啟動基於日誌點的複製鏈路
在slave伺服器上執行
mysql命令
CHANGE MASTER TO
MASTER_HOST= 'master_host_ip',
MASTER_USER= 'repl',
MASTER_PASSWORD = 'password',
MASTER_LOG_FILE='mysql_log_file_name',
MASTER_LOG_POS=xxxxxx;
5. 啟動基於GTID的複製鏈路
GTID:全域性事務ID
GTID可以保證每一個在主上提交的事務,在複製叢集中可以生成一個唯一的ID值,要使用基於GTID的複製,我們要在主從複製的配置檔案中同時加入以下配置項
mysql配置
gtid_mode=on # 是否啟動gtid模式,啟動了此模式會在二進位制日誌中會額外記錄每個事務的GTID識別符號
enforce-gtid-consistency # 強制gtid一致性,用於保證啟動gtid後事務的安全
log-slave-updates = on # mysql5.6一定要啟用引數,5.7可以不啟用
mysql命令
CHANGE MASTER TO
MASTER_HOST= 'master_host_ip',
MASTER_USER= 'repl',
MASTER_PASSWORD = 'password',
MASTER_AUTO_POSITION=1;
GTID複製的限制
無法再使用create table ... select 語句建立表,只能先create表,再insert 資料
無法在事務中使用create temporary table 建立臨時表
無法使用關聯更新同時更新事務表和非事務表
4和5中選一個執行即可
五. mysql主從複製演示
1. 先對主伺服器進行配置
[client]
port = 3306 # 客戶端埠號為3306
socket = /home/mysql/data/mysql.sock
[mysqld]
# skip #
skip_name_resolve = 1
skip-external-locking =1
# GENERAL #
user = mysql # MySQL啟動使用者
default_storage_engine = InnoDB # 新資料表的預設資料表型別
character-set-server = utf8 # #服務端預設編碼(資料庫級別)
socket = /home/mysql/data/mysql.sock
pid_file = /home/mysql/data/mysqld.pid
basedir = /home/mysql #使用該目錄作為根目錄(Mysql安裝目錄);
port = 3306
bind-address = 0.0.0.0
log_error_verbosity = 3
explicit_defaults_for_timestamp = off
#sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
#sql_mode = NO_ENGINE_SUBSTITUTION
# undo log
# innodb_undo_directory = /home.mysql/undo
# innodb_undo_tablespaces = 32
# MyISAM #
key_buffer_size =32M
# SAFETY #
max_allowed_packet = 100M
max_connect_errors = 1000000
sysdate_is_now =1
#innodb = FORCE
#innodb_strict_mode = 1
# Replice #
server-id = 100
relay_log = /home/mysql/sql_log/mysqld-relay-bin
#plugin-load = semisync_master.so
log_slave_updates = on
master_info_repository = TABLE
relay_log_info_repository =TABLE
# gtid_mode = on
# enforce_gtid_consistency =on
# skip-slave-start =1
#rpl_semi_sync_master_enabled = 1
#rpl_semi_sync_master_timeout=200 # 0.2 second
master_info_respository = TABLE
# gtid_mode= on
# enforce_gtid_consistency = on
# skip-slave-start = 1
# DATA STORAGE #
datadir = /home/mysql/data #mysql 資料檔案存放的目錄
tmpdir = /tmp # MySQL存放臨時檔案的目錄
# BINARY LOGGING #
log_bin = /home/mysql/sql_log/mysql-bin
max_binlog_size = 1000M
binlog_format = row
expire_log_days = 7
sync_binlog = 1
# CACHES AND LIMITS #
tmp_table_size = 32M
max_heap_table_size = 32M
query_cache_type = 0
由於主伺服器一直在執行著,在生產環境中主伺服器是很少會重啟的,如果主伺服器重啟,會造成正常的業務訪問的中斷,所以在伺服器啟動之前就啟動了二進位制日誌
這裡不需要重啟主伺服器了,由於主伺服器的預設server_id=1,我們雖然在配置檔案中更改了它的值 ,但實際執行環境中並沒有改變
我們可以檢視一下當前server_id
mysql> show variables like '%server_id%';
可以通過以下命令動態的進行修改
mysql> set global server_id = 100;
2. 再對從伺服器進行配置
[client]
port = 3306 # 客戶端埠號為3306
socket = /home/mysql/data/mysql.sock
[mysqld]
# skip #
skip_name_resolve = 1
skip-external-locking =1
# GENERAL #
user = mysql # MySQL啟動使用者
default_storage_engine = InnoDB # 新資料表的預設資料表型別
character-set-server = utf8 # #服務端預設編碼(資料庫級別)
socket = /home/mysql/data/mysql.sock
pid_file = /home/mysql/data/mysqld.pid
basedir = /home/mysql #使用該目錄作為根目錄(Mysql安裝目錄);
port = 3306
bind-address = 0.0.0.0
log_error_verbosity = 3
explicit_defaults_for_timestamp = off
#sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
#sql_mode = NO_ENGINE_SUBSTITUTION
read_only = on
# undo log
# innodb_undo_directory = /home.mysql/undo
# innodb_undo_tablespaces = 32
# MyISAM #
key_buffer_size =32M
# SAFETY #
max_allowed_packet = 100M
max_connect_errors = 1000000
sysdate_is_now =1
#innodb = FORCE
#innodb_strict_mode = 1
# Replice #
server-id = 101
relay_log = /home/mysql/sql_log/mysqld-relay-bin
#plugin-load = semisync_master.so
log_slave_updates = on
master_info_repository = TABLE
relay_log_info_repository =TABLE
# gtid_mode = on
# enforce_gtid_consistency =on
# skip-slave-start =1
#rpl_semi_sync_master_enabled = 1
#rpl_semi_sync_master_timeout=200 # 0.2 second
master_info_respository = TABLE
# gtid_mode= on
# enforce_gtid_consistency = on
# skip-slave-start = 1
# DATA STORAGE #
datadir = /home/mysql/data #mysql 資料檔案存放的目錄
tmpdir = /tmp # MySQL存放臨時檔案的目錄
# BINARY LOGGING #
log_bin = /home/mysql/sql_log/mysql-bin
max_binlog_size = 1000M
binlog_format = row
expire_log_days = 7
sync_binlog = 1
# CACHES AND LIMITS #
tmp_table_size = 32M
max_heap_table_size = 32M
query_cache_type = 0
修改完從伺服器配置後,重啟mysql伺服器
如果使用的是mysql5.7版本的需要注意
mysql5.7增加了server-uuid值,預設情況下載auto.cnf檔案中,如果是使用的映象的方式安裝,可能大家的uuid一樣 ,所以需要把auto.cnf檔案刪除掉。mysql重啟後會自動重新生成uuid的值,這樣就可以保證不同伺服器上的mysql例項的uuid的值是不一樣的
如果server-uuid的值相同,主從複製會出現問題
以上我們就完成了主從複製的配置,接下來我們要在主伺服器上建立複製賬號
3. 在mysql主伺服器上建立mysql複製賬號
mysql> create user 'dba_repl'@'192.168.2.%' identified by '123456';
mysql> grant replication slave on *.* to 'dba_repl'@'192.168.2.%';
建立好複製賬號以後
4. 通過mysql主伺服器上的全備初始化從伺服器上資料
進行全備
[[email protected] data]# cd /data/db_backup/
[[email protected] db_backup]# mysqldump -uroot -p --master-data=1 --single-transaction --routines --triggers --events --all-databases > all.sql
Enter password:
將其拷貝到從伺服器上
[[email protected] db_backup]# scp all.sql [email protected]:/root
在從伺服器上恢復備份進行初始化
[[email protected] ~]# mysql -uroot -p < all.sql
初始化完成後,準備
5. 從伺服器進行基於日誌點的複製鏈路的配置
mysql> change master to master_host='192.168.2.100',
-> master_user='dba_repl',
-> master_password='123456',
->MASTER_LOG_FILE='mysql-bin.000017',MASTER_LOG_POS=663;
MASTER_LOG_FILE和MASTER_LOG_POS的值從全備檔案中的CHANGE MASTER中獲取
以上覆制鏈路的配置完成
啟動slave
mysql> start slave;
檢查是否啟動成功狀態
mysql> show slave status \G;
顯示
Relay_Master_Log_File: mysql-bin.000017
Slave_IO_Running:Yes
Slave_SQL_Running: Yes
說明啟動成功了,可以在主伺服器上插入資料,在從服務上檢視資料是否同步過來了
六. 主從複製的一些缺點
雖然主從複製,增加了一個數據庫副本,從資料庫和主資料庫的資料最終會是一致的
之所以說是最終一致,因為mysql複製是非同步的,正常情況下主從複製資料之間會有一個微小的延遲
通過這個資料庫副本看似解決了資料庫單點問題,但並不完美
因為這種架構下,如果主伺服器宕機,需要手動切換從伺服器,業務中斷不能忍受,不能滿足應用高可用的要求
如果才能解決當master伺服器宕機後,前端應用自動切換連結呢?
下節再進行學習