前言¶
筆者在《MySQL數據庫實現主從複製》這一篇文章中有提到讀寫分離這個技術,這個技術時基於主從複製之後的一種技術。在數據庫主從複製中,一個主數據庫有一個或者多個從數據庫,我們可以對主數據庫進行寫入操作(insert,delete,update),對一個或者多個從數據庫進行讀取操作(select)。這個的操作方式,就是大量的查詢請求也會分佈到各個從數據庫上,達到負載均衡,比如3個從數據庫,有9條查詢請求,那麼每一個從數據庫只要處理3條查詢請求就可以了,大大減少了數據庫的查詢壓力。
在Mycat中,讀寫分離可以說有兩種,一種是一主一從,另一種是一主多從。我們分別來介紹這兩種方式:
一主一從: 是一個主數據庫一個從數據庫,如果我們對主數據庫進行寫入操作,那麼從數據庫也會執行相應的操作。筆者把一主多從也歸爲這種方式,因爲一主多從其實也就是增加多幾個從數據庫而已,具體的結構每個變動太大。在一主一從中,最大的好處是實現了讀寫分離,在Mycat的調度下,把所有寫的操作都是在主數據庫中,把所有的讀的操作都放在從數據庫中。可能有讀者可能會有疑問,這中讀取分離也可以使用後端代碼實現,爲什麼要使用Mycat呢。主要是使用Mycat配置會更加簡單,更容易維護,當數據庫的位置發生了變化,如果是使用代碼實現的,那麼網站的後端代碼要全部修改了,對於分佈式的後端服務器來說,那工作量是非常大的。再且使用後端代碼實現的讀寫分離也很難實現數據庫的分佈式。而使用Mycat都能解決這些問題。
如圖所示:

雙主雙從: 這個主要是保證數據的安全,保證數據庫的高可用。在這篇文章《MySQL數據庫實現主從複製》中,筆者也介紹到主從複製最大的作用就是保證數據的安全。在一主一從中,我們的從數據庫在數據安全性上並沒有發揮到最好,只是爲了提供讀寫分離和查詢負載均衡。當主數據庫服務器掛掉了,那麼就無法進行寫入數據,整個數據庫就無法正常工作了。所以雙主雙從或者多主多從的出現就是爲了解決這個問題的,在雙主雙從模式下(M1 ->S1 , M2->S2,M1->M2,M2->M1並且 M1 與 M2 互爲主備),這種雙主雙從的模型,只要我們對M1或者M2任意一個主數據庫插入數據,其他3個數據庫也會作相應的改動。因爲M1和M2是互爲主從數據庫,所以兩個數據庫是互相同步的,另外兩個數據庫是他們的從數據庫,寫入操作也會更新從數據庫。當M1掛掉了,會自動啓動M2作爲該數據庫的主數據庫,保證了網站的正確運行。同時在正常情況下,M2,S1,S2 都參與查詢的負載均衡。
如圖所示:

那麼下面就介紹Mycat中間件實現一主一從和雙主雙從的讀寫分離,在閱讀下面教程之前,讀者應該先閱讀筆者之前的兩篇文章,分別是《CentOS下安裝和使用Mycat實現分佈式數據庫》和《MySQL數據庫實現主從複製》,在接下來的教程中會運用到這兩篇文章的知識,所以讀者要閱讀並理解這兩篇文件的知識。好,我們現在開始吧。
一主一從讀寫分離¶
我們一共使用5個虛擬機,每個機器的作用如下:
| 主機名 | IP地址 | 任務角色 | 數據庫 |
|---|---|---|---|
| node1 | 192.168.204.121 | Mycat | 無 |
| node2 | 192.168.204.122 | master1 | MySQL |
| node3 | 192.168.204.123 | slave1 | MySQL |
| node4 | 192.168.204.124 | master2 | MySQL |
| node5 | 192.168.204.125 | slave2 | MySQL |
MySQL數據庫配置¶
首先我們要在node2、node3、node4和node5上安裝MySQL數據庫,安裝方式 可以參考《MySQL數據庫實現主從複製》的安裝MySQL部分,這裏就不展開講了。安裝完成之後要對數據庫做一些配置,如下:
node2的數據庫是node3的數據庫的主數據庫,所以node2數據庫的配置文件/etc/my.cnf如下:
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
default-character-set=utf8 # 設置編碼方式
lower_case_table_names=1 # 不區分字母大小寫
log-bin=mysql-bin # 開啓二進制日誌
server-id=1 # 設置server-id
# 不同步哪些數據庫
binlog-ignore-db = mysql
binlog-ignore-db = test
binlog-ignore-db = information_schema
# 只同步哪些數據庫,除此之外,其他不同步
# binlog-do-db = game
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
node3的數據庫是node2上數據庫的從數據庫,所以不用修改太多。node3數據庫的配置文件/etc/my.cnf如下:
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
default-character-set=utf8
lower_case_table_names=1
server-id=2 #設置server-id,必須唯一
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
node4的數據庫是node5的數據庫的主數據庫,所以node4數據庫的配置文件/etc/my.cnf如下:
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
default-character-set=utf8 # 設置編碼方式
lower_case_table_names=1 # 不區分字母大小寫
log-bin=mysql-bin # 開啓二進制日誌
server-id=3 # 設置server-id
# 不同步哪些數據庫
binlog-ignore-db = mysql
binlog-ignore-db = test
binlog-ignore-db = information_schema
# 只同步哪些數據庫,除此之外,其他不同步
# binlog-do-db = game
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
node5的數據庫是node4上數據庫的從數據庫,所以不用修改太多。node5數據庫的配置文件/etc/my.cnf如下:
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
default-character-set=utf8
lower_case_table_names=1
server-id=4 #設置server-id,必須唯一
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
方便之後的操作,我們關閉了全部虛擬機的防火牆:
service iptables stop
全部都修改了配置文件,所以全部都要重啓MySQL數據庫:
service mysqld restart
我們進入到node2數據庫中,輸入以下命令查看相關信息:
mysql> show master status;
得到的信息如下:
mysql> show master status;
+------------------+----------+--------------+-------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+-------------------------------+
| mysql-bin.000007 | 106 | | mysql,test,information_schema |
+------------------+----------+--------------+-------------------------------+
1 row in set (0.00 sec)
根據node2這個主數據庫的信息,開始配置node3的從數據庫,進入到node3數據庫 中,輸入以下命令,注意master_log_file和master_log_pos來自於上一步獲取到的node2主數據庫的信息:
mysql> change master to master_host='192.168.204.122', master_user='root', master_password='root', master_log_file='mysql-bin.000007', master_log_pos=106;
在執行上一條命令之前,要保證slave是關閉的,如果沒用關閉,使用以下命令關閉:
mysql> stop slave;
配置完成之後,要啓動slave,執行下面的命令啓動slave:
mysql> start slave;
其中完成之後使用以下命令查看啓動的情況:
mysql> show slave status\G;
正常情況下輸出以下內容,要保證Slave_IO_Running和Slave_SQL_Running是Yes:
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.204.122
Master_User: root
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000007
Read_Master_Log_Pos: 106
Relay_Log_File: mysqld-relay-bin.000002
Relay_Log_Pos: 251
Relay_Master_Log_File: mysql-bin.000007
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 106
Relay_Log_Space: 407
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
1 row in set (0.00 sec)
ERROR:
No query specified
接下來開始配置node4數據庫中,進入到node4數據庫並輸入以下命令查看相關信息:
mysql> show master status;
得到的信息如下:
mysql> show master status;
+------------------+----------+--------------+-------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+-------------------------------+
| mysql-bin.000001 | 106 | | mysql,test,information_schema |
+------------------+----------+--------------+-------------------------------+
1 row in set (0.00 sec)
根據node4這個主數據庫的信息,開始配置node5的從數據庫,進入到node5數據庫 中,輸入以下命令,注意master_log_file和master_log_pos來自於上一步獲取到的node4主數據庫的信息:
mysql> change master to master_host='192.168.204.124', master_user='root', master_password='root', master_log_file='mysql-bin.000001', master_log_pos=106;
在執行上一條命令之前,要保證slave是關閉的,如果沒用關閉,使用以下命令關閉:
mysql> stop slave;
配置完成之後,要啓動slave,執行下面的命令啓動slave:
mysql> start slave;
其中完成之後使用以下命令查看啓動的情況:
mysql> show slave status\G;
正常情況下輸出以下內容,要保證Slave_IO_Running和Slave_SQL_Running是Yes:
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.204.124
Master_User: root
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 106
Relay_Log_File: mysqld-relay-bin.000002
Relay_Log_Pos: 251
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 106
Relay_Log_Space: 407
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
1 row in set (0.00 sec)
ERROR:
No query specified
Mycat的配置¶
關於Mycat的安裝可以參考《CentOS下安裝和使用Mycat實現分佈式數據庫》安裝和配置Mycat,這裏就不再介紹Mycat的安裝了,這一部分主要是介紹Mycat配置讀寫分離。
安裝完成之後,開始配置schema.xml文件,我們的讀寫分離主要是在這裏配置的。
vim $MYCAT_HOME/conf/schema.xml
該配置文件如下,我們創建了兩個數據庫,分別是yeyupiaoling1和yeyupiaoling2,主要是分佈式數據庫,數據採用分片存儲。這個兩個數據庫都有同一張employee表,也可以配置多個表。我們的讀寫分離主要是在dataHost裏配置。主要的配置有三個balance="1" writeType="0" switchType="1",它們的作用分別是:
balance 屬性負載均衡類型,目前的取值有 4 種:
balance="0",不開啓讀寫分離機制,所有讀操作都發送到當前可用的writeHost 上。balance="1",全部的 readHost 與 stand by writeHost 參與 select 語句的負載均衡,簡單的說,當雙主雙從模式(M1 ->S1 , M2->S2,並且 M1 與 M2 互爲主備),正常情況下, M2,S1,S2 都參與 select 語句的負載均衡。balance="2",所有讀操作都隨機的在 writeHost、 readhost 上分發。balance="3", 所有讀請求隨機的分發到 wiriterHost 對應的 readhost 執行,writerHost 不負擔讀壓力,注意 balance=3 只在 1.4 及其以後版本有, 1.3 沒有。
writeType 屬性,負載均衡類型,目前的取值有 3 種:
writeType="0",所有寫操作發送到配置的第一個 writeHost,第一個掛了切到還生存的第二個writeHost,重新啓動後已切換後的爲準,切換記錄在配置文件中:dnindex.properties .writeType="1",所有寫操作都隨機的發送到配置的 writeHost,1.5 以後廢棄不推薦。writeType="2",官方文檔沒有介紹。
switchType 屬性:
- -1 表示不自動切換
- 1 默認值,自動切換
- 2 基於MySQL 主從同步的狀態決定是否切換
下面就是schema.xml文件全部配置信息:
<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://org.opencloudb/">
<!-- 設置表的存儲方式.schema name="JamesMycatSchema" 與 server.xml中的 JamesMycatSchema 設置一致 -->
<schema name="JamesMycatSchema" checkSQLschema="false" sqlMaxLimit="100">
<table name="employee" primaryKey="ID" dataNode="dn2,dn3" rule="sharding-by-intfile" />
</schema>
<!--數據節點dn1,對應的主機c1,對應是數據庫db1 -->
<dataNode name="dn2" dataHost="node2" database="yeyupiaoling1" />
<dataNode name="dn3" dataHost="node4" database="yeyupiaoling2" />
<!-- 主機C2-->
<dataHost name="node2" maxCon="1000" minCon="10" balance="1" writeType="0" switchType="1"
dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<!--MySQL的寫的數據,master1 -->
<writeHost host="hostM2" url="192.168.204.122:3306" user="root" password="root">
<!--MySQL讀的數據庫,slave1 -->
<readHost host="hostM3" url="192.168.204.123:3306" user="root" password="root"/>
</writeHost>
</dataHost>
<!-- 主機C3-->
<dataHost name="node4" maxCon="1000" minCon="10" balance="1" writeType="0" switchType="1"
dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<!--MySQL的寫的數據,master2 -->
<writeHost host="hostM4" url="192.168.204.124:3306" user="root" password="root">
<!--MySQL讀的數據庫,slave2 -->
<readHost host="hostM5" url="192.168.204.125:3306" user="root" password="root"/>
</writeHost>
</dataHost>
</mycat:schema>
然後配置server.xml,這裏主要是配置Mycat的登錄賬戶和密碼的,其中schemas的值要對應schema.xml中的schema的name的值。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://org.opencloudb/">
<system>
<property name="defaultSqlParser">druidparser</property>
</system>
<user name="mycat">
<property name="password">123456</property>
<property name="schemas">JamesMycatSchema</property>
</user>
</mycat:server>
配置完成之後,可以重啓Mycat:
mycat restart
啓動之後,可以分別查看輸出的日誌信息,觀察是否正常啓動了:
tail -f $MYCAT_HOME/logs/wrapper.log
tail -f $MYCAT_HOME/logs/mycat.log
測試¶
正常其中之後,可以測試整個數據庫是否符合了分佈式切片存儲和讀寫分離。筆者使用的是NavicatForMySQL連接數據庫,讀者可以使用自己熟悉的連接工具,或者是直接在命令行上直接操作。
首先連接node2數據庫並在上面創建一個yeyupiaoling1數據庫:

然後在node2的yeyupiaoling1數據庫上創建一張employee表:
create table employee(id int not null primary key,name varchar(100),sharding_id int not null);
可以在新建查詢上執行這個SQL語句,其中字段sharding_id非常重要,我們選擇的規則就是Mycat是根據這個字段來分片存儲數據庫。

同樣連接node4數據庫並在上面創建一個yeyupiaoling2數據庫:

然後在node4的yeyupiaoling2數據庫上創建一張employee表,同樣的執行方式,就不重複介紹了。
create table employee(id int not null primary key,name varchar(100),sharding_id int not null);

然後連接node1的Mycat,記得Mycat默認的端口是8066,賬號和密碼是server.xml中設置的。連接之後可以看到一個JamesMycatSchema數據庫,這個就是我們在schema.xml配置的,可以看到有一張employee表,我們新建查詢在這裏插入一些數據:
insert into employee(id,name,sharding_id) values(1, 'I am db1',10000);
insert into employee(id,name,sharding_id) values(2, 'I am db2',10010);
insert into employee(id,name,sharding_id) values(3, 'I am db3',10010);
insert into employee(id,name,sharding_id) values(4, 'I am db1',10000);
insert into employee(id,name,sharding_id) values(5, 'I am db2',10010);
insert into employee(id,name,sharding_id) values(6, 'I am db3',10010);
insert into employee(id,name,sharding_id) values(7, 'I am db1',10000);
insert into employee(id,name,sharding_id) values(8, 'I am db2',10010);
insert into employee(id,name,sharding_id) values(9, 'I am db3',10010);
insert into employee(id,name,sharding_id) values(10, 'I am db1',10000);
insert into employee(id,name,sharding_id) values(11, 'I am db2',10010);
insert into employee(id,name,sharding_id) values(12, 'I am db3',10010);
insert into employee(id,name,sharding_id) values(13, 'I am db1',10000);
insert into employee(id,name,sharding_id) values(14, 'I am db2',10010);
insert into employee(id,name,sharding_id) values(15, 'I am db3',10010);
insert into employee(id,name,sharding_id) values(16, 'I am db1',10000);
insert into employee(id,name,sharding_id) values(17, 'I am db2',10010);
insert into employee(id,name,sharding_id) values(18, 'I am db3',10010);

在Mycat中可以可以看到employee表已經插入的全部數據。

然後在node2和node3的數據庫中都可以看到插入的數據庫,根據分片規則存儲方式,這裏是就是這個數據庫存儲的數據。

同樣在node4和node5上也存儲了另一部分的數據。

從上面來看,分佈式存儲和主從複製已經沒有問題了,那麼我們如何支持是不是讀寫分離呢,那麼我們接下來就測試一下是不是讀寫分離。
首先我們把node5數據庫的數據庫全部清空,也就是node4的從數據庫。

node5的數據庫的數據清空了,但node5的主數據庫node4數據庫並沒清空,數據還是存在的。如果在Mycat上查詢不到node4數據庫的數據,那麼就證明在查詢的時候只是查詢的從數據庫的數據,也就是在schema.xml的dataHost配置dataHost指定的數據庫。

經過在Mycat上查詢,發現結果如預想的一樣,所以證明了是讀寫分離的。

雙主雙從讀寫分離¶
在這一部分,我們來實現雙主雙從讀寫分離,主要在上一步的基礎之上做一些修改。在上一部分的一主一從讀寫分離中,M1->S1,M2->S2,但是M1和M2是沒有關係的。而在雙主雙從上M1和M2是互爲主從關係,它們各自是對方的主從數據庫,這樣的話,無論是M1或者M2發生數據變化,其他的數據庫也會發生相應的變化。在開始之前,先清空數庫之前的數據,保證各個數據庫一致。
MySQL數據庫配置¶
在上一部分的MySQL的配置基礎上,這部分的修改並不多,但爲了讀者更清楚瞭解各個配置文件的內容,筆者將會展示所有的配置信息:
node2(master1)的MySQL配置文件/etc/my.cnf,主要是增加了log-slave-updates,增加這個的作用主要是爲了當node2(master1)的數據庫作爲node4(master2)的從數據庫時,node4(master2)的數據發生更改時,作爲從數據庫的node2(master1)也會發生相應改變,但是如果沒有添加log-slave-updates的話,作爲從數據庫的node2(master1)在跟着node4進行寫入操作時,這個寫入操作node2(master1)並不會添加到bin二進制文件中,所以node2(master1)的從數據庫node3(slave1)就不會跟着改變,這樣的話就node3就不會跟node4(master2)的數據同步。
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
default-character-set=utf8 # 設置編碼方式
lower_case_table_names=1 # 不區分字母大小寫
log-bin=mysql-bin # 開啓二進制日誌
server-id=1 # 設置server-id
log-slave-updates # 在作爲從數據庫的時候,有寫入操作也要更新二進制日誌文件
# 不同步哪些數據庫
binlog-ignore-db = mysql
binlog-ignore-db = test
binlog-ignore-db = information_schema
# 只同步哪些數據庫,除此之外,其他不同步
# binlog-do-db = game
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
node3數據庫的配置文件/etc/my.cnf,這個配置不用做修改:
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
default-character-set=utf8
lower_case_table_names=1
server-id=2 #設置server-id,必須唯一
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
node4的配置跟node2一樣,主要不同的是server-id:
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
default-character-set=utf8 # 設置編碼方式
lower_case_table_names=1 # 不區分字母大小寫
log-bin=mysql-bin # 開啓二進制日誌
server-id=3 # 設置server-id
log-slave-updates # 在作爲從數據庫的時候,有寫入操作也要更新二進制日誌文件
# 不同步哪些數據庫
binlog-ignore-db = mysql
binlog-ignore-db = test
binlog-ignore-db = information_schema
# 只同步哪些數據庫,除此之外,其他不同步
# binlog-do-db = game
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
node5數據庫的配置文件/etc/my.cnf,也是一樣只要修改server-id:
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
default-character-set=utf8
lower_case_table_names=1
server-id=4 #設置server-id,必須唯一
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
node2的MySQL的信息如下:
mysql> show master status;
+------------------+----------+--------------+-------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+-------------------------------+
| mysql-bin.000008 | 106 | | mysql,test,information_schema |
+------------------+----------+--------------+-------------------------------+
1 row in set (0.00 sec)
配置node2的從數據庫,需要配置的是node3和node4的數據庫,配置如下:
首先要關閉slave:
mysql> stop slave;
配置信息,注意master_log_file和master_log_pos的值:
mysql> change master to master_host='192.168.204.122', master_user='root', master_password='root', master_log_file='mysql-bin.000008', master_log_pos=106;
然後啓動slave:
mysql> start slave;
node4的MySQL的信息如下:
mysql> show master status;
mysql> show master status;
+------------------+----------+--------------+-------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+-------------------------------+
| mysql-bin.000002 | 106 | | mysql,test,information_schema |
+------------------+----------+--------------+-------------------------------+
1 row in set (0.00 sec)
配置node4的從數據庫,需要配置的是node2和node5的數據庫,配置如下:
首先要關閉slave:
mysql> stop slave;
配置信息,注意master_log_file和master_log_pos的值:
mysql> change master to master_host='192.168.204.124', master_user='root', master_password='root', master_log_file='mysql-bin.000002', master_log_pos=106;
然後啓動slave:
mysql> start slave;
配置完成就可以查看各個數據庫的配置信息了,觀察是否配置成功了,以下是node2的配置信息:
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.204.124
Master_User: root
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 106
Relay_Log_File: mysqld-relay-bin.000002
Relay_Log_Pos: 251
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 106
Relay_Log_Space: 407
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
1 row in set (0.00 sec)
ERROR:
No query specified
然後我們可以使用NavicatForMySQL連接node2數據庫,我們可以測試只對master1數據庫執行寫操作,其他的數據庫是不是也會做相應的改變。
比如我們在node2的數據庫創建一個yeyupiaoling數據庫:

然後在這個數據庫上創建一張employee表:
create table employee(id int not null primary key,name varchar(100),sharding_id int not null);
然後我們發現其它的數據庫也會做相應的改變:

證明了我們的配置是正確的。
Mycat的配置¶
我們首先配置schema.xml:
vim $MYCAT_HOME/conf/schema.xml
配置信息如下:
<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://org.opencloudb/">
<!-- 設置表的存儲方式.schema name="JamesMycatSchema" 與 server.xml中的 JamesMycatSchema 設置一致 -->
<schema name="JamesMycatSchema" checkSQLschema="false" sqlMaxLimit="100">
<table name="employee" primaryKey="ID" dataNode="dn2" rule="sharding-by-intfile" />
</schema>
<!--數據節點dn1,對應的主機c1,對應是數據庫db1 -->
<dataNode name="dn2" dataHost="node2" database="yeyupiaoling" />
<!-- 主機C2-->
<dataHost name="node2" maxCon="1000" minCon="10" balance="1" writeType="0" switchType="1"
dbType="mysql" dbDriver="native">
<heartbeat>select user()</heartbeat>
<!--MySQL的寫的數據,master1 -->
<writeHost host="hostM2" url="192.168.204.122:3306" user="root" password="root">
<!--MySQL讀的數據庫,slave1 -->
<readHost host="hostM3" url="192.168.204.123:3306" user="root" password="root"/>
</writeHost>
<!--MySQL的寫的數據,master2 -->
<writeHost host="hostM4" url="192.168.204.124:3306" user="root" password="root">
<!--MySQL讀的數據庫,slave2 -->
<readHost host="hostM5" url="192.168.204.125:3306" user="root" password="root"/>
</writeHost>
</dataHost>
</mycat:schema>
然後配置server.xml:
vim $MYCAT_HOME/conf/server.xml
配置信息如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://org.opencloudb/">
<system>
<property name="defaultSqlParser">druidparser</property>
</system>
<user name="mycat">
<property name="password">123456</property>
<property name="schemas">JamesMycatSchema</property>
</user>
</mycat:server>
配置partition-hash-int.txt:
vim $MYCAT_HOME/conf/partition-hash-int.txt
因爲我們選擇的分片規則是sharding-by-intfile,所以Mycat會根據sharding_id進行分片存儲到不同的數據庫節點的上,因爲我們上面配置的數據庫只是配置了一個數據庫節點,所以這個文件只是配置了一個:
10000=0
配置完成之後,要重新啓動Mycat:
mycat restart
啓動之後,可以分別查看輸出的日誌信息,觀察是否正常啓動了:
tail -f $MYCAT_HOME/logs/wrapper.log
tail -f $MYCAT_HOME/logs/mycat.log
正常啓動啓動之後,測試是否一切正常了。
測試¶
首先我們連接Mycat,然後在Mycat上對employee表添加數據:
insert into employee(id,name,sharding_id) values(1, 'I am db1',10000);
insert into employee(id,name,sharding_id) values(2, 'I am db2',10000);
insert into employee(id,name,sharding_id) values(3, 'I am db3',10000);
insert into employee(id,name,sharding_id) values(4, 'I am db1',10000);
insert into employee(id,name,sharding_id) values(5, 'I am db2',10000);
insert into employee(id,name,sharding_id) values(6, 'I am db3',10000);
insert into employee(id,name,sharding_id) values(7, 'I am db1',10000);
insert into employee(id,name,sharding_id) values(8, 'I am db2',10000);
insert into employee(id,name,sharding_id) values(9, 'I am db3',10000);
insert into employee(id,name,sharding_id) values(10, 'I am db1',10000);
insert into employee(id,name,sharding_id) values(11, 'I am db2',10000);
insert into employee(id,name,sharding_id) values(12, 'I am db3',10000);
insert into employee(id,name,sharding_id) values(13, 'I am db1',10000);
insert into employee(id,name,sharding_id) values(14, 'I am db2',10000);
insert into employee(id,name,sharding_id) values(15, 'I am db3',10000);
insert into employee(id,name,sharding_id) values(16, 'I am db1',10000);
insert into employee(id,name,sharding_id) values(17, 'I am db2',10000);
insert into employee(id,name,sharding_id) values(18, 'I am db3',10000);
操作如下:

然後我們連接4個數據庫,查看它們的數據,發現是跟預期的一樣,每個數據庫都插入了數據:

讀寫分離在上一部分已經測試過了,這裏主要是測試一下查詢負載均衡,這裏筆者刪除了node5(slave2)的id爲10之後的數據:

node3(slave1)數據庫的刪除id爲10之前的:

node4(master2)的數據庫的數據不做修改:

然後我們在Mycat上不斷進行查詢操作,觀察查詢到的結果,就可以判斷是不是slave1、master2、slave2都查詢。從查詢的結果來看,的確slave1、master2、slave2都查詢。



然後測試高可用作用,我們手動關閉node2(master1)數據庫,看看是不是自動啓用node4(master2)作爲主數據庫了。當我們關閉了node2(master1)的數據庫,發現Mycat還能正常工作,但是無論我們怎麼刷新查詢操作,都只能查詢到一下的數據,這個是node5(slave2)數據庫中的數據。這種情況證明了兩件事情,一是當node2(master)數據庫掛掉了,會自動啓用node4(master2)作爲主數據庫,二是如果主數據庫掛掉了,其的從數據庫也不會參與查詢操作,這樣保證了數據的一致性。
關閉數據庫命令:
service mysqld stop

然後我們在node4數據庫上插入一條數據,主要是觀察當再次啓動node2的數據庫時,會不會保證數據庫的數據一致。
insert into employee(id,name,sharding_id) values(20, 'hello',10000);

然後我們再啓動MySQL數據庫,觀察到在node4添加的數據也被添加到這裏了。
啓動數據庫命令:
service mysqld start

最後有一點要說的是,在真實的項目中,不應該對從數據庫(slave)做寫入操作,這樣會破壞數據的一致性的。上面筆者的操作主要是爲了測試使用的。
參考資料¶
- https://blog.csdn.net/ydyang1126/article/details/70224185
- https://www.cnblogs.com/biglittleant/p/7059569.html
- https://blog.csdn.net/qq_33200967/article/details/80939040
- https://blog.csdn.net/qq_33200967/article/details/80863305