歡迎訪問我的個人網站O(∩_∩)O哈哈~希望大佬們能給個star,個人網站網址:http://www.wenzhihuai.com,個人網站代碼地址:https://github.com/Zephery/newblog。
先來回顧一下上一篇的小集群架構,tomcat集群,nginx進行反向代理,服務器異地:
由上一篇講到,部署的時候,將war部署在不同的服務器里,通過spring-session實現了session共享,基本的分布式部署還算是完善了點,但是想了想數據庫的訪問會不會延遲太大,畢竟一個服務器在北京,一個在深圳,然后試着ping了一下:
果然,36ms。。。看起來挺小的,但是對比一下sql執行語句的時間:
大部分都能在10ms內完成,而最長的語句是insert語句,可見,由於異地導致的36ms延時還是比較大的,搗鼓了一下,最后還是選擇換個架構,每個服務器讀取自己的數據庫,然后數據庫底層做一下主主復制,讓數據同步。最終架構如下:
一、MySql的復制
數據庫復制的基本問題就是讓一台服務器的數據與其他服務器保持同步。MySql目前支持兩種復制方式:基於行的復制和基於語句的復制,這兩者的基本過程都是在主庫上記錄二進制的日志、在備庫上重放日志的方式來實現異步的數據復制。其過程分為三步:
(1)master將改變記錄到二進制日志(binary log)中(這些記錄叫做二進制日志事件,binary log events);
(2)slave將master的binary log events拷貝到它的中繼日志(relay log);
(3)slave重做中繼日志中的事件,將改變反映它自己的數據。
該過程的第一部分就是master記錄二進制日志。在每個事務更新數據完成之前,master在二日志記錄這些改變。MySQL將事務串行的寫入二進制日志,即使事務中的語句都是交叉執行的。在事件寫入二進制日志完成后,master通知存儲引擎提交事務。
下一步就是slave將master的binary log拷貝到它自己的中繼日志。首先,slave開始一個工作線程——I/O線程。I/O線程在master上打開一個普通的連接,然后開始binlog dump process。Binlog dump process從master的二進制日志中讀取事件,如果已經跟上master,它會睡眠並等待master產生新的事件。I/O線程將這些事件寫入中繼日志。
SQL slave thread處理該過程的最后一步。SQL線程從中繼日志讀取事件,更新slave的數據,使其與master中的數據一致。只要該線程與I/O線程保持一致,中繼日志通常會位於OS的緩存中,所以中繼日志的開銷很小。
此外,在master中也有一個工作線程:和其它MySQL的連接一樣,slave在master中打開一個連接也會使得master開始一個線程。復制過程有一個很重要的限制——復制在slave上是串行化的,也就是說master上的並行更新操作不能在slave上並行操作。
MySql的基本復制方式有主從復制、主主復制,主主復制即把主從復制的配置倒過來再配置一遍即可,下面的配置則是主從復制的過程,到時候可自行改為主主復制。其他的架構如:一主庫多備庫、環形復制、樹或者金字塔型都是基於這兩種方式,可參考《高性能MySql》。
二、配置過程
2.1 創建所用的復制賬號
由於是個自己的小網站,就不做過多的操作了,直接使用root賬號
2.2 配置master
接下來要對mysql的serverID,日志位置,復制方式等進行操作,使用vim打開my.cnf。
[client]
default-character-set=utf8
[mysqld]
character_set_server=utf8
init_connect= SET NAMES utf8
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
# master
log-bin=mysql-bin
# 設為基於行的復制
binlog-format=ROW
# 設置server的唯一id
server-id=2
# 忽略的數據庫,不使用備份
binlog-ignore-db=information_schema
binlog-ignore-db=cluster
binlog-ignore-db=mysql
# 要進行備份的數據庫
binlog-do-db=myblog
重啟Mysql之后,查看主庫狀態,show master status。
其中,File為日志文件,指定Slave從哪個日志文件開始讀復制數據,Position為偏移,從哪個POSITION號開始讀,Binlog_Do_DB為要備份的數據庫。
2.3 配置slave
從庫的配置跟主庫類似,vim /etc/my.cnf配置從庫信息。
[client]
default-character-set=utf8
[mysqld]
character_set_server=utf8
init_connect= SET NAMES utf8
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
# slave
log-bin=mysql-bin
# 服務器唯一id
server-id=3
# 不備份的數據庫
binlog-ignore-db=information_schema
binlog-ignore-db=cluster
binlog-ignore-db=mysql
# 需要備份的數據庫
replicate-do-db=myblog
# 其他相關信息
slave-skip-errors=all
slave-net-timeout=60
# 開啟中繼日志
relay_log = mysql-relay-bin
#
log_slave_updates = 1
# 防止改變數據
read_only = 1
重啟slave,同時啟動復制,還需要調整一下命令。
mysql> CHANGE MASTER TO MASTER_HOST = '119.23.46.71', MASTER_USER = 'root', MASTER_PASSWORD = 'helloroot', MASTER_PORT = 3306, MASTER_LOG_FILE = 'mysql-bin.000009', MASTER_LOG_POS = 346180;
可以看見slave已經開始進行同步了。我們使用show slave status\G來查看slave的狀態。
其中日志文件和POSITION不一致是合理的,配置好了的話,即使重啟,也不會影響到主從復制的配置。
某天在Github上漂游,發現了阿里的canal,同時才知道上面這個業務是叫異地跨機房同步,早期,阿里巴巴B2B公司因為存在杭州和美國雙機房部署,存在跨機房同步的業務需求。不過早期的數據庫同步業務,主要是基於trigger的方式獲取增量變更,不過從2010年開始,阿里系公司開始逐步的嘗試基於數據庫的日志解析,獲取增量變更進行同步,由此衍生出了增量訂閱&消費的業務。下面是基本的原理:
原理相對比較簡單:
1.canal模擬mysql slave的交互協議,偽裝自己為mysql slave,向mysql master發送dump協議
2.mysql master收到dump請求,開始推送binary log給slave(也就是canal)
3.canal解析binary log對象(原始為byte流)
其中,配置過程如下:https://github.com/alibaba/canal,可以搭配Zookeeper使用。在ZKUI中能夠查看到節點:
一般情況下,還要配合阿里的另一個開源產品使用otter,相關文檔還是找找GitHub吧,個人搭建完了之后,用起來還是不如直接使用mysql的主主復制,而且異地機房同步這種大企業才有的業務。
公司又要996了,實在是忙不過來,感覺自己寫的還是急躁了點,困==
歡迎訪問我的個人網站O(∩_∩)O哈哈~希望能給個star
個人網站網址:http://www.wenzhihuai.com
個人網站代碼地址:https://github.com/Zephery/newblog