MySQL主從


MySQL主從

一 主從復制介紹

1.1 什么是主從復制

將主服務器的binlog日志復制到從服務器上執行一遍,達到主從數據的一致狀態,稱之為主從復制。

一句話表示就是,主數據庫做什么,從數據庫就跟着做什么。

1.2 為何要做主從

(1)為實現服務器負載均衡/讀寫分離做鋪墊,提升訪問速度

#1、什么是讀寫分離
有了主從保持數據一致作為大前提,我們便可以可以分離讀寫操作,其中Master負責寫操作的負載,也就是說一切寫的操作都在Master上進行,而讀的操作則分攤到Slave上進行。那么讀寫分離的作用是什么呢?

#2、讀寫分離的作用
先說答案:讀寫分離可以大大提高讀取的效率。

在一般的互聯網應用中,經過一些數據調查得出結論,讀/寫的比例大概在 10:1左右 ,也就是說寫操作非常少,大量的數據操作是集中在讀的操作(如某些應用,像基金凈值預測的網站。其數據的更新都是有管理員更新的,即更新的用戶比較少。而查詢的用戶數 量會非常的多。)
此時我們可以制作一主多從,因為寫操作很少,所以由一個主庫負責即可,而大量的讀操作則分配給多個從庫,這樣占據比例最大的讀操作的壓力就被負載均衡了,因此讀效率會得到了極大的提升,另外,還有一個原因就是:
熟悉DB的研發人員都知道,寫操作涉及到鎖的問題,不管是行鎖還是表鎖還是塊鎖,都是比較降低系統執行效率的事情。我們這樣的分離是把寫操作集中在一個節點上,而讀操作其其他的N個節點上進行,這從另一個方面有效的提高了讀的效率,保證了系統的性能及高可用性。

#3、具體做法
方案一:
就是主庫寫,從庫讀

方案二:
主庫負責寫,還有部分讀,從庫只負責讀,而且是讀操作的主力

即當主服務器比較忙時,部分查詢請求會自動發送到從服務器中,以降低主服務器的工作負荷。

(2)通過復制實現數據的異地備份,保障數據安全

可以定期的將數據從主服務器上復制到從服務器上,這實現了數據的異地備份。
在傳統的備份體制下,是將數據備份在本地。此時備份作業與數據庫服務器運行在同一台設備上,當備份作業運行時就會影響到服務器的正常運行。有時候會明顯的降低服務器的性能。同時,將備份數據存放在本地,也 不是很安全。如硬盤因為電壓等原因被損壞或者服務器被失竊,此時由於備份文件仍然存放在硬盤上,數據庫管理員無法使用備份文件來恢復數據。這顯然會給企業 帶來比較大的損失。

(3)提高數據庫系統的可用性

數據庫復制功能實現了主服務器與從服務器之間數據的同步,增加了數據庫系統的可用性。主庫宕機后,從庫尚可用,即當主服務器出現問題時,數據庫管理員可以馬上讓從服務器作為主服務器,用來數據的更新與查詢服務。然后回過頭來再仔細的檢查主服務器的問題。此時一般數據庫管理員會采用兩種手段。

​  一:從庫臨時取代主庫,只用來讀
主服務器故障之后,雖然從服務器取代了主服務器的位置,但是對於主服務器可以采取的操作仍然做了一些限制,例如仍然只能夠進行數據的查詢,而不能夠進行數據的更新、刪除等操作。這主要是基於從數據的安全性考慮。如現在一些銀行系統的升級,在升級的過程中,只能夠查詢余額而不能夠取錢。這是同樣的道理。

​  二:從庫永久取代主庫,負責讀和寫
從服務器真正變成了主服務器。當從服務器切換為主服務器之后,其地位完全與原先的主服務器相同。此時可以實現對數據的查詢、更新、刪除等操 作。為此就需要做好數據的安全性工作。即數據的安全策略,要與原先的主服務器完全相同。否則的話,就可能會留下一定的安全隱患

1.3 主從復制的原理

整體上來說,復制有3個步驟:

​ (1) master將改變記錄到二進制日志(binary log)中(這些記錄叫做二進制日志事件,binary log events)。
​ (2) slave的io線程將master的binary log events拷貝到它的中繼日志(relay log);

​ (3) slave的sql線程解析中繼日志中的事件並在從庫執行,保持與主庫一致。

復制過程有一個很重要的限制——復制在slave上是串行化的,也就是說master上的並行更新操作不能在slave上並行操作。

詳解如下

# 從庫准備
(1)從庫change master to 時,ip port user password binlog position寫入到master.info進行記錄
(2)從庫 start slave 時,會啟動IO線程和SQL線程

# 同步的過程
1.從庫的IO線程,讀取master.info信息,獲取主庫信息並連接主庫
2.主庫接收從庫的鏈接請求后,會生成一個准備binlog DUMP的線程,來響應從庫
3.主庫一旦有新的日志生成,會發送“信號”給主庫的binlog dump線程,然后binlog dump線程會讀取binlog日志的更新
4.TP(傳送)給從從庫的IO線程
5.IO線程將收到的日志存儲到了TCP/IP 緩存
6.寫入TCP/IP緩存后,立即返回ACK給主庫 ,此時主庫工作完成
7.IO線程更新master.info文件binlog 文件名和postion
8.IO線程將緩存中的數據,存儲到relay-log日志文件,此時io線程工作完成
9.從庫SQL線程讀取relay-log.info文件,獲取到上次執行到的relay-log的位置,作為起點
10.從庫SQL線程基於從步驟9中獲取到的起點,去中繼日志relay-log.000001獲取后續操作,在從庫回放relay-log
11.SQL線程回放完成之后,會更新relay-log.info文件,把當前操作的位置記入,作為下一次操作的起點。
12. relay-log會有自動清理的功能。

1.4 主從復制的日志格式

這里的日志格式就是指二進制日志的三種格式

binlog_format=statement

binlog_format=row

binlog_format=mixed

其中基於row的復制方式更能保證主從庫數據的一致性,但日志量較大,在設置時考慮磁盤的空間問題

1.5 主從復制的方式

MySQL的主從復制有兩種復制方式,分別是異步復制和半同步復制

二 異步復制

2.1 異步復制原理介紹

我們之前介紹的就是異步復制,即客戶端線程提交一個寫操作,寫入主庫的binlog日志后就立即返回,並不需要等待從庫完成同步操作,而主庫的dump線程會監測binlog日志的變量然后主動將更新推送給從庫。

MySQL 主從復制默認是異步的模式。

2.2 異步復制部署

前提:主從數據庫版本一致

2.2.1 主庫停服時制作主從

一、主庫:192.168.15.101

1)在主庫上創建一個用於復制的賬號,並賦予replication slave權限,這里必須 *.* 不能指定庫授權,因為 replication slave 是全局的

mysql> grant replication slave on *.* to 'jason'@'%' identified by '123';
mysql> flush privileges;
  1. 修改主庫配置文件,開啟主庫的Binlog,並設置server-id
[mysqld]
# 節點ID,確保唯一
server-id = 1        

#開啟mysql的binlog日志功能
log-bin = mysql-bin
#控制數據庫的binlog刷到磁盤上去 , 0 不控制,性能最好,1每次事物提交都會刷到日志文件中,性能最差,最安全
sync_binlog = 1     
#binlog日志格式
binlog_format = row   
#binlog過期清理時間
expire_logs_days = 7
#binlog每個日志文件大小
max_binlog_size = 100m
#binlog緩存大小
binlog_cache_size = 4m   
#最大binlog緩存大小
max_binlog_cache_size= 512m         

#不生成日志文件的數據庫,多個忽略數據庫可以用逗號拼接,或者 復制黏貼下述配置項,寫多行
binlog-ignore-db=mysql 

# 表中自增字段每次的偏移量
auto-increment-offset = 1 
# 表中自增字段每次的自增量
auto-increment-increment = 1  
#跳過從庫錯誤
slave-skip-errors = all 

3)重啟主庫

systemctl restart mysql

4)備份主庫,備份時鎖表保證備份一致

mysqldump -uroot -pEgon@123 -A -E -R --triggers --triggers --master-data=2 --single-transaction > /tmp/all.sql

5)將備份文件發送給從庫

scp /tmp/all.sql root@192.168.15.100:/tmp

二、從庫:192.168.15.100

1)測試復制賬號

mysql -ujason -p123 -h 192.168.15.101

2)導入初始數據

 mysql -uroot -pEgon@123 < /tmp/all.sql 

3)修改從庫配置文件,增加server-id,注意這個值是唯一的,要區別於主庫和其他從庫

[mysqld]
server-id = 2

relay-log = mysql-relay-bin
replicate-wild-ignore-table=mysql.%
replicate-wild-ignore-table=test.%
replicate-wild-ignore-table=information_schema.%

# 從庫也可以開啟binlog,但通常關閉
# log-bin=mysql-bin

4)重啟從庫

systemctl restart mysqld

5)配置復制

先去主庫查看一下binlog日志名與位置

然后在從庫進行配置

[root@slave1 ~]# mysql -uroot -pEgon@123 # 登錄然后執行

change master to
master_host='192.168.15.101',  -- 庫服務器的IP
master_port=3306,              -- 主庫端口
master_user='jason', -- 主庫用於復制的用戶
master_password='123', -- 密碼
master_log_file='mysql-bin.000001', -- 主庫日志名
master_log_pos=120; -- 主庫日志偏移量,即從何處開始復制

6)從庫啟動slave線程,並檢查

mysql> start slave;
Query OK, 0 rows affected (0.01 sec)


2.2.2 主庫運行時制作主從

1.准備純凈的從庫環境
主庫:192.168.15.101
從庫:192.168.15.100

2.修改主庫配置文件(略)
3.重啟主庫(略)
4.主庫創建賬號(略)
5.模擬主庫運行,有數據寫入、
for i in `seq 1 1000000`
do 
    mysql -uroot -p123 -e "insert db1.t1 values($i)";
    sleep 1;
done

6.主庫全備數據
#不打點備份(no)
mysqldump -uroot -p123 -A -R --triggers > /tmp/all.sql
#打點備份(yes)
mysqldump -uroot -p123 -A -R --triggers --master-data=2 --single-transaction > /tmp/all.sql

7.將熱備數據傳達從庫
scp /tmp/all.sql 192.168.15.100:/tmp

8.修改從庫配置文件(略)

9.重啟從庫(略)

10.在從庫導入全備數據(導入打點備份,原因如下)
#導入不打點的數據的話,接下來主從,位置點只能去主庫查看 show master status; 而數據在不停地往主庫里插入,該命令查看的只是那一刻binlog的記錄的位置,基於該位置同步數據會丟失所獲得位置點往前一直到全備的數據,以及操作從庫過程中新寫入主庫的數據。

#如果導入的是打點的數據,那么全量備份的起始點可以從備份文件中獲得,從庫可以以此為同步的基准點,去主庫獲取全量備份之后的數據


11.查看sql文件中的位置點(如果是打點備份的話)
該位置即主庫剛剛做完全量備份時,主庫binlog日志所處的位置
[root@jason ~]# head -50 /tmp/all.sql|grep 'MASTER_LOG_POS'
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=129005;

12.從庫配置同步
[root@slave1 ~]# mysql -uroot -pEgon@123 # 登錄然后執行
change master to
master_host='192.168.15.101',
master_port=3306, 
master_user='jason',
master_password='123',
master_log_file='mysql-bin.000001', 
master_log_pos=129005; 

13.開啟SQL線程和IO線程
	start slave;
14.查看主從狀態
	show slave status;

練習:基於上述方式制作雙主同步

2.2.3 主從復制基本故障處理

#清空主從配置
	reset slave all;
(1)IO線程問題
1.檢測網絡:
	[root@db01 ~]# ping 172.16.1.51

2.檢測端口:
	[root@db01 ~]# telnet 172.16.1.51 3307
	#阿里雲機器有的禁ping
	[root@db01 ~]# tcping 172.16.1.51 3306

3.檢測賬號,密碼:
	#根據授權命令
	grant replication slave on *.* to rep@'172.16.1.5%' identified by '123';
	#連接測試
	mysql -urep -p123 -h127.0.0.1 -P 3307

4.查看binlog是否存在
	show master status;

5.反向解析
	#沒有跳過反向解析
	ERROR 1045 (28000): Access denied for user 'root'@'db01' (using password: YES)
	#配置
	skip_name_resolve
(2)SQL線程問題
1.主庫有的數據,從庫沒有
	主庫:a庫
	從庫:沒有a庫
2.從庫有的數據,主庫沒有
	從庫:a庫
	主庫:要創建a庫
3.主庫與從庫數據庫結構有差別

#處理方法一:
	#臨時停止同步
	mysql> stop slave;
	#將同步指針向下移動一個(可重復操作)解決不了根本問題
	mysql> set sql_slave_skip_counter=1;
	#開啟同步
	mysql> start slave;
	
#處理方法二:
	#編輯配置文件
	[root@db01 ~]# vim /etc/my.cnf
	#在[mysqld]標簽下添加以下參數
	slave-skip-errors=1032,1062,1007
        1007:對象已存在

        1032:無法執行DML

        1062:主鍵沖突,或約束沖突
	
#處理方法三:
	1.要求,主從復制之前,主庫和從庫的數據保證一致.
	2.在從庫上設置  只讀:set read-only=1;
	(做讀寫分離時使用,但是做MHA會出現提升為主庫時,主庫只讀,后面會講專門做讀寫分離的Atlas)

2.2.4 延遲從庫

我們說用延時從庫可以做備份,主庫執行刪除的時候,從庫還沒有刪除,可以把表數據拿出來恢復回去
企業中一般會延時3-6小時
(1)延時從庫配置

1)已經有主從的情況下

1.停止主從
	mysql> stop slave;
2.設置延時為180秒
	mysql> CHANGE MASTER TO MASTER_DELAY = 180;
3.開啟主從
	mysql> start slave;
4.查看狀態
	mysql> show slave status \G
	SQL_Delay: 180
5.主庫創建數據,會看到從庫值變化,創建的庫沒有創建
	SQL_Remaining_Delay: 170

2)沒有主從復制的情況下

1.修改主庫,從庫配置文件
	server_id
	開啟binlog

2.保證從庫和主庫的數據一致

3.執行change語句
	change master to
	master_host='172.16.1.50',
	master_user='rep',
	master_password='123',
	master_log_file='mysql-bin.000001',
	master_log_pos=2752,
	master_delay=180;

3)延時從庫停止方法

1.停止主從
mysql> stop slave;

2.設置延時為0
mysql> CHANGE MASTER TO MASTER_DELAY = 0;

3.開啟主從
mysql> start slave;

#注:做延時從庫只是為了備份,不提供服務
(2)思考:延時到底是在哪里延時的
思考:IO線程還是SQL線程做的手腳?

#去主庫創建一個庫
	create database ttt;
#查看從庫的relaylog看看有沒有內容
	mysqlbinlog --base64-output=decode-rows -vvv db03-relay-bin.000002

總結:
	延時從庫是在SQL線程做的手腳,IO線程已經把數據放到relay-log里了.
	SQL線程在執行的時候,會延遲你設定的時間長度.
(3)使用延時從庫恢復數據

1.場景

總數據量級500G,正常備份去恢復需要1.5-2小時
1)配置延時3600秒
mysql> CHANGE MASTER TO MASTER_DELAY = 3600;

2)主庫
drop database db;

3)怎么利用延時從庫,恢復數據?

2.環境准備

1.進行每日的全備
mysqldump -uroot -p123 -A -R --triggers --master-data=2 –single-transaction > /backup/full.sql

2.調整延時從庫延時時間為60分鍾
	stop slave;
	CHANGE MASTER TO MASTER_DELAY = 3600;
	start slave;
	
3.主庫寫入新數據
	create database yanshi;
	use yanshi;
	create table yanshi(id int);
	insert into yanshi values(1),(2),(3),(4);
	
	create database yanshi2;
	use yanshi2;
	create table yanshi2(id int);
	insert into yanshi2 values(1),(2),(3),(4);

3.模擬刪除數據

1.刪除一個庫,可以是之前的,也可以是剛創建的
	#因為剛我們看了,只要我執行了,從庫已經寫到了relay-log,跟我數據庫里的數據關系不大
	drop database world;

4.使用延時從庫恢復數據

1.停止從庫sql線程
	stop slave sql_thread;
2.查看狀態
	show slave status;
3.備份從庫數據
	mysqldump -uroot -p123 -B world > /backup/congku.sql
4.截取一下relay-log
	1)確認起點,查看relay-log.info即可
		[root@db02 data]# cat relay-log.info
		./db02-relay-bin.000005
		283
	2)確認終點,找到drop語句之前
		[root@db02 data]# mysqlbinlog --base64-output=decode-rows -vvv db02-relay-bin.000005
		
	3)截取數據
		[root@db02 data]# mysqlbinlog --start-position=283 --stop-position=1112 db02-relay-bin.000005 > /tmp/yanshi.sql
5.將從庫全備的數據與relaylog截取數據拷貝到主庫
	scp /tmp/yanshi.sql 172.16.1.51:/tmp/
	scp /backup/congku.sql 172.16.1.51:/tmp/
6.將數據導入主庫
	#導入前不要停掉binlog,
	mysql < /tmp/yanshi.sql
	mysql < /tmp/congku.sql
7.開啟從庫的sql線程
	start slave sql_thread;

#主庫那邊執行到刪除的時候沒關系,因為還有創建的部分,他會再次把數據創建回來

2.3 異步復制的問題

MYSQL5.5之前版本的主從復制都是異步(asynchronous)的,而在異步復制中,主庫執行完操作后,寫入binlog日志后,就返回客戶端,這一動作就結束了,主庫並不會驗證從庫有沒有收到binlog日志、以及收到的binlog是否完整,那如果主庫提交一個事務並寫入Binlog中后,當從庫還沒有從主庫得到Binlog時,主庫宕機了或因磁盤損壞等故障導致該事務的Binlog丟失了,那從庫就不會得到這個事務,也就造成了從庫與主庫數據不一致的問題,我們也就無法使用備庫來繼續提供數據一致的服務了,半同步復制可以解決該問題

三 半同步復制

3.1 半同步復制原理介紹

從MYSQL5.5開始,支持半同步復制(Semi synchronous Replication)在一定程度上保證提交的事務已經傳給了至少一個備庫。

1、一個事務操作的完成需要記完兩份日志,即主從的binlog是同步的
半同步復制,當主庫每提交一個事務后,不會立即返回,而是等待其中一個從庫接收到Binlog並成功寫入Relay-log中才返回客戶端,所以這樣就保證了一個事務至少有兩份日志,一份保存在主庫的Binlog,另一份保存在其中一個從庫的Relay-log中,從而保證了數據的安全性和一致性。

2、半同步即並非完全同步
半同步復制的“半”體現在,雖然主從庫的Binlog是同步的,但主庫不會等待從庫的sql線程執行完Relay-log后才返回,而是確認從庫的io線程接收到Binlog,達到主從Binlog同步的目的后就返回了,所以從庫的數據對於主庫來說還是有延時的,這個延時就是從庫sql線程執行Relay-log的時間。所以只能稱為半同步。

3、半同步復制超時則會切換回異步復制,正常后則切回半同步復制
在半同步復制時,如果主庫的一個事務提交成功了,在推送到從庫的過程當中,從庫宕機了或網絡故障,導致從庫並沒有接收到這個事務的Binlog,此時主庫會等待一段時間(這個時間由rpl_semi_sync_master_timeout的毫秒數決定),如果這個時間過后還無法推送到從庫,那MySQL會自動從半同步復制切換為異步復制,當從庫恢復正常連接到主庫后,主庫又會自動切換回半同步復制。

3.2 半同步復制開啟方法

半同步模式是作為MySQL5.5的一個插件來實現的,主從庫使用的插件不一樣

(1)先確認主從的MySQL服務器是否支持動態增加插件

mysql> select @@have_dynamic_loading;
+------------------------+
| @@have_dynamic_loading |
+------------------------+
| YES                    |
+------------------------+
1 row in set (0.00 sec)

(2)分別在主從庫上安裝對用插件

# 插件一般默認在MySQL安裝目錄/lib/plugin下,可以去查看一下是否存在
ls /usr/lib64/mysql/plugin/ | grep semisync


# 主庫的插件是semisync_master.so,從庫是semisync_slave.so

主庫> install plugin rpl_semi_sync_master soname 'semisync_master.so';

從庫> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';

# 安裝完成后,在plugin表(系統表)中查看一下
select * from mysql.plugin;

(3)在主從庫開啟半同步復制

主庫

#啟動插件
mysql> set global rpl_semi_sync_master_enabled=1;
#設置超時
mysql> set global rpl_semi_sync_master_timeout=30000;

#修改配置文件
[root@db01 ~]# vim /etc/my.cnf
#在[mysqld]標簽下添加如下內容(不用重啟庫,因為上面已經開啟了)
[mysqld]
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1000

從庫

#啟動插件
mysql> set global rpl_semi_sync_slave_enabled=1;

#重啟io線程使其生效
mysql> stop slave io_thread;
mysql> start slave io_thread;

#編輯配置文件(不需要重啟數據庫)
[root@mysql-db02 ~]# vim /etc/my.cnf

#在[mysqld]標簽下添加如下內容
[mysqld]
rpl_semi_sync_slave_enabled =1

(4)在主庫上查看半同步復制的狀態

mysql>show status like '%semi_sync';

在輸出信息中,我們重點關注三個參數:

#ON表示半同步復制打開,OFF表示關閉
rpl_semi_sync_master_status  OFF/ON

#這個數字表示主庫當前有幾個事務說通過半同步復制到從庫的
rpl_semi_sync_master_yes_tx   [number] 

#表示有幾個事務不是通過半同步復制到從庫的
rpl_semi_sync_master_no_tx   [number]      

四 過濾復制

4.1 企業諸多環境介紹

實際情況中,企業中的環境可能有很多,如下所示

(1) 開發環境

開發開發完自己測試

(2) 測試環境

1)性能測試
2)功能測試

(3) 預發布環境(beta,內測不刪檔)

(1)、只是一台服務器

(2)、沒有真實的流量

(3)、連的是線上數據庫

疑問:如果有一個待上線需求,需要改動數據庫表結構,怎么處理?

先把預發布環境使用的數據庫切換為測試環境使用的數據庫
然后有針對性的測試下數據庫的變更是否會影響線上當前代碼程序的運行,測試通過后再上線

(4)灰度環境

(1)、1台或多台線上主機

(2)、鏈接的是線上數據庫

(3)、真實流量

灰度發布,又稱金絲雀發布。
金絲雀發布這一術語源於煤礦工人把籠養的金絲雀帶入礦井的傳統。礦工通過金絲雀來了解礦井中一氧化碳的濃度,如果一氧化碳的濃度過高,金絲雀就會中毒,從而使礦工知道應該立刻撤離。

灰度發布發生在預發布環境之后,生產環境之前。
對應到軟件開中,則是指在發布新的產品特性時通過少量的用戶試點確認新特性沒有問題,確保無誤后推廣到更大的用戶使用群體。

生產環境一般會部署在多台機器上,以防某台機器出現故障,這樣其他機器可以繼續運行,不影響用戶使用。灰度發布會發布到其中的幾台機器上,驗證新功能是否正常。如果失敗,只需回滾這幾台機器即可。

(5)沙盒環境

沙盒環境又稱測試環境和開發環境,是提供給開發者開發和測試用的環境。
沙盒通常嚴格控制其中的程序所能訪問的資源,比如,沙盒可以提供用后即回收的磁盤及內存空間。在沙盒中,網絡訪問、對真實系統的訪問、對輸入設備的讀取通常被禁止或是嚴格限制。

也就是說所謂的沙盒測試就是在產品未上線前在內部環境或網絡下進行的測試,此時在正常的線上環境是無法看到或查詢到該產品或項目的,只有產品在測試環境下無問題上傳到生產環境之后,用戶才能看到該產品或功能

(6) 生產環境

除了生產和預發布其他的環境都是虛擬機測試用的

測試環境有很多游戲,我就想一個從庫同步一種游戲,還有合服,建新服,其實就是一個庫或者一個表而已.

考慮到環境過多為了節省資源,我們會有只同步某一個庫的需求。這就用到了黑名單與白名單

4.2 過濾復制的兩種方式

(1)黑名單

不記錄黑名單列出的庫的二進制日志

#參數
replicate-ignore-db=test
replicate-ignore-table=test.t1
replicate-wild-ignore-table=test.t%  支持通配符,t開頭的表

注意:
replicate-ignore-table依賴參數replicate-ignore-db
即如果想忽略某個庫下的某張表,需要一起配置
replicate-ignore-db=test
replicate-ignore-table=test.t1

(2)白名單

只執行白名單中列出的庫或者表的中繼日志

#參數:
replicate-do-db=test
replicate-do-table=test.t1
replicate-wild-do-table=test.t%

注意:
replicate-do-table依賴參數replicate-do-db
即如果想只接收某個庫下的某張表,需要一起配置
replicate-do-db=test
replicate-do-table=test.t1

(3)主從庫設置黑白名單的影響

# 1、黑白名單對主庫的影響是:是否記錄binlog日志
在主庫上設置白名單:只記錄白名單設置的庫或者表、相關的SQL語句到binlog中
在主庫上設置黑名單:不記錄黑名單設置的庫或者表、相關的SQL語句到binlog中

# 2、黑白名單對從庫的影響是:sql線程是否執行io線程拿到的binlog
IO線程一定會拿到所有的binlog,但

如果在從庫上設置白名單:SQL線程只執行白名單設置的庫或者表相關的SQL語句

如果在從庫上設置黑名單:SQL線程不執行黑名單設置的庫或者表相關的SQL語句

4.3 配置過濾復制

(1)做好一主兩從

# 如果查看從庫show slave status\G報錯
A slave with the same server_uuid/server_id as this slave has connected to the master;
# 解決方案如下
如果server_id相同,請修改/etc/my.cnf中server_id的配置

如果server_uuid相同,請刪除auto.cnf文件(auto.cnf文件在/etc/my.cnf中datadir配置的目錄下),然后重啟數據庫,數據庫會重新生成server_uuid和auto.cnf文件

[rml_read_more]:

(2)從庫1配置

[root@db02 ~]# vim /etc/my.cnf
[mysqld]
replicate-do-db=big_jason

[root@db02 ~]# systemctl restart mysql

#查看主從狀態
show slave status;

(3)從庫2配置

[root@db03 ~]# vim /etc/my.cnf
[mysqld]
replicate-wild-do-table=big_jason.t%
replicate-do-db=small_jason
replicate-do-table=small_jason.t1

[root@db03 ~]# systemctl restart mysql

#查看主從狀態
show slave status;

(4)主庫創建表測試

create database big_jason;
create database small_jason;

use big_jason;
create table t1(id int);  -- 表名以t開頭
create table t2(id int);  -- 表名以t開頭
create table x3(id int);

use small_jason;
create table t1(id int);
create table t2(id int);
create table t3(id int);

5)從庫查看表

從庫1上只能看到big_jason庫下的所有表:t1、t2、x3

從庫2上只能看到
	big_jason庫下t開頭的那兩張表,看不到表x3
	small_jason庫下的t1表

6)自行練習驗證:嘗試把白名單配置到主庫

[root@db01 ~]# vim /etc/my.cnf
[mysqld]
replicate-do-db=db1

[root@db01 ~]# systemctl restart mysql

#測試同步

五 主從復制的架構

5.1 主備架構,只有主庫提供讀寫服務,備庫僅留作備用

jdbc:mysql://vip:3306/xxdb

1、高可用分析:高可用,主庫掛了,keepalive(只是一種工具)會自動切換到備庫。這個過程對業務層是透明的,無需修改代碼或配置。

2、高性能分析:讀寫都操作主庫,很容易產生瓶頸。大部分互聯網應用讀多寫少,讀會先成為瓶頸,進而影響寫性能。另外,備庫只是單純的備份,資源利用率50%,這點方案二可解決。

3、一致性分析:讀寫都操作主庫,不存在數據一致性問題。

4、擴展性分析:無法通過加從庫來擴展讀性能,進而提高整體性能。

5、可落地分析:兩點影響落地使用。第一,性能一般,這點可以通過建立高效的索引和引入緩存來增加讀性能,進而提高性能。這也是通用的方案。第二,擴展性差,這點可以通過分庫分表來擴展。

5.2 雙主架構,兩個主庫同時提供服務,負載均衡

jdbc:mysql://vip:3306/xxdb

1、高可用分析:高可用,一個主庫掛了,不影響另一台主庫提供服務。這個過程對業務層是透明的,無需修改代碼或配置。

2、高性能分析:讀寫性能相比於方案一都得到提升,提升一倍。

3、一致性分析:存在數據一致性問題。請看,一致性解決方案

4、擴展性分析:當然可以擴展成三主循環,但筆者不建議(會多一層數據同步,這樣同步的時間會更長)。如果非得在數據庫架構層面擴展的話,擴展為方案四。

5、可落地分析:兩點影響落地使用。第一,數據一致性問題,一致性解決方案可解決問題第二,主鍵沖突問題,ID統一地由分布式ID生成服務來生成可解決問題。

5.3 主從架構,一主多從,讀寫分離

寫
jdbc:mysql://master-ip:3306/xxdb

讀
jdbc:mysql://slave1-ip:3306/xxdb
jdbc:mysql://slave2-ip:3306/xxdb

1、高可用分析:主庫單點,從庫高可用。一旦主庫掛了,寫服務也就無法提供。

2、高性能分析:大部分互聯網應用讀多寫少,讀會先成為瓶頸,進而影響整體性能。讀的性能提高了,整體性能也提高了。另外,主庫可以不用索引,線上從庫和線下從庫也可以建立不同的索引(線上從庫如果有多個還是要建立相同的索引,不然得不償失;線下從庫是平時開發人員排查線上問題時查的庫,可以建更多的索引)。

3、一致性分析:存在數據一致性問題。請看,一致性解決方案

4、擴展性分析:可以通過加從庫來擴展讀性能,進而提高整體性能。(帶來的問題是,從庫越多需要從主庫拉取binlog日志的端就越多,進而影響主庫的性能,並且數據同步完成的時間也會更長)

5、可落地分析:兩點影響落地使用。第一,數據一致性問題,一致性解決方案可解決問題第二,主庫單點問題,筆者暫時沒想到很好的解決方案。

注:思考一個問題,一台從庫掛了會怎樣?讀寫分離之讀的負載均衡策略怎么容錯?

5.4 級聯復制架構(Master –Slaves - Slaves)

因為每個從庫在主庫上都會有一個獨立的Binlog Dump線程來推送binlog日志,所以隨着從庫數量的增加,主庫的IO壓力和網絡壓力也會隨之增加,這時,多級復制架構應運而生。

多級復制架構只是在一主多從的基礎上,再主庫和各個從庫之間增加了一層二級主庫Master2,這層二級主庫僅僅用來將一級主庫推送給它的BInlog日志再推送給各個從庫,以此來減輕一級主庫的推送壓力。

但它的缺點就是Binlog日志要經過兩次復制才能到達從庫,增加了復制的延時。

我們可以通過在二級從庫上應用Blackhol存儲引擎(黑洞引擎)來解決這一問題,降低多級復制的延時。

“黑洞引擎”就是寫入Blackhole表中數據並不會寫到磁盤上,所以這個Blackhole表永遠是個空表,對數據的插入/更新/刪除操作僅在Binlog中記錄,並復制到從庫中去。

5.5 雙主+主從架構,看似完美的方案

img

寫
jdbc:mysql://vip:3306/xxdb

讀
jdbc:mysql://slave1-ip:3306/xxdb
jdbc:mysql://slave2-ip:3306/xxdb

1、高可用分析:高可用。

2、高性能分析:高性能。

3、一致性分析:存在數據一致性問題。請看,一致性解決方案

4、擴展性分析:可以通過加從庫來擴展讀性能,進而提高整體性能。(帶來的問題同方案二

5、可落地分析:同方案二,但數據同步又多了一層,數據延遲更嚴重

六 一致性解決方案

6.1 導致主從延時因素

注:圖中圈出的是數據同步的地方

數據同步(從主庫把binlog日志推送給從庫,然后在從庫再執行一遍)是需要時間的,這個同步時間內主庫和從庫的數據會存在不一致的情況,遇到網絡延遲,或者主庫並發事務過多的情況(主庫可以並行事務,但從庫的是SQL線程串行回放的,如果並發事務過大,從庫必然忙活不過來,造成延遲),都會加劇不一致的情況。

如果同步過程中有讀請求,那么讀到的就是從庫中的老數據。如下圖。

查看主從延遲

# 延時指標1:查看從庫獲取到主庫binlog的時間
show slave status;
查看延時時間
Seconds_Behind_Master: 0


# 延時指標2:查看從庫回放的日志量與主庫日量的差
主庫:show master status ;
從庫: show slave status \G

查看從庫已經拿到的主庫日志量
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 172826

查看從庫已經執行的主庫日志量
Relay_Master_Log_File: mysql-bin.000003
Exec_Master_Log_Pos: 131837

既然知道了數據不一致性產生的原因,那如何解決呢?

首先如果業務允許延時存在,那么就不去管它,如果對一致性確實有要求,那么可以圍繞以下角度去優化

6.2 硬件方面

1.采用好服務器,比如4u比2u性能明顯好,2u比1u性能明顯好。

2.存儲用ssd或者盤陣或者san,提升隨機寫的性能。

3.主從間保證處在同一個交換機下面,並且是萬兆環境。

總結,硬件強勁,延遲自然會變小。一句話,縮小延遲的解決方案就是花錢和花時間。

6.3 文件系統方面

master端修改linux、Unix文件系統中文件的etime屬性, 由於每當讀文件時OS都會將讀取操作發生的時間回寫到磁盤上,對於讀操作頻繁的數據庫文件來說這是沒必要的,只會增加磁盤系統的負擔影響I/O性能。可以通過設置文件系統的mount屬性,組織操作系統寫atime信息,在linux上的操作為:打開/etc/fstab,加上noatime參數/dev/sdb1 /data reiserfs noatime 1 2然后重新mount文件系統#mount -o remount /data

6.4 優化mysql參數

1、logs-slave-updates 從服務器從主服務器接收到的更新不記入它的二進制日志。

2、sync_binlog在slave端設置為0或禁用slave端的binlog

3、slave端,如果使用的存儲引擎是innodb,innodb_flush_log_at_trx_commit =2


對數據安全性較高,需要設置
sync_binlog=1
innodb_flush_log_at_trx_commit = 1 
而對於slave則不需要這么高的數據安全,完全可以設置為
sync_binlog=0或者關閉binlog
innodb_flush_log_at_trx_commit =0或2

6.5 主從都開啟GTID復制模式

從MySQL 5.6.5 開始新增了一種基於 GTID 的復制方式。通過 GTID 保證了每個在主庫上提交的事務在集群中有一個唯一的ID。這種方式強化了數據庫的主備一致性,故障恢復以及容錯能力。

GTID (Global Transaction ID)是全局事務ID,當在主庫上提交事務或者被從庫應用時,可以定位和追蹤每一個事務,對DBA來說意義就很大了,我們可以適當的解放出來,不用手工去可以找偏移量的值了,而是通過CHANGE MASTER TO MASTER_HOST='xxx', MASTER_AUTO_POSITION=1的即可方便的搭建從庫,在故障修復中也可以采用MASTER_AUTO_POSITION=‘X’的方式。

可能大多數人第一次聽到GTID的時候會感覺有些突兀,但是從架構設計的角度,GTID是一種很好的分布式ID實踐方式,通常來說,分布式ID有兩個基本要求:
1)全局唯一性
2)趨勢遞增

這個ID因為是全局唯一,所以在分布式環境中很容易識別,因為趨勢遞增,所以ID是具有相應的趨勢規律,在必要的時候方便進行順序提取,行業內適用較多的是基於Twitter的ID生成算法snowflake,所以換一個角度來理解GTID,其實是一種優雅的分布式設計。

5.7版本GTID做了增強,不手工開啟也自動維護匿名的GTID信息

5.7 版本的從庫並發配置方法
gtid_mode=ON     #開啟GTID復制模式
enforce_gtid_consistency=ON      #強制GTID一致性
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=16
master_info_repository=TABLE     #將master-info信息記錄到表中
relay_log_info_repository=TABLE    #將relay-info信息記錄到表中
relay_log_recovery=ON

6.6 架構方面

首先,如果業務允許延時存在,那么就不去管數據一致問題。如果需要考慮延時,架構方案有如下幾種

(1)、強制讀主

采用主備架構方案,讀寫都走主庫。此時肯定不會出現數據不一致問題,因為讀寫都打到了一個庫上,剛剛寫完就可以立即讀到。

但從庫一直被閑置,主庫的壓力太大了,為了緩解主庫的讀壓力,可以引入緩存。

但是有一點需要知道:如果緩存掛了,可能會產生雪崩現象,不過一般分布式緩存都是高可用的。

在本架構中,從庫的作用是,主庫一旦掛掉,vip則漂移到從庫上,從庫可以投入使用。

具體步驟分析如下

  • 1:寫操作
    • w1.delete key先把寫入的數據更新進緩存,保障可以立即讀到
    • 然后w2.write,把數據寫入主庫
  • 2、讀操作
    • r1.get key先從緩存里讀數據,如果讀到則返回給用戶
    • 如果沒有讀到,則r2.read讀取主庫
    • 然后r3.set key將讀到的數據更新進緩存,方便下一次讀

(2)選擇讀主

寫操作時根據庫+表+業務特征生成一個key放到Cache里

並且為key設置超時時間,而該key的超時時間>=主從數據同步的時間,這保證了一件事,就是當緩存數據超時時,從庫中一定同步好了數據,此時我們可以讀從庫。

  • 1:寫操作
    • w1.delete key先把寫入的數據更新進緩存,保障可以立即讀到,並且設置緩存的超時時間,該時間>=主從同步的延遲時間
    • 然后w2.write,把數據寫入主庫
  • 2、讀操作
    • r1.get key先從緩存里讀數據,如果讀到則返回給用戶
    • 如果沒有讀到,則證明該數據在緩存中超時了,因為該超時時間是>=主從同步的時間的,所以此時從庫也一定是有數據了,我們直接r2.read去從庫讀即可
    • 然后r3.set key將讀到的數據更新進緩存,方便下一次讀

總結一下緩存使用方式:

​ 第一步:淘汰緩存-》delete key;

​ 第二步:寫入數據庫;

​ 第三步:讀取緩存,命中則返回,否則去數據庫中讀;

​ 第四步:讀取數據庫后寫入緩存。

4、半同步復制,等主從同步完成,寫請求才返回。就是大家常說的“半同步復制”semi-sync。這可以利用數據庫原生功能,實現比較簡單。代價是寫請求時延增長,吞吐量降低。

5、數據庫中間件,引入開源(mycat等)或自研的數據庫中間層。個人理解,思路同2。數據庫中間件的成本比較高,並且還多引入了一層。

6.7 架構演變

1、架構演變一:方案一 -> 方案一+分庫分表 -> 方案二+分庫分表 -> 方案四+分庫分表;

2、架構演變二:方案一 -> 方案一+分庫分表 -> 方案三+分庫分表 -> 方案四+分庫分表;

3、架構演變三:方案一 -> 方案二 -> 方案四 -> 方案四+分庫分表;

4、架構演變四:方案一 -> 方案三 -> 方案四 -> 方案四+分庫分表;

總結

1、加緩存和索引是通用的提升數據庫性能的方式;

2、分庫分表帶來的好處是巨大的,但同樣也會帶來一些問題,詳見前日推文。

3、不管是主備+分庫分表還是主從+讀寫分離+分庫分表,都要考慮具體的業務場景。絕大部分的數據庫架構還是采用方案一和方案一+分庫分表,只有極少部分用方案三+讀寫分離+分庫分表。另外,阿里雲提供的數據庫雲服務也都是主備方案,要想主從+讀寫分離需要二次架構。

4、記住一句話:不考慮業務場景的架構都是耍流氓。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM