1. 程式人生 > >mysql總結3(複製:M/S(非同步,半同步)、M/M,複製過濾器)

mysql總結3(複製:M/S(非同步,半同步)、M/M,複製過濾器)

對於mysql複製一般來講只有一個節點即能讀又能寫,其餘節點只能讀

複製的功用:

資料分佈
負載均衡
備份
高可用和故障切換
mysql的升級測試

主從複製:
最基本條件:開啟二進位制日誌
原理:
1、slave將自己扮演成客戶端,向master請求二進位制日誌(若salve沒有指明自己請求的位置,則master從第一個檔案的最開始出發送給salve),slave得到二進位制日誌後將其儲存在本地的中繼日誌中(IO執行緒)
2、master收到將二進位制日誌的事件讀出來,響應給salve(dump執行緒)
3、slave得到二進位制日誌後將其儲存在本地的中繼日誌中後slave還會開啟一個執行緒,將中繼日誌的事件刷到磁碟中(SQL執行緒)

所以整個主從複製過程是由三個執行緒完成的:

從節點:
I/O Thread:從master中請求二進位制日誌,將其儲存在中級日誌中
SQL Thread:從中繼日誌中讀取二進位制檔案,在本地完成重放
主節點:
dump Thread:為每個salve的I/O Thread啟動一個dump執行緒,用於向其傳送binary log event

主從複製的特點:

1、預設為非同步複製
2、資料不一致比較常見

複製架構:M/S 、 M/M 、 環狀複製

一主多從
從伺服器還可以再有從伺服器(mysql支援級聯複製)
一從多主

mysql的非同步複製:

mysql收到寫操作後,只需保證本地寫操作完成就立即返回給客戶端寫操作已完成,不會等待從伺服器返回結果

對於非常繁忙的主節點,許多事務可能並行提交,那麼使用者請求過來後如何進行負載均衡呢?

這裡不能使用lvs,因為要進行讀寫分離
使用一個工作在第七層模型的伺服器,判斷客戶端過來的是寫請求還是讀請求。再進行排程。稱為mysql七層反向代理(mysql的讀寫分離器)

如果說某個請求的相關資料集是一個剛剛接收了寫操作的資料集上。他會將請求發給主節點而不是從節點(因此從節點會落後於主節點)

當mysql接收到一條select型別的query時,mysql會對這條query進行hash計算而得到一個hash值,然後通過該hash值到query cache中去匹配,如果沒有匹配中,則將這個hash值存放在一個hash連結串列中,同時將query的結果集存放進cache中,存放hash值的連結串列的每一個hash節點存放了相應query結果集在cache中的地址,以及該query所涉及到的一些table的相關資訊;如果通過hash值匹配到了一樣的query,則直接將cache中相應的query結果集返回給客戶端。如果mysql任何一個表中的任何一條資料發生了變化,便會通知query cache需要與該table相關的query的cache全部失效,並釋放佔用的記憶體地址。

有了query cache這種機制,前端排程應該怎麼做呢?

某請求排程到某從節點,從節點收到後儲存在query cache中。同一請求傳送至同一從節點,直接從query cache中返回資料,這樣雖然提高了快取利用率,減少了IO開銷。但這種機制不利於負載均衡,所以我們可以在前端進行memcache

主節點宕機了,將落後於主節點最少的從節點提升成主節點 (這種情況下基於gtid模式更加精確方便)

雙主模式(互為主從 ):每一個節點即是主節點,又是對方的從節點。

這種模式下如何避免兩個伺服器之間來回複製?

每一個節點在本地儲存二進位制事件時會有一個server_id, 每個節點在本地重放二進位制日誌時,會保留server_id資訊,另一個節點在讀到後對比server_id是否與自己的相同。若相同,則判斷為自己以前寫過的資料,這樣避免重複寫入。

主主模型可能會帶來資料不一致:

例如:主1:年齡大於30歲,工資翻倍,主2:工資大於3000的,年齡減一,有一個人正好30歲,怎麼辦?

多主模型:前一個伺服器是後一個伺服器的主(用的不多)

這裡寫圖片描述

一主多從:

在此模式下,主既要接受客戶端段寫請求,還要負載給從傳送二進位制日誌。如何進行優化。

MySQL在5.x系列提供了Blackhole引擎–“黑洞”. 其作用正如其名字一樣:任何寫入到此引擎的資料均會被丟棄掉, 不做實際儲存;Select語句的內容永遠是空。 和Linux中的 /dev/null 檔案完成的作用完全一致(參考:https://www.cnblogs.com/wt645631686/p/8086682.html
在主從之間新增一個分散式master,配置blackhole儲存引擎,他起到一箇中繼的作用,他接收資料但在repilication時偷偷將資料丟掉,只是會把master的二進位制日誌供下層的slave來讀取。
這裡寫圖片描述

半同步複製

主節點在等待從節點返回,才返回。
在一主多從模式下,一般只給一個salve配置成半同步,其他配置成非同步

複製過濾器

從節點指向複製的有限個數據庫。在從節點上明確說明自己只在中繼日誌把需要的replication到本地。

接下來對: 主從、主主、半同步、複製過濾器進行演示:

主從複製的實現:

基於binlog:

主節點:
(1)啟動二進位制日誌;
[mysqld]
log-bin=mysql-bin
(2)為當前節點設定一個全域性唯一的ID號
[mysqld]
server_id=13)建立由複製許可權的使用者帳號

MariaDB [(none)]> grant replication slave, replication client on *.* to 'repluser'@'172.25.44.7' identified by 'repluser';

從節點:
(1)啟動中繼日誌
[mysqld]
relay_log=relay-log
relay_log_index=relay-log.index2)為當前節點設定一個全域性唯一的ID號
server_id=73)使用有複製許可權的使用者帳號連線至主伺服器,並啟動複製執行緒
change master to master_host='172.25.44.6', master_user='repluser',master_password='repluser',master_log_file='mysql-bin.000003',master_log_pos=423;
start slave;


完成上述配置,重啟服務後,檢視變數,看二進位制日誌是否開啟:
這裡寫圖片描述
檢視二進位制檔案:
這裡寫圖片描述
從:
重啟服務後,檢視中繼日誌是否開啟,
這裡寫圖片描述
檢視server_id
這裡寫圖片描述
在使用master的授權連線主伺服器時,可以檢視幫助:
這裡寫圖片描述

在完成授權後,檢視slave的狀態:
這裡寫圖片描述
發現IO執行緒和SQL執行緒都時NO,這時因為還沒有開啟複製執行緒
所以接下來開啟複製執行緒:
檢視幫助:
這裡寫圖片描述
不指定的話兩個執行緒都開啟
這裡寫圖片描述
這時檢視狀態為YES
這裡寫圖片描述
看到兩個YES,基本上就成功了
測試:
主:
這裡寫圖片描述
從:
這裡寫圖片描述

主從架構中存在的問題:

1、一般來講,從節點絕不應該接受寫操作,以免資料不一致
這裡寫圖片描述
這一項預設為off,將其設定為on
可以看到,即使我把這一項設定為on,還是可以進行寫操作
這裡寫圖片描述
原因是:此限制歲擁有super許可權的使用者無效
要想限制所有人:
這裡寫圖片描述
此執行緒不會組織SQL執行緒從本地讀取中繼日誌進行寫操作。因為它不是通過執行緒連線進來進行寫操作的

2、如何保證主從複製的事務安全
(1)master:
主伺服器在資料提交時,為了保證資料的永續性、可靠性等特點,都應該立即將事務從記憶體寫入磁碟中,即使不寫入資料檔案中至少也應該寫入事務日誌中。
二進位制日誌為了加速寫操作,在記憶體中有緩衝。因此一些和事務相關得提交語句,及提交之前的一些寫語句仍然可能在二進位制日誌的記憶體緩衝區,並不在二進位制日誌中。這就意味著從伺服器複製不到。、
明明事務已經提交,但從伺服器上並沒有提交。
為了避免以上問題:即主伺服器事務提交後,從伺服器能儘快獲得一份和此事務相關的語句,並在本地執行一遍,至少也得儲存在中繼日誌中。這樣,當主節點因為事故宕機後,從節點的事務也是完整的

在master節點啟用sync_binlog=ON  在事務提交時,必須立即將binlog緩衝區中記錄下來的時間重新整理代二進位制日誌中。
若用到InnoDB儲存引擎:
innodb_use_global_flush_log_at_trx_commit=ON
innodb_support_xa=ON       

(2)slave 上:
skip_salve_start=ON (在slave的mysql開啟後,不自動啟動複製執行緒)

在從節點上有兩個info檔案。他們有什麼作用呢?
在MySQL 5.6.2之前,slave記錄的master資訊以及slave應用binlog的資訊存放在檔案中,即master.info與relay-log.info。

這裡寫圖片描述

master.info檔案:( IO Thread)
該檔案的作用:記錄已經複製到哪個主節點的哪一個二進位制的哪一個位置。用的是什麼身份、密碼複製的。
這也就是為什麼預設情況下,啟動mysql服務後會自動連線到主節點。
這裡寫圖片描述
relay-log.info檔案:(SQL Thread)
用來記錄本地已經複製到哪個二進位制日誌的哪一個位置,儲存在中繼日誌的哪個位置。
這裡寫圖片描述

(3)
master:
sync_master_info :每間隔多少事務重新整理master.info,如果是table(innodb)設定無效,每個事務都會更新
這裡寫圖片描述
slave: 預設為10000,即每10000次sync_relay_log事件會重新整理到磁碟。為0則表示不重新整理,交由OS的cache控制
sync_relay_log_info:每間隔多少事務重新整理relay-log.info,如果是table(innodb)設定無效,每個事務都會更新
這裡寫圖片描述
兩個執行緒的執行進度(偏移量)都儲存在檔案中.IO thread的執行狀態資訊儲存在master.info檔案,SQL thread的執行狀態資訊儲存在relay-log.info檔案。系統執行正常的情況下,這種模式到目前為止還沒有問題。需要注意的是這些檔案被修改後不是同步寫入磁碟的,每當系統發生crash,儲存的偏移量可能都不準確.MySQL 5.5通過兩個引數修復了該問題,使用sync_master_info=1和sync_replay_log_info=1 來保證Slave 的兩個執行緒每次寫一個事務就分別向兩個檔案同步一次 IO thread和SQL thread當前執行的資訊。當然同步操作不是免費的,頻繁更新磁碟檔案需要消耗效能(參考:http://blog.itpub.net/22664653/viewspace-1752588/)

問題::在mysql主從複製過程中,如果主節點已經運行了一段時間並且有大量資料,這時候如何配置並啟動slave?
在主伺服器上進行備份,備份的時候記錄二進位制日誌的檔名和posiition,在從伺服器將資料匯入(就像恢復資料一樣)。並在從伺服器上指明從備份那一刻的二進位制日誌和position處開始複製。

主主複製:

(1)主主複製會導致資料不一致,因此慎用!
兩個節點互為主從,所以兩個節點都啟動二進位制日誌和中繼日誌。
(2)自動增長id:
配置node1使用奇數id:
auto_increment_increment = 1
auto_increment_offset =2
配置node2使用偶數節點:
auto_increment_increment = 2
auto_increment_offset =2

mysql中有自增長欄位,在做資料庫的主主同步時需要設定自增長的兩個相關配置:auto_increment_offset和auto_increment_increment。

auto_increment_offset表示自增長欄位從那個數開始,他的取值範圍是1 .. 65535
auto_increment_increment表示自增長欄位每次遞增的量,其預設值是1,取值範圍是1 .. 65535

在主主同步配置時,需要將兩臺伺服器的auto_increment_increment增長量都配置為2,而要把auto_increment_offset分別配置為1和2.
這樣才可以避免兩臺伺服器同時做更新時自增長欄位的值之間發生衝突。(參考:https://www.cnblogs.com/DBArtist/p/auto_increment.html)

配置步驟:
(1)各節點使用一個唯一的sever_id;
(2)都啟動binary log 和 relay log;
(3)建立擁有複製許可權的使用者帳號;
(4)定義自動增長id的欄位的數值範圍奇偶;
(5)均把對方主為主節點。並啟動複製執行緒;

由於我之前已經做過主從複製,在配置主主複製之前,我先將伺服器恢復至最初狀態。我用的方法比較簡單粗暴——直接刪除/var/lob/mysql下的資料(建議生產環境中不要這麼幹!)
這裡寫圖片描述
這裡寫圖片描述

node1:server6
這裡寫圖片描述

這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

node2:server7(配置於node1類似,這裡就不演示了)

測試:
在node1上寫資料:
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

node2檢視:
這裡寫圖片描述
這裡寫圖片描述
在node2上寫資料:
這裡寫圖片描述
node1檢視:
這裡寫圖片描述

以上就實現了主從複製,
但是主主複製配置檔案中auto_increment_increment和auto_increment_offset只能保證主鍵不重複,卻不能保證主鍵有序。

半同步複製

必須是MySQL5.5或者以上

master:
MySQL必須有自動載入功能,即have_dynamic_loading變數為YES(因為我們是在MySQL裡面來載入安裝這個功能外掛)
檢視是否具有自動載入功能:
這裡寫圖片描述
檢視外掛所在目錄
這裡寫圖片描述

semisync_master.so semisync_slave.so 這兩個檔案就是就是半同步外掛所對應的配置檔案
這裡寫圖片描述
主安裝rpl_semi_sync_master外掛:
這裡寫圖片描述

可以看到外掛已經被安裝上了:
MariaDB [(none)]> show plugins;
這裡寫圖片描述
檢視與半同步有關的變數:
這裡寫圖片描述
rpl_semi_sync_master_enabled :是否啟用自己為半同步複製的主節點
rpl_semi_sync_master_timeout:等待從節點的超時時間

可以看到外掛的狀態為off
這裡寫圖片描述
開啟外掛:
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

建立使用者並授權
這裡寫圖片描述

從:
安裝外掛
這裡寫圖片描述
這裡寫圖片描述

開啟外掛:
這裡寫圖片描述
檢視狀態發現狀態依舊時off,沒關係
這裡寫圖片描述
使用master授權的使用者連線到master,並開啟複製執行緒
這裡寫圖片描述
這裡寫圖片描述

測試:
主寫資料:
這裡寫圖片描述
從檢視:
這裡寫圖片描述
這時再檢視從的半同步外掛的狀態,發現已經開啟了
這裡寫圖片描述
檢視主節點的引數:
這裡寫圖片描述

複製過濾器:

讓從節僅複製指定的資料庫,或者指定資料庫地指定表;
有兩種實現方式:
(1)主服務僅向二進位制日誌中記錄與特定資料庫(特定表)相關的事件
問題:時間還原無法實現:不建議使用;