單節點數據庫弊端
- 大型互聯網程序用戶群體龐大,所以架構必須要特殊設計
- 單節點的數據庫無法滿足性能上的要求
- 單節點的數據庫沒有冗余設計,無法滿足高可用
推薦Mysql集群部署方案
PXC (Percona XtraDB Cluster)
建議PXC使用PerconaServer (MySQL改進版,性能提升很大)
PXC的數據強一致性
- 同步復制,事務在所有集群節點要么同時提交,要么不提交
- Replication采用異步復制,無法保證數據的一致性
PXC集群部署
在Docker中安裝PXC集群,使用Docker倉庫中的PXC官方鏡像
docker官方倉庫中拉下PXC鏡像
docker pull percona/percona-xtradb-cluster:5.7.21
重命名鏡像:(名稱太長,可以重命名一下)
docker tag percona/percona-xtradb-cluster:5.7.21 pxc
出於安全考慮,給PXC集群創建Docker Swarm虛擬網絡
( docker network create -d overlay --attachable swarm_mysql(自定義名稱) )
#初始化swarm虛擬網絡 docker swarm init #查看Swarm節點下的主機,只能在主機下查看 docker node ls #刪除節點的某一台主機 docker node rm -f vhmhgzyfyl710x0ojkbg9yywm(節點ID) #解散Swarm集群 docker swarm leave -f docker swarm leave #查看docker網絡 docker network ls #創建swarm虛擬網絡 docker network create -d overlay --attachable swarm_mysql(自定義名稱) #刪除swarm虛擬網絡 docker network rm swarm_mysql
創建Docker數據卷
使用Docker時,業務數據應保存在宿主機中,采用目錄映射,這樣可以使數據與容器獨立。但是容器中的PXC無法直接使用映射目錄,解決辦法是采用Docker卷來映射!
# 創建名稱為v1的數據卷,--name可以省略
docker volume create --name v1
查看數據卷
#查看數據卷元信息
docker inspect v1
刪除數據卷
#刪除數據卷命令 docker volume rm v1
創建部署PXC集群所需的數據卷
# 創建5個數據卷 docker volume create --name v1 docker volume create --name v2 docker volume create --name v3 docker volume create --name v4 docker volume create --name v5
創建5個PXC容器
# 創建5個PXC容器構成集群 # 第一個節點 docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -v v1:/var/lib/mysql --name=node1 --network=swarm_mysql pxc # 在第一個節點啟動后要等待一段時間,等候mysql啟動完成。 # 第二個節點 docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v2:/var/lib/mysql --name=node2 --net=swarm_mysql pxc # 第三個節點 docker run -d -p 3308:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v3:/var/lib/mysql --name=node3 --net=swarm_mysql pxc # 第四個節點 docker run -d -p 3309:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v4:/var/lib/mysql --name=node4 --net=swarm_mysql pxc # 第五個節點 docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v5:/var/lib/mysql --name=node5 --net=swarm_mysql pxc
數據庫負載均衡的必要性
數據庫單節點處理所有請求,負載高,性能差
將請求均勻地發送給集群中的每一個節點。
- 所有請求發送給單一節點,其負載過高,性能很低,而其他節點卻很空閑。
- 使用Haproxy做負載均衡,可以將請求均勻地發送給每個節點,單節點負載低,性能好
安裝負載均衡中間件Haproxy
從Docker倉庫拉取haproxy鏡像
#下載haproxy鏡像
docker pull haproxy
創建Haproxy配置文件。供Haproxy容器使用( haproxy.cfg )
global #工作目錄 chroot /usr/local/etc/haproxy #日志文件,使用rsyslog服務中local5日志設備(/var/log/local5),等級info log 127.0.0.1 local5 info #守護進程運行 daemon defaults log global mode http #日志格式 option httplog #日志中不記錄負載均衡的心跳檢測記錄 option dontlognull #連接超時(毫秒) timeout connect 5000 #客戶端超時(毫秒) timeout client 50000 #服務器超時(毫秒) timeout server 50000 #監控界面 listen admin_stats #監控界面的訪問的IP和端口 bind 0.0.0.0:8888 #訪問協議 mode http #URI相對地址 stats uri /dbs #統計報告格式 stats realm Global\ statistics #登陸帳戶信息 stats auth admin:abc123456 #數據庫負載均衡 listen proxy-mysql #訪問的IP和端口 bind 0.0.0.0:3306 #網絡協議 mode tcp #負載均衡算法(輪詢算法) #輪詢算法:roundrobin #權重算法:static-rr #最少連接算法:leastconn #請求源IP算法:source balance roundrobin #日志格式 option tcplog #在MySQL中創建一個沒有權限的haproxy用戶,密碼為空。Haproxy使用這個賬戶對MySQL數據庫心跳檢測 option mysql-check user haproxy server MySQL_1 172.18.0.2:3306 check weight 1 maxconn 2000 server MySQL_2 172.18.0.3:3306 check weight 1 maxconn 2000 server MySQL_3 172.18.0.4:3306 check weight 1 maxconn 2000 server MySQL_4 172.18.0.5:3306 check weight 1 maxconn 2000 server MySQL_5 172.18.0.6:3306 check weight 1 maxconn 2000 #使用keepalive檢測死鏈 option tcpka
文件映射到容器內部
#映射文件 docker cp 宿主機的haproxy.cfg的路徑 haproxy:/usr/local/etc/haproxy/
在數據庫集群中創建空密碼、無權限用戶haproxy,來供Haproxy對MySQL數據庫進行心跳檢測
#示例 #進入node1容器 docker exec -it node1 bash #登錄mysql mysql -u root -p #指定數據庫 use mysql; #創建用戶 create user 'haproxy'@'%' identified by '';
創建Haproxy容器
# 這里要加 --privileged docker run -it -d -p 4001:8888 -p 4002:3306 -v /home/haproxy:/usr/local/etc/haproxy --name haproxy --net=swarm_mysql --privileged haproxy
(容器啟動后,haproxy自動啟動,如果沒啟動使用下面命令啟動)進入容器並啟動haproxy
#進入容器 docker exec -it h1 bash #啟動haproxy haproxy -f /usr/local/etc/haproxy/haproxy.cfg
瀏覽器中打開Haproxy監控界面
根據配置文件和啟動容器設置的端口,我的訪問路徑為:http://192.168.63.144:4001/dbs ,用戶名admin,密碼abc123456
嘗試宕掉一台數據庫
Haproxy不存儲數據,只轉發數據。可以在數據庫中建立Haproxy的連接,端口4002,用戶名和密碼為數據庫集群的用戶名和密碼
雙機熱備場景
單節點Haproxy不具備高可用,必須要有冗余設計
雙機就是兩個請求處理程序,比如兩個haproxy,當一個掛掉的時候,另外 一個可以頂上。熱備我理解就是keepalive。在haproxy 容器中安裝keepalive。
虛擬IP
定義一個虛擬ip,然后比如兩個haproxy分別安裝keepalive鏡像,因為haproxy是ubuntu系統的,所以安裝用apt-get,keepalive是作用是搶占虛擬ip,搶到的就是主服務器,沒有搶到的就是備用服務器,然后兩個keepalive進行心跳檢測(就是創建一個用戶到對方那里試探,看是否還活着,mysql的集群之間也是心跳檢測),如果 掛掉搶占ip。
Haproxy的雙機熱備方案最關鍵的技術就是虛擬IP。宿主機安裝keepalive,容器安裝keepalive,通過虛擬IP轉發進行通信,實現雙機熱備。
Keepalive實現雙機熱備方案
- 定義虛擬IP
- 在Docker中啟動兩個Haproxy容器,每個容器中還需要安裝Keepalived程序(以下簡稱KA)
- 兩個KA會爭搶虛擬IP,一個搶到后,另一個沒搶到就會等待,搶到的作為主服務器,沒搶到的作為備用服務器
- 兩個KA之間會進行心跳檢測,如果備用服務器沒有受到主服務器的心跳響應,說明主服務器發生故障,那么備用服務器就可以爭搶虛擬IP,繼續工作
- 我們向虛擬IP發送數據庫請求,一個Haproxy掛掉,可以有另一個接替工作
docker內的虛擬IP不能被外網,所以需要借助宿主機Keepalived映射成外網可以訪問地虛擬IP
Haproxy容器安裝Keepalived
安裝keeplived
#進入容器 docker exec -it haproxy bash #更新apt-get工具 apt-get update #下載keepalived apt-get install keepalived
編寫Keepalived配置文件
Keepalived的配置文件復制到 /etc/keepalived/keepalived.conf 路徑
vrrp_instance VI_1 { state MASTER # Keepalived的身份(MASTER主服務要搶占IP,BACKUP備服務器不會搶占IP)。 interface eth0 # docker網卡設備,虛擬IP所在 virtual_router_id 51 # 虛擬路由標識,MASTER和BACKUP的虛擬路由標識必須一致。從0~255 priority 100 # MASTER權重要高於BACKUP數字越大優先級越高 advert_int 1 # MASTER和BACKUP節點同步檢查的時間間隔,單位為秒,主備之間必須一致 authentication { # 主從服務器驗證方式。主備必須使用相同的密碼才能正常通信 auth_type PASS auth_pass 123456 } virtual_ipaddress { # 虛擬IP。可以設置多個虛擬IP地址,每行一個 172.18.0.201 } }
啟動Keepalived
#啟動keepalived
service keepalived start
#查看網卡虛擬IP是否生效
ip a
可以按照以上步驟,再另外創建一個Haproxy容器,注意映射的宿主機端口不能重復,Haproxy配置一樣。
宿主機安裝Keepalived
首先查看當前局域網IP分配情況
#下載nmap工具 yum install nmap -y #查看當前網段所有占用的IP nmap -sP 192.168.1.0/24
在宿主機中安裝Keepalived
yum install keepalived
編寫宿主機Keepalived配置
復制到 /etc/keepalived/keepalived.conf 路徑
vrrp_instance VI_1 { state MASTER #這里是宿主機的網卡,可以通過ip a查看當前自己電腦上用的網卡名是哪個 interface ens33 virtual_router_id 100 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { #這里是指定的一個宿主機上的虛擬ip,一定要和宿主機網卡在同一個網段, #我的宿主機網卡ip是192.168.63.144,所以指定虛擬ip是160 192.168.63.160 } } #接受監聽數據來源的端口,網頁入口使用 virtual_server 192.168.63.160 8888 { delay_loop 3 lb_algo rr lb_kind NAT persistence_timeout 50 protocol TCP #把接受到的數據轉發給docker服務的網段及端口,由於是發給docker服務,所以和docker服務數據要一致 real_server 172.18.0.201 8888 { weight 1 } } #接受數據庫數據端口,宿主機數據庫端口是3306,所以這里也要和宿主機數據接受端口一致 virtual_server 192.168.63.160 3306 { delay_loop 3 lb_algo rr lb_kind NAT persistence_timeout 50 protocol TCP #同理轉發數據庫給服務的端口和ip要求和docker服務中的數據一致 real_server 172.18.0.201 3306 { weight 1 } }
啟動Keepalived服務
#啟動keepalived
service keepalived start
#查看keepalived狀態
service keepalived status
#關閉keepallived
service keepalived stop
其他電腦便可以通過虛擬IP 192.168.63.160 的8888和3306端口來訪問宿主機Docker中的 172.18.0.201 的相應端口。