背景
最近新項目需要用到mysql數據庫,並且由於數據量大的原因,故打算采用1主1從(主數據庫負責增、刪、改操作;從數據庫負責查操作)的數據庫架構,在實現主從之后還要實現讀寫分離的代理,在網上搜尋了很久,自己也了解了一些資料,目前有三種代理組件:1、mysql_proxy 2、amoeba 3、mycat 我采用了第3種,選擇mycat的原因下面會提到。
部署環境
我在我虛擬機下面裝了三台Centos7_x64系統:
1、192.168.8.47 主mysql服務器
2、192.168.8.45 從mysql服務器
3、192.168.8.52 mycat讀寫分離代理服務器
實現步驟
1、主mysql服務器上安裝mysql數據庫(從mysql服務器安裝一樣,為了兼容主從同步故從mysql版本和主保持一致)
1、下載mysql源安裝包,地址:wget http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm
2、安裝mysql源 :yum localinstall mysql57-community-release-el7-8.noarch.rpm
3、檢查mysql源是否安裝成功:yum repolist enabled | grep "mysql.*-community.*"
看到這個,就說明安裝成功了。
4、安裝mysql:yum install mysql-community-server
5、啟動mysql服務:systemctl start mysqld
6、設置開啟mysql自啟動:systemctl enable mysqld 和
systemctl daemon-reload都執行
7、安裝完mysql之后在/var/log/mysqld.log文件中給root生成一個默認密碼,通過下面的方式可以找到root默認密碼,然后登錄mysql進行修改
grep 'temporary password' /var/log/mysqld.log
其中,y.0w(csyT,Sx就是默認密碼。
8、登錄mysql以及修改默認密碼
mysql -uroot -p
ALTER USER 'root'@'localhost' IDENTIFIED BY 'newpwd';
注意:mysql5.7默認安裝了密碼安全檢查插件(validate_password),默認密碼檢查策略要求密碼必須包含:大小寫字母、數字和特殊符號,並且長度不能少於8位。否則會提示ERROR 1819 (HY000): Your password does not satisfy the current policy requirements錯誤
2、配置主從同步
在此之前,先啰嗦說下主從同步的原因,在腦海中形成個初步的印象
master服務器將數據的改變記錄二進制binlog日志,當master上的數據發生改變時,則將其改變寫入二進制日志中;salve服務器會在一定時間間隔內對master二進制日志進行探測其是否發生改變,如果發生改變,則開始一個I/OThread請求master二進制事件,同時主節點為每個I/O線程啟動一個dump線程,用於向其發送二進制事件,並保存至從節點本地的中繼日志中,從節點將啟動SQL線程從中繼日志中讀取二進制日志,在本地重放,使得其數據和主節點的保持一致,最后I/OThread和SQLThread將進入睡眠狀態,等待下一次被喚醒。
注意幾點:
1--master將操作語句記錄到binlog日志中,然后授予slave遠程連接的權限(master一定要開啟binlog二進制日志功能;通常為了數據安全考慮,slave也開啟binlog功能)。
2--slave開啟兩個線程:IO線程和SQL線程。其中:IO線程負責讀取master的binlog內容到中繼日志relay log里;SQL線程負責從relay log日志里讀出binlog內容,並更新到slave的數據庫里,這樣就能保證slave數據和master數據保持一致了。
3--Mysql復制至少需要兩個Mysql的服務,當然Mysql服務可以分布在不同的服務器上,也可以在一台服務器上啟動多個服務。
4--Mysql復制最好確保master和slave服務器上的Mysql版本相同(如果不能滿足版本一致,那么要保證master主節點的版本低於slave從節點的版本)
5--master和slave兩節點間時間需同步
Mysql復制的流程圖如下:
如上圖所示:
Mysql復制過程的第一部分就是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從線程)處理該過程的最后一步。SQL線程從中繼日志讀取事件,並重放其中的事件而更新slave的數據,使其與master中的數據一致。只要該線程與I/O線程保持一致,中繼日志通常會位於OS的緩存中,所以中繼日志的開銷很小。
此外,在master中也有一個工作線程:和其它MySQL的連接一樣,slave在master中打開一個連接也會使得master開始一個線程。復制過程有一個很重要的限制——復制在slave上是串行化的,也就是說master上的並行更新操作不能在slave上並行操作。
4)Mysql復制的模式
1--主從復制:主庫授權從庫遠程連接,讀取binlog日志並更新到本地數據庫的過程;主庫寫數據后,從庫會自動同步過來(從庫跟着主庫變);
2--主主復制:主從相互授權連接,讀取對方binlog日志並更新到本地數據庫的過程;只要對方數據改變,自己就跟着改變;
5)Mysql主從復制的優點
1--在從服務器可以執行查詢工作(即我們常說的讀功能),降低主服務器壓力;(主庫寫,從庫讀,降壓)
2--在從主服務器進行備份,避免備份期間影響主服務器服務;(確保數據安全)
3--當主服務器出現問題時,可以切換到從服務器。(提升性能)
6)Mysql主從復制工作流程細節
1)MySQL支持單向、異步復制,復制過程中一個服務器充當主服務器,而一個或多個其它服務器充當從服務器。MySQL復制基於主服務器在二進制日志中跟蹤所有對數據庫的更改(更新、刪除等等)。因此,要進行復制,必須在主服務器上啟用二進制日志。每個從服務器從主服務器接收主服務器上已經記錄到其二進制日志的保存的更新。當一個從服務器連接主服務器時,它通知主服務器定位到從服務器在日志中讀取的最后一次成功更新的位置。從服務器接收從那時起發生的任何更新,並在本機上執行相同的更新。然后封鎖並等待主服務器通知新的更新。從服務器執行備份不會干擾主服務器,在備份過程中主服務器可以繼續處理更新。
2)MySQL使用3個線程來執行復制功能,其中兩個線程(Sql線程和IO線程)在從服務器,另外一個線程(IO線程)在主服務器。
當發出START SLAVE時,從服務器創建一個I/O線程,以連接主服務器並讓它發送記錄在其二進制日志中的語句。主服務器創建一個線程將二進制日志中的內容發送到從服務器。該線程可以即為主服務器上SHOW PROCESSLIST的輸出中的Binlog Dump線程。從服務器I/O線程讀取主服務器Binlog Dump線程發送的內容並將該數據拷貝到從服務器數據目錄中的本地文件中,即中繼日志。第3個線程是SQL線程,由從服務器創建,用於讀取中繼日志並執行日志中包含的更新。在從服務器上,讀取和執行更新語句被分成兩個獨立的任務。當從服務器啟動時,其I/O線程可以很快地從主服務器索取所有二進制日志內容,即使SQL線程執行更新的遠遠滯后。
1、配置主mysql數據庫配置文件:vim /usr/local/mysql/my.cnf
..............
server-
id
=1
#數據庫唯一ID,主從的標識號絕對不能重復。
log-bin=mysql-bin
#開啟bin-log,並指定文件目錄和文件名前綴
binlog-
do
-db=test_z
#需要同步的數據庫。如果是多個同步庫,就以此格式另寫幾行即可。如果不指明對某個具體庫同步,就去掉此行,表示同步所有庫(除了ignore忽略的庫)。
#binlog-ignore-db=mysql
#不同步mysql系統數據庫。如果是多個不同步庫,就以此格式另寫幾行;也可以在一行,中間逗號隔開。
sync_binlog = 1 #確保binlog日志寫入后與硬盤同步
binlog_checksum = none #跳過現有的采用checksum的事件,mysql5.6.5以后的版本中binlog_checksum=crc32,而低版本都是binlog_checksum=none
binlog_format = mixed #bin-log日志文件格式,設置為MIXED可以防止主鍵重復。
溫馨提示:在主服務器上最重要的二進制日志設置是sync_binlog,這使得mysql在每次提交事務的時候把二進制日志的內容同步到磁盤上,即使服務器崩潰也會把事件寫入日志中。
sync_binlog這個參數是對於MySQL系統來說是至關重要的,他不僅影響到Binlog對MySQL所帶來的性能損耗,而且還影響到MySQL中數據的完整性。對於
"sync_binlog"
參數的各種設置的說明如下:
sync_binlog=0,當事務提交之后,MySQL不做fsync之類的磁盤同步指令刷新binlog_cache中的信息到磁盤,而讓Filesystem自行決定什么時候來做同步,或者cache滿了之后才同步到磁盤。
sync_binlog=n,當每進行n次事務提交之后,MySQL將進行一次fsync之類的磁盤同步指令來將binlog_cache中的數據強制寫入磁盤。
在MySQL中系統默認的設置是sync_binlog=0,也就是不做任何強制性的磁盤刷新指令,這時候的性能是最好的,但是風險也是最大的。因為一旦系統Crash,在binlog_cache中的所有binlog信息都會被丟失。而當設置為“1”的時候,是最安全但是性能損耗最大的設置。因為當設置為1的時候,即使系統Crash,也最多丟失binlog_cache中未完成的一個事務,對實際數據沒有任何實質性影響。
從以往經驗和相關測試來看,對於高並發事務的系統來說,“sync_binlog”設置為0和設置為1的系統寫入性能差距可能高達5倍甚至更多。
grant replication slave,replication client on *.* to root@
'192.168.8.45'
identified by
"Zxq311915~.."
;
mysql> show master status;(注意File與Position項,從服務器需要這兩項參數)
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000007 | 120 | test_z | |
+------------------+----------+--------------+------------------+-------------------+
1 row
in
set
(0.00 sec)
...........
server-
id
=2
#設置從服務器id,必須與主服務器不同
log-bin=mysql-bin
#啟動MySQ二進制日志系統
replicate-
do
-db=test_z
#需要同步的數據庫名。如果不指明同步哪些庫,就去掉這行,表示所有庫的同步(除了ignore忽略的庫)。
#replicate-ignore-db=mysql
#不同步mysql系統數據庫
slave-skip-errors = all
#跳過所有的錯誤錯誤,繼續執行復制操作
2、配置主從同步指令
mysql>stop slave; #執行同步前,要先關閉slave
mysql>
change master to master_host=
'192.168.8.47'
,master_user=
'root'
,master_password=
'Zxq311915~..'
,master_log_file=
'mysql-bin.000007'
,master_log_pos=120;
mysql>start slave; #開啟同步
mysql>show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting
for
master to send event
Master_Host: 192.168.8.47
Master_User: slave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000007
Read_Master_Log_Pos: 120
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 279
Relay_Master_Log_File: mysql-bin.000007
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB: test_z
Replicate_Ignore_DB:
.............
Seconds_Behind_Master: 0
如上,當IO和SQL線程的狀態均為Yes,則表示主從已實現同步了!
<user name="web">
<property name="password">Zxq123456~..</property>
<property name="schemas">test_z</property>
</user>
<user name="web_r">
<property name="password">Zxq123456~..</property>
<property name="schemas">test_z</property>
<property name="readOnly">true</property>
</user>
這里配置了兩個用戶可以用來連接mycat,【用戶1:賬號,web;密碼,Zxq123456~.. ;數據庫,test_z,權限,所有 】【 用戶2:賬號,web_r;密碼,Zxq123456~..;數據庫,test_z;權限,只讀】
5、配置schema.xml文件(由於我只需要讀寫分離的配置,只進行了按需的配置,還可以添加很多其他的功能配置,可以網上自行搜索)
這里着重解釋幾個配置參數:
1、 name="test_z"這里就是對外的數據庫名稱,必須和server.xml中配置的一樣。
2、database="test_z"指真是數據庫名稱
3、balance參數可選0、1、2、3(這個選項只有mycat1.3以及之后版本才有)
0---不開啟讀寫分離機制,所有讀操作都發送到當前可用的 writeHost 上
1---全部的 readHost 與 stand by writeHost 參與 select 語句的負載均衡,簡單的說,當雙主雙從模式(M1 ->S1 , M2->S2,並且 M1 與 M2 互為主備),正常情況下, M2,S1,S2 都參與 select 語句的負載均衡
2---所有讀操作都隨機的在 writeHost、 readhost 上分發
3---所有讀請求隨機的分發到 wiriterHost 對應的 readhost 執行,writerHost 不負擔讀壓力
4、writeType參數可選0、1、2
0--所有寫操作發送到配置的第一個 writeHost,第一個掛了切到還生存的第二個
1--所有寫操作都隨機的發送到配置的 writeHost
2--沒有實現
5、switchType參數可選-1、1、2
-1--不自動切換
1--自動切換,默認值
2--根據mysql主從同步的狀態決定是否切換
6、啟動mycat
./mycat start
7、用戶授權
mysql> grant
select
,update,delete,insert on test_z.* to web@
'192.168.8.52'
identified
by
'Zxq311915~..'
;
7、測試讀寫分離
.NET控制台代碼測試;
1、由於MyCAT與MySQL協議有些許差異,開發者可能不能夠直接使用Oracle官方提供的Mysql.Data(ADO層)來與MyCAT直接連接,因此我們專門為.NET開發者設計了針對MyCAT優化過的ADO層驅動,即Pomelo.Data.MyCat,開發者通過使用MyCatConnection、MyCatCommand類可以實現對MyCAT的連接與查詢。
2、導入Pomelo.Data.Mycat
3、代碼測試
大伙還記得之前配置的參數吧,這里連接字符串要用到,mycat默認監聽端口是8066,至於怎么測試讀寫分離,我想大家都會,自行在數據庫里通過添加刪除數據來控制。
--------------------------------------------------------------------
后記
今天寫這篇文章作為個備忘錄,寫的比較簡單,算是一個大概的過程,后面會根據實際使用中按需擴展或者修改,大家如果閱讀過程中發現有不對的地方,歡迎指正。