寫在前面:本文寫作前景為在b站上看到的一個(gè)三高(高可用、高并發(fā)、高性能)的分布式集群架構(gòu)方案,并對(duì)其中的pxc集群以及haproxy負(fù)載均衡進(jìn)行了試驗(yàn)。如若文中出現(xiàn)錯(cuò)誤,歡迎廣大網(wǎng)友提出。
保護(hù)知識(shí)產(chǎn)權(quán),本文參考了如下博客文章
- pxc集群搭建
http://www.itdecent.cn/p/eae6b12c1cd5 - haproxy負(fù)載均衡
https://blog.csdn.net/qq_21108311/article/details/82973763 - 分布式集群理解
https://www.cnblogs.com/zyxblogPHP/p/10706206.html
如有侵權(quán)請(qǐng)聯(lián)系刪除
一 為什么需要分布式與集群
為什么需要分布式?舉一個(gè)簡單的例子如果應(yīng)用程序和服務(wù)器在同一臺(tái)機(jī)器上時(shí),如果這臺(tái)服務(wù)負(fù)載達(dá)到上限需要將整個(gè)應(yīng)用遷到一個(gè)更高的性能的機(jī)器上。如果采用分布式架構(gòu),如果是數(shù)據(jù)庫服務(wù)器性能達(dá)到上限只需要增加數(shù)據(jù)庫服務(wù)器的性能。將數(shù)據(jù)庫、應(yīng)用程序、緩存等分開也可以方便對(duì)各部分進(jìn)行管理。
為什么需要集群?以校園網(wǎng)為例,校園網(wǎng)采用單一的數(shù)據(jù)庫節(jié)點(diǎn)。當(dāng)選課開始或者成績公布時(shí),大量請(qǐng)求涌入,由于壓力過大這臺(tái)服務(wù)器突然宕機(jī)整個(gè)系統(tǒng)就會(huì)崩潰。采用集群的方案,如果一臺(tái)數(shù)據(jù)庫宕機(jī)還會(huì)有其它數(shù)據(jù)庫保證整個(gè)服務(wù)正常進(jìn)行。
采用分布式的集群如果某一節(jié)點(diǎn)性能不夠,最簡單的方式就可以采用增加節(jié)點(diǎn)的服務(wù)器。
二 MySQL集群
MySQL集群方案有兩種,分別為pxc(Percona XtraDB Cluster)和Replication,這兩種方案各有優(yōu)缺點(diǎn)。
pxc為強(qiáng)一致性集群方案,數(shù)據(jù)同步為雙向同步,集群中的每一個(gè)節(jié)點(diǎn)都可以是主節(jié)點(diǎn)。例如:當(dāng)向pxc集群中的某一臺(tái)數(shù)據(jù)庫發(fā)出寫操作后,只有當(dāng)集群中所有節(jié)點(diǎn)都寫入完成才會(huì)返回寫入成功。這種方式可以保證每個(gè)節(jié)點(diǎn)的數(shù)據(jù)都是一致的,當(dāng)然性能也受集群中最慢的節(jié)點(diǎn)影響。
Replication方案為讀寫分離方案數(shù)據(jù),數(shù)據(jù)同步為單向同步。當(dāng)向主庫進(jìn)行寫操作后會(huì)進(jìn)過一段延遲寫入從庫,所以其一致性較弱。從庫寫入數(shù)據(jù)后不會(huì)同步到主庫
總結(jié)如下:
| 特點(diǎn) | pxc | Replication |
|---|---|---|
| 速度 | 慢 | 快 |
| 一致性 | 強(qiáng) | 弱 |
| 應(yīng)用場(chǎng)景 | 財(cái)務(wù)、賬戶、訂單 | 新聞、帖子、日志 |
這里選擇pxc集群搭建
數(shù)據(jù)備份方案:Xtrabackup熱備
三 負(fù)載均衡與雙機(jī)熱備
三大主流負(fù)載均衡器,Nginx,HAProxy,LVS,簡單對(duì)比如下
| - | Nginx | HAProxy | LVS |
|---|---|---|---|
| 免費(fèi) | 是 | 是 | 是 |
| 虛擬主機(jī) | 支持 | 支持 | 不支持 |
| 支持協(xié)議 | http | http、tcp | tcp |
| 配置 | 簡單 | 簡單 | 復(fù)雜 |
| 負(fù)載算法 | 輪詢、加權(quán)輪詢、ip哈希 | 輪詢、加權(quán)輪詢、原地址保持、請(qǐng)求URL、根據(jù)cookie | 輪詢、加權(quán)輪詢、最小連接、權(quán)重最小連接 |
可參考鏈接:https://www.cnblogs.com/HacTF/p/7774106.html
這里選擇HAproxy作為負(fù)載均衡器,HAproxy還提供一個(gè)監(jiān)控界面來查看當(dāng)前HAProxy的運(yùn)行狀態(tài)。
關(guān)于雙機(jī)熱備
為什么采用雙機(jī)熱備?在pxc集群中,如果一臺(tái)MySQL掛掉會(huì)有其它MySQL保證系統(tǒng)的正常運(yùn)行,但是如果HAProxy掛掉整個(gè)pxc集群都將無法訪問。在這里就需要一個(gè)備份HAProxy在主HAproxy掛掉后及時(shí)接替主HAProxy的工作保證系統(tǒng)的正常。
怎樣進(jìn)行雙機(jī)熱備方案?采用keepalived。keepalived是以VRRP(Vritrual Router Redundancy Protocol,虛擬路由冗余協(xié)議)協(xié)議為基礎(chǔ)用來保證集群高可用性,防止單點(diǎn)故障的一個(gè)軟件。
keepalived工作原理:keepalived將提供一個(gè)雙機(jī)浮動(dòng)的vip(虛擬ip),這樣可以簡單實(shí)現(xiàn)一個(gè)雙機(jī)熱備高可用功能。即將N臺(tái)提供相同功能的路由器組成一個(gè)路由器組,這個(gè)組里面有一個(gè)master和多個(gè)backup,master上面有一個(gè)對(duì)外提供服務(wù)的vip(該路由器所在局域網(wǎng)內(nèi)其他機(jī)器的默認(rèn)路由為該vip),master會(huì)發(fā)組播,當(dāng)backup收不到VRRP包時(shí)就認(rèn)為master宕掉了,這時(shí)就需要根據(jù)VRRP的優(yōu)先級(jí)來選舉一個(gè)backup當(dāng)master。以此保證路由器的高可用。
keepalived的配置可用自行查找資料
pxc集群負(fù)載均衡與雙機(jī)熱備理解

四 Redis集群
redis-cluste集群方案是redis官方在3.0版本后提供的分布式集群方案。在該方案中不存在中心節(jié)點(diǎn)。集群中每個(gè)節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)都不一樣,并且節(jié)點(diǎn)之間互相連接。
redis-cluster中有一個(gè)“槽”的概念,在一個(gè)集群中一共有16384個(gè)槽。每一個(gè)key會(huì)經(jīng)過計(jì)算算出數(shù)據(jù)存在哪一個(gè)槽中,計(jì)算方式為CRC16(key) mode 16384。不論是存或者取數(shù)據(jù)key都會(huì)先經(jīng)過此運(yùn)算計(jì)算槽。在物理機(jī)中,集群會(huì)把不同的槽映射到不同的物理機(jī)中。例如,集群中有三臺(tái)機(jī)器,A對(duì)應(yīng)槽為0-5500,B對(duì)應(yīng)槽為5501-11000,C對(duì)應(yīng)槽為11001-16384。當(dāng)新增一個(gè)節(jié)點(diǎn)時(shí)cluster會(huì)從各節(jié)點(diǎn)拿出一部分槽分配到新節(jié)點(diǎn)上。例如,A:1501-5500,B:7001-11000,C:12501-16384,D:0-1500,5501-7000,11001-12500。
每個(gè)節(jié)點(diǎn)都會(huì)通過通訊共享槽與集群中各個(gè)節(jié)點(diǎn)的關(guān)系。當(dāng)客戶端向redis cluster中的任一節(jié)點(diǎn)發(fā)送請(qǐng)求,當(dāng)前節(jié)點(diǎn)會(huì)計(jì)算key對(duì)應(yīng)的槽,如果該槽正好在該節(jié)點(diǎn)上則返回key對(duì)應(yīng)的數(shù)據(jù),如果該槽不在該節(jié)點(diǎn)上會(huì)返回moved重定向異常,客戶端從重定向異常中獲取正確目標(biāo)的節(jié)點(diǎn),然后從目標(biāo)節(jié)點(diǎn)中請(qǐng)求數(shù)據(jù)。該方式保證了獲取數(shù)據(jù)最多需要兩次請(qǐng)求。

需要注意的是,如果集群中某一節(jié)點(diǎn)掛掉該節(jié)點(diǎn)的數(shù)據(jù)就會(huì)無法訪問。為保證集群的高可用性,redis cluster加入了主從模式,一個(gè)主節(jié)點(diǎn)對(duì)應(yīng)多個(gè)從節(jié)點(diǎn)。主節(jié)點(diǎn)提供數(shù)據(jù),從節(jié)點(diǎn)從主節(jié)點(diǎn)復(fù)制數(shù)據(jù),保證主從節(jié)點(diǎn)數(shù)據(jù)一致。如果主節(jié)點(diǎn)掛掉,從節(jié)點(diǎn)會(huì)接替主節(jié)點(diǎn),隨后故障主節(jié)點(diǎn)修復(fù)該節(jié)點(diǎn)會(huì)自動(dòng)降級(jí)為從節(jié)點(diǎn)。
關(guān)于redis cluster集群我找到一篇比較詳細(xì)的文章,可以參考:https://www.cnblogs.com/williamjie/p/11132211.html
五 應(yīng)用程序與前端
關(guān)于應(yīng)用程序的部署,因?yàn)楦髡Z言的方案不同,Java有Tomcat,Python有uWSGI和Gunicorn。
在應(yīng)用程序部署好后也需要負(fù)載均衡器做負(fù)載,為防止負(fù)載均衡器意外掛掉也需要進(jìn)行雙機(jī)熱備。Nginx是一款開源,高性能,輕量級(jí)的負(fù)載均衡器和反向代理服務(wù)器。雙機(jī)熱備方案同樣使用keepalived爭(zhēng)搶虛擬ip的形式。以Python為例:

具體方案不再綴述。
由于前段方案也是Nginx負(fù)載和keepalived雙機(jī)熱備的方式,這里也不再綴述。
六 總體架構(gòu)
在這里前后端分離的分布式總體架構(gòu)已經(jīng)明確了。請(qǐng)求從前端服務(wù)器開始,Nginx對(duì)前端服務(wù)器做負(fù)載均衡,為防止Nginx掛掉使用keepalived爭(zhēng)搶虛擬ip方式進(jìn)行雙機(jī)熱備。對(duì)數(shù)據(jù)的請(qǐng)求由后端應(yīng)用程序開始,請(qǐng)求到達(dá)后端的Nginx,由Nginx進(jìn)行反向代理與負(fù)載均衡,為防止Nginx意外掛掉同樣使用keepalived進(jìn)行雙機(jī)熱備。如果訪問熱點(diǎn)數(shù)據(jù)則先在redis集群里尋找,如果redis集群中沒有則向pxc數(shù)據(jù)庫集群中進(jìn)行請(qǐng)求。pxc集群同樣需要使用HAProxy做負(fù)載均衡,為防止HAProxy掛掉使用keepalived做雙機(jī)熱備。

七 pxc集群搭建與負(fù)載均衡
注:這里不詳細(xì)描述具體步驟,詳細(xì)步驟可參考最上面附的兩篇博客
環(huán)境準(zhǔn)備:Centos7(1核2G,阿里云)、docker
關(guān)于docker的操作可以參考https://yeasy.gitbooks.io/docker_practice/content/
或者docker --help,這里主要涉及的有操作有網(wǎng)段network,卷 volume,鏡像image,容器container,可分別用docker network --help查看相應(yīng)的操作。
前提準(zhǔn)備:
前往阿里云控制臺(tái)的安全組實(shí)例配置中把將要使用的端口開放,創(chuàng)建網(wǎng)段,創(chuàng)建卷
可配置阿里云的鏡像加速器(強(qiáng)烈建議)
集群搭建
創(chuàng)建網(wǎng)段:docker network create --subnet=172.19.0.0/24 pxc-test-network
創(chuàng)建卷:docker volume create pxc-test-volume1
拉取鏡像:docker pull percona/percona-xtradb-cluster:5.7
可將鏡像重命名:docker tag percona/percona-xtradb-cluster:5.7 pxc
創(chuàng)建第一個(gè)節(jié)點(diǎn),pxc集群創(chuàng)建第一個(gè)節(jié)點(diǎn)數(shù)據(jù)庫實(shí)例化會(huì)比較慢,如果第一個(gè)節(jié)點(diǎn)沒有完成實(shí)例化或者實(shí)例化失敗后面的節(jié)點(diǎn)加入的時(shí)候會(huì)失敗。
docker run -d -p 7306:3306 -e MYSQL_ROOT_PASSWORD=root -e CLUSTER_NAME=pxc_cluster -v pxc-test-volume1:/var/lib/mysql --name=pxc_node1 --net=pxc-test-network --ip=172.19.0.2 pxc
可以是Navicat或者其它軟件連接MySQL,如果連接成功則證明第一個(gè)節(jié)點(diǎn)創(chuàng)建成功。
創(chuàng)建第二個(gè)節(jié)點(diǎn)并加入集群:
docker run -d -p 7307:3306 -e MYSQL_ROOT_PASSWORD=root -e CLUSTER_NAME=pxc_cluster -e CLUSTER_JOIN=pxc_node1 -v pxc-test-volume2:/var/lib/mysql --name=pxc_node2 --net=pxc-test-network --ip=172.19.0.3 pxc
創(chuàng)建第三個(gè)節(jié)點(diǎn)并加入集群:
docker run -d -p 7308:3306 -e MYSQL_ROOT_PASSWORD=root -e CLUSTER_NAME=pxc_cluster -e CLUSTER_JOIN=pxc_node1 -v pxc-test-volume3:/var/lib/mysql --name=pxc_node3 --net=pxc-test-network --ip=172.19.0.4pxc
參數(shù)解釋:
- MYSQL_ROOT_PASSWORD:MySQL用戶密碼,用戶是root
- CLUSTER_NAME:集群名字
- CLUSTER_JOIN:與某個(gè)節(jié)點(diǎn)同步
HAProxy負(fù)載均衡
拉取鏡像docker pull haproxy
編寫配置文件并將配置文件映射到docker容器內(nèi)這里為/data/haproxy/haproxy.cfg(后附上配置文件詳情)
啟動(dòng)容器docker run -it -d -p 8001:8888 -p 8002:3306 -v /data/haproxy:/usr/local/etc/haproxy --name haproxy_node1 --privileged --net=pxc-test-network --ip 172.19.0.07 docker.io/haproxy
進(jìn)入容器:docker exec -it haproxy bash
啟用配置文件:haproxy -f /usr/local/etc/haproxy/haproxy.cfg
然后可放問監(jiān)控界面,http://你的ip:port/dbs,輸入用戶名和密碼(在配置文件配置)
要記得在MySQL中創(chuàng)建haproxy的用戶,在一個(gè)節(jié)點(diǎn)創(chuàng)建就行了pxc會(huì)自動(dòng)同步
CREATE USER 'haproxy@'%' IDENTIFIED BY ''

遇到的坑
- 拉取pxc的鏡像總是卡住,解決:配置阿里云鏡像加速
- 一開始集群節(jié)點(diǎn)為五個(gè),后來啟動(dòng)HAProxy容器的時(shí)候不就該容易無法啟動(dòng)pxc主節(jié)點(diǎn)也老是掛掉,整到晚上一點(diǎn)。第二天
free -h查看內(nèi)存就剩幾十M,推測(cè)內(nèi)存不夠于是在一臺(tái)新的阿里云服務(wù)器上配置HAProxy,成功! - pxc集群為五個(gè)節(jié)點(diǎn)的時(shí)候,往節(jié)點(diǎn)寫入數(shù)據(jù)成功,然后查這一條數(shù)據(jù)失敗,docker查看主節(jié)點(diǎn)容易掛掉,頓時(shí)懵逼。首先想是不是配置有問題,后來推測(cè)是不是因?yàn)閮?nèi)存不夠,集群節(jié)點(diǎn)改為三個(gè),成功!
附:HAProxy配置文件haproxy.cfg
global
#工作目錄
chroot /usr/local/etc/haproxy
#日志文件,使用rsyslog服務(wù)中l(wèi)ocal5日志設(shè)備(/var/log/local5),等級(jí)info
log 127.0.0.1 local5 info
#守護(hù)進(jìn)程運(yùn)行
daemon
defaults
log global
mode http
#日志格式
option httplog
#日志中不記錄負(fù)載均衡的心跳檢測(cè)記錄
option dontlognull
#連接超時(shí)(毫秒)
timeout connect 5000
#客戶端超時(shí)(毫秒)
timeout client 50000
#服務(wù)器超時(shí)(毫秒)
timeout server 50000
#監(jiān)控界面
listen admin_stats
#監(jiān)控界面的訪問的IP和端口
bind 0.0.0.0:8888
#訪問協(xié)議
mode http
#URI相對(duì)地址
stats uri /dbs
#統(tǒng)計(jì)報(bào)告格式
stats realm Global\ statistics
#登陸帳戶信息,用戶名:密碼
stats auth root:root
#數(shù)據(jù)庫負(fù)載均衡
listen proxy-mysql
#訪問的IP和端口(前面ip=0代表任何ip都可訪問)
bind 0.0.0.0:3306
#網(wǎng)絡(luò)協(xié)議
mode tcp
#負(fù)載均衡算法(輪詢算法)
#輪詢算法:roundrobin
#權(quán)重算法:static-rr
#最少連接算法:leastconn
#請(qǐng)求源IP算法:source
balance roundrobin
#日志格式
option tcplog
#在MySQL中創(chuàng)建一個(gè)沒有權(quán)限的haproxy用戶,密碼為空。Haproxy使用這個(gè)賬戶對(duì)MySQL數(shù)據(jù)庫心跳檢測(cè)
option mysql-check user haproxy
server NODE1 47.100.48.93:7306 check weight 1 maxconn 2000
server NODE2 47.100.48.93:7307 check weight 1 maxconn 2000
server NODE3 47.100.48.93:7308 check weight 1 maxconn 2000
server NODE4 47.100.48.93:7309 check weight 1 maxconn 2000
server NODE5 47.100.48.93:7310 check weight 1 maxconn 2000
#使用keepalive檢測(cè)死鏈
option tcpka