MySQL集群中間件比較
在CentOS8下搭建PXC集群一文中,演示了如何從零開(kāi)始搭建一個(gè)三節(jié)點(diǎn)的PXC集群。但是光搭建了PXC集群還不夠,因?yàn)樵趯?shí)際的企業(yè)應(yīng)用中,可能會(huì)存在多個(gè)PXC集群,每個(gè)集群作為一個(gè)數(shù)據(jù)分片存在。因此,在完整的架構(gòu)下我們還需要為集群引入數(shù)據(jù)庫(kù)中間件,以實(shí)現(xiàn)數(shù)據(jù)分片和負(fù)載均衡等功能。
市面上有許多的數(shù)據(jù)庫(kù)中間件,這些中間件主要分為兩種類型,負(fù)載均衡型和數(shù)據(jù)切分型(通常數(shù)據(jù)切分型會(huì)具備負(fù)載均衡功能):
-
負(fù)載均衡型:
- Haproxy
- MySQL - Proxy
-
數(shù)據(jù)切分型:
- MyCat
- Atlas
- OneProxy
- ProxySQL
負(fù)載均衡型中間件的作用:
- 負(fù)載均衡提供了請(qǐng)求轉(zhuǎn)發(fā),可以將請(qǐng)求均勻的轉(zhuǎn)發(fā)到集群中的各個(gè)節(jié)點(diǎn)上,降低了單節(jié)點(diǎn)的負(fù)載
- 使得我們可以充分利用到集群中的各個(gè)節(jié)點(diǎn)的資源,以發(fā)揮集群的性能
數(shù)據(jù)切分型中間件的作用:
- 按照不同的路由算法分發(fā)SQL語(yǔ)句,讓不同的分片可以存儲(chǔ)不同的數(shù)據(jù),這樣就形成了數(shù)據(jù)切分
- 讓數(shù)據(jù)均勻的存儲(chǔ)在不同的分片上,避免某一個(gè)分片的數(shù)據(jù)量超過(guò)數(shù)據(jù)庫(kù)的存儲(chǔ)極限。這里的分片指的是一個(gè)集群或一個(gè)數(shù)據(jù)庫(kù)節(jié)點(diǎn)
以下是對(duì)常見(jiàn)的中間件進(jìn)行的一個(gè)比較:
| 名稱 | 是否開(kāi)源免費(fèi) | 負(fù)載能力 | 開(kāi)發(fā)語(yǔ)言 | 功能 | 文檔 | 普及率 |
|---|---|---|---|---|---|---|
| MyCat | 開(kāi)源免費(fèi) | 基于阿里巴巴的Corba中間件重構(gòu)而來(lái),有高訪問(wèn)量的檢驗(yàn) | Java | 功能全面,有豐富的分片算法以及讀寫分離、全局主鍵和分布式事務(wù)等功能 | 文檔豐富,不僅有官方的《Mycat權(quán)威指南》,還有許多社區(qū)貢獻(xiàn)的文檔 | 電信、電商領(lǐng)域均有應(yīng)用,是國(guó)內(nèi)普及率最高的MySQL中間件 |
| Atlas | 開(kāi)源免費(fèi) | 基于MySQL Proxy,主要用于360產(chǎn)品,有每天承載幾十億次請(qǐng)求的訪問(wèn)量檢驗(yàn) | C語(yǔ)言 | 功能有限,實(shí)現(xiàn)了讀寫分離,具有少量的數(shù)據(jù)切分算法,不支持全局主鍵和分布式事務(wù) | 文檔較少,只有開(kāi)源項(xiàng)目文檔,無(wú)技術(shù)社區(qū)和出版物 | 普及率低,除了奇虎360外,僅在一些中小型項(xiàng)目在使用,可供參考的案例不多 |
| OneProxy | 分為免費(fèi)版和企業(yè)版 | 基于C語(yǔ)言的內(nèi)核,性能較好 | C語(yǔ)言 | 功能有限,實(shí)現(xiàn)了讀寫分離,具有少量的數(shù)據(jù)切分算法,不支持全局主鍵和分布式事務(wù) | 文檔較少,官網(wǎng)不提供使用文檔,無(wú)技術(shù)社區(qū)和出版物 | 普及率低,僅僅在一些中小型企業(yè)的內(nèi)部系統(tǒng)中使用過(guò) |
| ProxySQL | 開(kāi)源免費(fèi) | 性能出眾,Percona推薦 | C++ | 功能相對(duì)豐富,支持讀寫分離、數(shù)據(jù)切分、故障轉(zhuǎn)移及查詢緩存等 | 文檔豐富,有官方文檔和技術(shù)社區(qū) | 普及率相比于Mycat要低,但已有許多公司嘗試使用 |
配置Mycat數(shù)據(jù)切分
經(jīng)過(guò)上一小節(jié)的介紹與比較,可以看出MyCat與ProxySQL是比較理想的數(shù)據(jù)庫(kù)中間件。由于MyCat相對(duì)于ProxySQL功能更全面,普及率也更高一些,所以這里采用Mycat來(lái)做為PXC集群的中間件。關(guān)于Mycat的介紹與安裝,可以參考我的另一篇Mycat 快速入門,這里就不再重復(fù)了。
本小節(jié)主要介紹如何配置Mycat的數(shù)據(jù)切分功能,讓Mycat作為前端的數(shù)據(jù)切分中間件轉(zhuǎn)發(fā)SQL請(qǐng)求到后端的PXC集群分片中。因此,這里我搭建了兩個(gè)PXC集群,每個(gè)集群就是一個(gè)分片,以及搭建了兩個(gè)Mycat節(jié)點(diǎn)和兩個(gè)Haproxy節(jié)點(diǎn)用于后面組建雙機(jī)熱備。如圖:

各個(gè)節(jié)點(diǎn)的信息如下表:
| 角色 | Host | IP |
|---|---|---|
| Haproxy-Master | Haproxy-Master | 192.168.190.140 |
| Haproxy-Backup | Haproxy-Backup | 192.168.190.141 |
| Mycat:Node1 | mycat-01 | 192.168.190.136 |
| Mycat:Node2 | mycat-02 | 192.168.190.135 |
| PXC分片-1:Node1 | PXC-Node1 | 192.168.190.132 |
| PXC分片-1:Node2 | PXC-Node2 | 192.168.190.133 |
| PXC分片-1:Node3 | PXC-Node3 | 192.168.190.134 |
| PXC分片-2:Node1 | PXC-Node1 | 192.168.190.137 |
| PXC分片-2:Node2 | PXC-Node2 | 192.168.190.138 |
| PXC分片-2:Node3 | PXC-Node3 | 192.168.190.139 |
在每個(gè)分片里創(chuàng)建一個(gè)test庫(kù),并在該庫(kù)中創(chuàng)建一張t_user表用作測(cè)試,具體的建表SQL如下:
CREATE TABLE `t_user` (
`id` int(11) NOT NULL,
`username` varchar(20) NOT NULL,
`password` char(36) NOT NULL,
`tel` char(11) NOT NULL,
`locked` char(10) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
完成以上準(zhǔn)備后,接著我們開(kāi)始配置Mycat,如果你對(duì)Mycat的配置文件不了解的話,可以參考我另一篇文章:Mycat 核心配置詳解,本文就不贅述了。
1、編輯server.xml文件,配置Mycat的訪問(wèn)用戶:
<user name="admin" defaultAccount="true">
<property name="password">Abc_123456</property>
<property name="schemas">test</property>
<property name="defaultSchema">test</property>
</user>
2、編輯schema.xml文件,配置Mycat的邏輯庫(kù)、邏輯表以及集群節(jié)點(diǎn)的連接信息:
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!-- 配置邏輯庫(kù) -->
<schema name="test" checkSQLschema="true" sqlMaxLimit="100" randomDataNode="dn1">
<!-- 配置邏輯表 -->
<table name="t_user" dataNode="dn1,dn2" rule="mod-long"/>
</schema>
<!-- 配置數(shù)據(jù)分片,每個(gè)分片都會(huì)有一個(gè)索引值,從0開(kāi)始。例如,dn1索引值為0,dn2的索引值為1,以此類推 -->
<!-- 分片的索引與分片算法有關(guān),分片算法計(jì)算得出的值就是分片索引 -->
<dataNode name="dn1" dataHost="pxc-cluster1" database="test" />
<dataNode name="dn2" dataHost="pxc-cluster2" database="test" />
<!-- 配置集群節(jié)點(diǎn)的連接信息 -->
<dataHost name="pxc-cluster1" maxCon="1000" minCon="10" balance="2"
writeType="1" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="W1" url="192.168.190.132:3306" user="admin"
password="Abc_123456">
<readHost host="W1-R1" url="192.168.190.133:3306" user="admin" password="Abc_123456"/>
<readHost host="W1-R2" url="192.168.190.134:3306" user="admin" password="Abc_123456"/>
</writeHost>
<writeHost host="W2" url="192.168.190.133:3306" user="admin"
password="Abc_123456">
<readHost host="W2-R1" url="192.168.190.132:3306" user="admin" password="Abc_123456"/>
<readHost host="W2-R2" url="192.168.190.134:3306" user="admin" password="Abc_123456"/>
</writeHost>
</dataHost>
<dataHost name="pxc-cluster2" maxCon="1000" minCon="10" balance="2"
writeType="1" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="W1" url="192.168.190.137:3306" user="admin" password="Abc_123456">
<readHost host="W1-R1" url="192.168.190.138:3306" user="admin" password="Abc_123456"/>
<readHost host="W1-R2" url="192.168.190.139:3306" user="admin" password="Abc_123456"/>
</writeHost>
<writeHost host="W2" url="192.168.190.138:3306" user="admin" password="Abc_123456">
<readHost host="W2-R1" url="192.168.190.137:3306" user="admin" password="Abc_123456"/>
<readHost host="W2-R2" url="192.168.190.138:3306" user="admin" password="Abc_123456"/>
</writeHost>
</dataHost>
</mycat:schema>
3、編輯rule.xml文件,修改mod-long分片算法的求?;鶖?shù),由于只有兩個(gè)集群作為分片,所以這里需要將基數(shù)改為2:
<tableRule name="mod-long">
<rule>
<columns>id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">2</property>
</function>
-
Tips:該分片算法使用表中
id列的值對(duì)求?;鶖?shù)進(jìn)行求模以得出數(shù)據(jù)分片的索引
完成以上三個(gè)文件的配置后,啟動(dòng)Mycat:
[root@mycat-01 ~]# mycat start
Starting Mycat-server...
[root@mycat-01 ~]# more /usr/local/mycat/logs/wrapper.log |grep successfully
# 日志輸出了 successfully 代表啟動(dòng)成功
INFO | jvm 1 | 2020/01/19 15:09:02 | MyCAT Server startup successfully. see logs in logs/mycat.log
測(cè)試
啟動(dòng)完成后,進(jìn)入Mycat中執(zhí)行一條insert語(yǔ)句,測(cè)試下是否能將該SQL轉(zhuǎn)發(fā)到正確的集群分片上。具體步驟如下:
[root@mycat-01 ~]# mysql -uadmin -P8066 -h127.0.0.1 -p
mysql> use test;
mysql> insert into t_user(id, username, password, tel, locked)
-> values(1, 'Jack', hex(AES_ENCRYPT('123456', 'Test')), '13333333333', 'N');
上面這條insert語(yǔ)句插入的是一條id為1的記錄,而我們采用的是對(duì)id列求模的分片算法,配置的求?;鶖?shù)為2。因此,根據(jù)id的值和求模基數(shù)進(jìn)行求模計(jì)算的結(jié)果為:1 % 2 = 1。得出來(lái)的1就是分片的索引,所以正常情況下Mycat會(huì)將該insert語(yǔ)句轉(zhuǎn)發(fā)到分片索引為1的集群上。
根據(jù)schema.xml文件中的配置,索引為1的分片對(duì)應(yīng)的集群是pxc-cluster2,即第二個(gè)PXC集群分片。接下來(lái),我們可以通過(guò)對(duì)比這兩個(gè)集群中的數(shù)據(jù),以驗(yàn)證Mycat是否按照預(yù)期正確地轉(zhuǎn)發(fā)了該SQL。
從下圖中可以看到,Mycat正確地將該insert語(yǔ)句轉(zhuǎn)發(fā)到了第二個(gè)分片上,此時(shí)第一個(gè)分片是沒(méi)有數(shù)據(jù)的:

接著我們?cè)贉y(cè)試當(dāng)id為2時(shí),Mycat是否能將該SQL轉(zhuǎn)發(fā)到第一個(gè)分片上。具體的SQL如下:
insert into t_user(id, username, password, tel, locked)
values(2, 'Jon', hex(AES_ENCRYPT('123456', 'Test')), '18888888888', 'N');
測(cè)試結(jié)果如圖:

在完成以上的測(cè)試后,此時(shí)在Mycat上是能夠查詢出所有分片中的數(shù)據(jù)的:

常用的四類數(shù)據(jù)切分算法
主鍵求模切分
上一小節(jié)的示例中,使用的就是主鍵求模切分,其特點(diǎn)如下:
- 主鍵求模切分適合用在初始數(shù)據(jù)很大,但是數(shù)據(jù)增長(zhǎng)不快的場(chǎng)景。例如,地圖產(chǎn)品、行政數(shù)據(jù)、企業(yè)數(shù)據(jù)等。
- 主鍵求模切分的弊端在于擴(kuò)展新分片難度大,遷移的數(shù)據(jù)太多
- 如果需要擴(kuò)展分片數(shù)量,建議擴(kuò)展后的分片數(shù)量是原有分片的2n倍。例如,原本是兩個(gè)分片,擴(kuò)展后是四個(gè)分片
主鍵范圍切分
- 主鍵范圍切分適合用在數(shù)據(jù)快速增長(zhǎng)的場(chǎng)景
- 容易增加分片,需要有明確的主鍵列
日期切分
- 日期切分適合用在數(shù)據(jù)快速增長(zhǎng)的場(chǎng)景
- 容易增加分片,需要有明確的日期列
枚舉值切分
- 枚舉值切分適合用在歸類存儲(chǔ)數(shù)據(jù)的場(chǎng)景,適合大多數(shù)業(yè)務(wù)
- 枚舉值切分按照某個(gè)字段的值(數(shù)字)與
mapFile配置的映射關(guān)系來(lái)切分?jǐn)?shù)據(jù) - 枚舉值切分的弊端在于分片存儲(chǔ)的數(shù)據(jù)不夠均勻
在Mycat 核心配置詳解一文中,也介紹過(guò)枚舉值切分算法。該算法相對(duì)于其他算法來(lái)說(shuō)要用到一個(gè)額外的映射文件(mapFile),所以這里就針對(duì)該算法的使用進(jìn)行一個(gè)簡(jiǎn)單的演示。
需求:用戶表中有一個(gè)存儲(chǔ)用戶所在區(qū)號(hào)的列,要求將該列作為分片列,實(shí)現(xiàn)讓不同區(qū)號(hào)下的用戶數(shù)據(jù)被分別存儲(chǔ)到不同的分片中
1、首先,在Mycat的rule.xml文件中,增加如下配置:
<!-- 定義分片規(guī)則 -->
<tableRule name="sharding-by-areafile">
<rule>
<!-- 定義使用哪個(gè)列作為分片列 -->
<columns>area_id</columns>
<algorithm>area-int</algorithm>
</rule>
</tableRule>
<!-- 定義分片算法 -->
<function name="area-int" class="io.mycat.route.function.PartitionByFileMap">
<!-- 定義mapFile的文件名,位于conf目錄下 -->
<property name="mapFile">area-hash-int.txt</property>
</function>
2、在conf目錄下創(chuàng)建area-hash-int.txt文件,定義區(qū)號(hào)與分片索引的對(duì)應(yīng)關(guān)系:
[root@mycat-01 /usr/local/mycat]# vim conf/area-hash-int.txt
020=0
0755=0
0757=0
0763=1
0768=1
0751=1
3、配置schema.xml,增加一個(gè)邏輯表,并將其分片規(guī)則設(shè)置為sharding-by-areafile:
<schema name="test" checkSQLschema="true" sqlMaxLimit="100" randomDataNode="dn1">
<table name="t_user" dataNode="dn1,dn2" rule="mod-long"/>
<table name="t_customer" dataNode="dn1,dn2" rule="sharding-by-areafile"/>
</schema>
4、進(jìn)入Mycat中執(zhí)行熱加載語(yǔ)句,該語(yǔ)句的作用可以使Mycat不用重啟就能應(yīng)用新的配置:
[root@mycat-01 ~]# mysql -uadmin -P9066 -h127.0.0.1 -p
mysql> reload @@config_all;
測(cè)試
完成以上配置后,我們來(lái)建個(gè)表測(cè)試一下,在所有的集群中創(chuàng)建t_customer表。具體的建表SQL如下:
create table t_customer(
id int primary key,
username varchar(20) not null,
area_id int not null
);
進(jìn)入Mycat中插入一條area_id為020的記錄:
[root@mycat-01 ~]# mysql -uadmin -P8066 -h127.0.0.1 -p
mysql> use test;
mysql> insert into t_customer(id, username, area_id)
-> values(1, 'Jack', 020);
根據(jù)映射文件中的配置,area_id為020的數(shù)據(jù)會(huì)被存儲(chǔ)到第一個(gè)分片中,如下圖:

-
Tips:這里由于
area_id是int類型的,所以前面的0會(huì)被去掉
然后再插入一條area_id為0763的記錄:
insert into t_customer(id, username, area_id)
values(2, 'Tom', 0763);
根據(jù)映射文件中的配置,area_id為0763的數(shù)據(jù)會(huì)被存儲(chǔ)到第二個(gè)分片中,如下圖:

完成以上測(cè)試后,此時(shí)在Mycat中應(yīng)能查詢到所有分片中的數(shù)據(jù):

父子表
當(dāng)有關(guān)聯(lián)的數(shù)據(jù)存儲(chǔ)在不同的分片時(shí),就會(huì)遇到表連接的問(wèn)題,在Mycat中是不允許跨分片做表連接查詢的。為了解決跨分片表連接的問(wèn)題,Mycat提出了父子表這種解決方案。
父子表規(guī)定父表可以有任意的切分算法,但與之關(guān)聯(lián)的子表不允許有切分算法,即子表的數(shù)據(jù)總是與父表的數(shù)據(jù)存儲(chǔ)在一個(gè)分片中。父表不管使用什么切分算法,子表總是跟隨著父表存儲(chǔ)。
例如,用戶表與訂單表是有關(guān)聯(lián)關(guān)系的,我們可以將用戶表作為父表,訂單表作為子表。當(dāng)A用戶被存儲(chǔ)至分片1中,那么A用戶產(chǎn)生的訂單數(shù)據(jù)也會(huì)跟隨著存儲(chǔ)在分片1中,這樣在查詢A用戶的訂單數(shù)據(jù)時(shí)就不需要跨分片了。如下圖所示:

實(shí)踐
了解了父子表的概念后,接下來(lái)我們看看如何在Mycat中配置父子表。首先,在schema.xml文件中配置父子表關(guān)系:
<schema name="test" checkSQLschema="true" sqlMaxLimit="100" randomDataNode="dn1">
<table name="t_customer" dataNode="dn1,dn2" rule="sharding-by-areafile">
<!-- 配置子表 -->
<childTable name="t_orders" joinKey="customer_id" parentKey="id"/>
</table>
</schema>
childTable標(biāo)簽說(shuō)明:
-
joinKey屬性:定義子表中用于關(guān)聯(lián)父表的列 -
parentKey屬性:定義父表中被關(guān)聯(lián)的列 -
childTable標(biāo)簽內(nèi)還可以繼續(xù)添加childTable標(biāo)簽
完成以上配置后,讓Mycat重新加載配置文件:
reload @@config_all;
測(cè)試
接著在所有分片中創(chuàng)建t_orders表,具體的建表SQL如下:
create table t_orders(
id int primary key,
customer_id int not null,
create_time datetime default current_timestamp
);
現(xiàn)在分片中有兩個(gè)用戶,id為1的用戶存儲(chǔ)在第一個(gè)分片,id為2的用戶存儲(chǔ)在第二個(gè)分片。此時(shí),通過(guò)Mycat插入一條訂單記錄:
insert into t_orders(id, customer_id)
values(1, 1);
由于該訂單記錄關(guān)聯(lián)的是id為1的用戶,根據(jù)父子表的規(guī)定,會(huì)被存儲(chǔ)至第一個(gè)分片中。如下圖:

同樣,如果訂單記錄關(guān)聯(lián)的是id為2的用戶,那么就會(huì)被存儲(chǔ)至第二個(gè)分片中:
insert into t_orders(id, customer_id)
values(2, 2);
測(cè)試結(jié)果如下:

由于父子表的數(shù)據(jù)都是存儲(chǔ)在同一個(gè)分片,所以在Mycat上進(jìn)行關(guān)聯(lián)查詢也是沒(méi)有問(wèn)題的:

組建雙機(jī)熱備的高可用Mycat集群
前言
在以上小節(jié)的示例中,我們可以看到對(duì)后端數(shù)據(jù)庫(kù)集群的讀寫操作都是在Mycat上進(jìn)行的。Mycat作為一個(gè)負(fù)責(zé)接收客戶端請(qǐng)求,并將請(qǐng)求轉(zhuǎn)發(fā)到后端數(shù)據(jù)庫(kù)集群的中間件,不可避免的需要具備高可用性。否則,如果Mycat出現(xiàn)單點(diǎn)故障,那么整個(gè)數(shù)據(jù)庫(kù)集群也就無(wú)法使用了,這對(duì)整個(gè)系統(tǒng)的影響是十分巨大的。
所以本小節(jié)將演示如何去構(gòu)建一個(gè)高可用的Mycat集群,為了搭建Mycat高可用集群,除了要有兩個(gè)以上的Mycat節(jié)點(diǎn)外,還需要引入Haproxy和Keepalived組件。
其中Haproxy作為負(fù)載均衡組件,位于最前端接收客戶端的請(qǐng)求并將請(qǐng)求分發(fā)到各個(gè)Mycat節(jié)點(diǎn)上,用于保證Mycat的高可用。而Keepalived則用于實(shí)現(xiàn)雙機(jī)熱備,因?yàn)镠aproxy也需要高可用,當(dāng)一個(gè)Haproxy宕機(jī)時(shí),另一個(gè)備用的Haproxy能夠馬上接替。也就說(shuō)同一時(shí)間下只會(huì)有一個(gè)Haproxy在運(yùn)行,另一個(gè)Haproxy作為備用處于等待狀態(tài)。當(dāng)正在運(yùn)行中的Haproxy因意外宕機(jī)時(shí),Keepalived能夠馬上將備用的Haproxy切換到運(yùn)行狀態(tài)。
Keepalived是讓主機(jī)之間爭(zhēng)搶同一個(gè)虛擬IP(VIP)來(lái)實(shí)現(xiàn)高可用的,這些主機(jī)分為Master和Backup兩種角色,并且Master只有一個(gè),而B(niǎo)ackup可以有多個(gè)。最開(kāi)始Master先獲取到VIP處于運(yùn)行狀態(tài),當(dāng)Master宕機(jī)后,Backup檢測(cè)不到Master的情況下就會(huì)自動(dòng)獲取到這個(gè)VIP,此時(shí)發(fā)送到該VIP的請(qǐng)求就會(huì)被Backup接收到。這樣Backup就能無(wú)縫接替Master的工作,以實(shí)現(xiàn)高可用。
引入這些組件后,最終我們的集群架構(gòu)將演變成這樣子:

安裝Haproxy
Haproxy由于是老牌的負(fù)載均衡組件了,所以CentOS的yum倉(cāng)庫(kù)中自帶有該組件的安裝包,安裝起來(lái)就非常簡(jiǎn)單。安裝命令如下:
[root@Haproxy-Master ~]# yum install -y haproxy
配置Haproxy:
[root@Haproxy-Master ~]# vim /etc/haproxy/haproxy.cfg
# 在文件的末尾添加如下配置項(xiàng)
# 監(jiān)控界面配置
listen admin_stats
# 綁定的ip及監(jiān)聽(tīng)的端口
bind 0.0.0.0:4001
# 訪問(wèn)協(xié)議
mode http
# URI 相對(duì)地址
stats uri /dbs
# 統(tǒng)計(jì)報(bào)告格式
stats realm Global\ statistics
# 用于登錄監(jiān)控界面的賬戶密碼
stats auth admin:abc123456
# 數(shù)據(jù)庫(kù)負(fù)載均衡配置
listen proxy-mysql
# 綁定的ip及監(jiān)聽(tīng)的端口
bind 0.0.0.0:3306
# 訪問(wèn)協(xié)議
mode tcp
# 負(fù)載均衡算法
# roundrobin:輪詢
# static-rr:權(quán)重
# leastconn:最少連接
# source:請(qǐng)求源ip
balance roundrobin
# 日志格式
option tcplog
# 需要被負(fù)載均衡的主機(jī)
server mycat_01 192.168.190.136:8066 check port 8066 weight 1 maxconn 2000
server mycat_02 192.168.190.135:8066 check port 8066 weight 1 maxconn 2000
# 使用keepalive檢測(cè)死鏈
option tcpka
由于配置了3306端口用于TCP轉(zhuǎn)發(fā),以及4001作為Haproxy監(jiān)控界面的訪問(wèn)端口,所以在防火墻上需要開(kāi)放這兩個(gè)端口:
[root@Haproxy-Master ~]# firewall-cmd --zone=public --add-port=3306/tcp --permanent
[root@Haproxy-Master ~]# firewall-cmd --zone=public --add-port=4001/tcp --permanent
[root@Haproxy-Master ~]# firewall-cmd --reload
完成以上步驟后,啟動(dòng)Haproxy服務(wù):
[root@Haproxy-Master ~]# systemctl start haproxy
然后使用瀏覽器訪問(wèn)Haproxy的監(jiān)控界面,初次訪問(wèn)會(huì)要求輸入用戶名密碼,這里的用戶名密碼就是配置文件中所配置的:

登錄成功后,就會(huì)看到如下頁(yè)面:

Haproxy的監(jiān)控界面提供的監(jiān)控信息也比較全面,在該界面下,我們可以看到每個(gè)主機(jī)的連接信息及其自身狀態(tài)。當(dāng)主機(jī)無(wú)法連接時(shí),Status一欄會(huì)顯示DOWN,并且背景色也會(huì)變?yōu)榧t色。正常狀態(tài)下的值則為UP,背景色為綠色。
另一個(gè)Haproxy節(jié)點(diǎn)也是使用以上的步驟進(jìn)行安裝和配置,這里就不再重復(fù)了。
測(cè)試Haproxy
Haproxy服務(wù)搭建起來(lái)后,我們來(lái)使用遠(yuǎn)程工具測(cè)試一下能否通過(guò)Haproxy正常連接到Mycat。如下:

連接成功后,在Haproxy上執(zhí)行一些SQL語(yǔ)句,看看能否正常插入數(shù)據(jù)和查詢數(shù)據(jù):

我們搭建Haproxy是為了讓Mycat具備高可用的,所以最后測(cè)試一下Mycat是否已具備有高可用性,首先將一個(gè)Mycat節(jié)點(diǎn)給停掉:
[root@mycat-01 ~]# mycat stop
Stopping Mycat-server...
Stopped Mycat-server.
[root@mycat-01 ~]#
此時(shí),從Haproxy的監(jiān)控界面中,可以看到mycat_01這個(gè)節(jié)點(diǎn)已經(jīng)處于下線狀態(tài)了:

現(xiàn)在集群中還剩一個(gè)Mycat節(jié)點(diǎn),然后我們到Haproxy上執(zhí)行一些SQL語(yǔ)句,看看是否還能正常插入數(shù)據(jù)和查詢數(shù)據(jù):

從測(cè)試結(jié)果可以看到,插入和查詢語(yǔ)句依舊是能正常執(zhí)行的。也就是說(shuō)即便此時(shí)關(guān)掉一個(gè)Mycat節(jié)點(diǎn)整個(gè)數(shù)據(jù)庫(kù)集群還能夠正常使用,說(shuō)明現(xiàn)在Mycat集群是具有高可用性了。
利用Keepalived實(shí)現(xiàn)Haproxy的高可用
實(shí)現(xiàn)了Mycat集群的高可用之后,我們還得實(shí)現(xiàn)Haproxy的高可用,因?yàn)楝F(xiàn)在的架構(gòu)已經(jīng)從最開(kāi)始的Mycat面向客戶端變?yōu)榱薍aproxy面向客戶端。
而同一時(shí)間只需要存在一個(gè)可用的Haproxy,否則客戶端就不知道該連哪個(gè)Haproxy了。這也是為什么要采用VIP的原因,這種機(jī)制能讓多個(gè)節(jié)點(diǎn)互相接替時(shí)依舊使用同一個(gè)IP,客戶端至始至終只需要連接這個(gè)VIP。所以實(shí)現(xiàn)Haproxy的高可用就要輪到Keepalived出場(chǎng)了,在安裝Keepalived之前需要開(kāi)啟防火墻的VRRP協(xié)議:
[root@Haproxy-Master ~]# firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --protocol vrrp -j ACCEPT
[root@Haproxy-Master ~]# firewall-cmd --reload
然后就可以使用yum命令安裝Keepalived了,需要注意Keepalived是安裝在Haproxy節(jié)點(diǎn)上的:
[root@Haproxy-Master ~]# yum install -y keepalived
安裝完成后,編輯keepalived的配置文件:
[root@Haproxy-Master ~]# mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak # 不使用自帶的配置文件
[root@Haproxy-Master ~]# vim /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state MASTER
interface ens32
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
192.168.190.100
}
}
配置說(shuō)明:
-
state MASTER:定義節(jié)點(diǎn)角色為master,當(dāng)角色為master時(shí),該節(jié)點(diǎn)無(wú)需爭(zhēng)搶就能獲取到VIP。集群內(nèi)允許有多個(gè)master,當(dāng)存在多個(gè)master時(shí),master之間就需要爭(zhēng)搶VIP。為其他角色時(shí),只有master下線才能獲取到VIP -
interface ens32:定義可用于外部通信的網(wǎng)卡名稱,網(wǎng)卡名稱可以通過(guò)ip addr命令查看 -
virtual_router_id 51:定義虛擬路由的id,取值在0-255,每個(gè)節(jié)點(diǎn)的值需要唯一,也就是不能配置成一樣的 -
priority 100:定義權(quán)重,權(quán)重越高就越優(yōu)先獲取到VIP -
advert_int 1:定義檢測(cè)間隔時(shí)間為1秒 -
authentication:定義心跳檢查時(shí)所使用的認(rèn)證信息-
auth_type PASS:定義認(rèn)證類型為密碼 -
auth_pass 123456:定義具體的密碼
-
-
virtual_ipaddress:定義虛擬IP(VIP),需要為同一網(wǎng)段下的IP,并且每個(gè)節(jié)點(diǎn)需要一致
完成以上配置后,啟動(dòng)keepalived服務(wù):
[root@Haproxy-Master ~]# systemctl start keepalived
當(dāng)keepalived服務(wù)啟動(dòng)成功,使用ip addr命令可以查看到網(wǎng)卡綁定的虛擬IP:

另一個(gè)節(jié)點(diǎn)也是使用以上的步驟進(jìn)行安裝和配置,這里就不再重復(fù)了。
測(cè)試Keepalived
以上我們完成了Keepalived的安裝與配置,最后我們來(lái)測(cè)試Keepalived服務(wù)是否正??捎?,以及測(cè)試Haproxy是否已具有高可用性。
首先,在其他節(jié)點(diǎn)上測(cè)試虛擬IP能否正常ping通,如果不能ping通就需要檢查配置了。如圖,我這里是能正常ping通的:

常見(jiàn)的虛擬IP ping不通的情況:
- 防火墻配置有誤,沒(méi)有正確開(kāi)啟VRRP協(xié)議
- 配置的虛擬IP與其他節(jié)點(diǎn)的IP不處于同一網(wǎng)段
- Keepalived配置有誤,或Keepalived根本沒(méi)啟動(dòng)成功
確認(rèn)能夠從外部ping通Keepalived的虛擬IP后,使用Navicat測(cè)試能否通過(guò)虛擬IP連接到Mycat:

連接成功后,執(zhí)行一些語(yǔ)句測(cè)試能否正常插入、查詢數(shù)據(jù):

到此就基本沒(méi)什么問(wèn)題了,最后測(cè)試一下Haproxy的高可用性,將其中一個(gè)Haproxy節(jié)點(diǎn)上的keepalived服務(wù)給關(guān)掉:
[root@Haproxy-Master ~]# systemctl stop keepalived
然后再次執(zhí)行執(zhí)行一些語(yǔ)句測(cè)試能否正常插入、查詢數(shù)據(jù),如下能正常執(zhí)行代表Haproxy節(jié)點(diǎn)已具有高可用性:
