安裝環境
centos7, docker
集群方案介紹
大型網站數據庫需要應對高負載、實現高可用。而單節點數據庫在并發量大的情況下無法滿足性能要求,且一臺宕機,整個服務受影響。
- Mysql集群:PXC
- 負載均衡:Haproxy
- 高可用:Keepalived
搭建pxc集群
安裝pxc鏡像
docker官方倉庫(https://hub.docker.com)搜索 percona-xtradb-cluster,拉取鏡像命令為: docker pull percona/percona-xtradb-cluster
終端執行:
// 安裝pxc鏡像
? docker pull percona/percona-xtradb-cluster
// 查看鏡像
? docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/percona/percona-xtradb-cluster latest f3abd21f393a 3 days ago 72.1 MB
// 鏡像名稱太長,為方便使用,修改一下
? docker tag docker.io/percona/percona-xtradb-cluster pxc
// 刪除原鏡像
docker rmi docker.io/percona/percona-xtradb-cluster
創建Docker內部網絡
出于安全考慮,不要把pxc容器的IP直接暴露出去,而是創建docker內部網絡。
// 網段subnet自定義,網段名自定義為network20
? docker network create --subnet=172.20.0.0/16 network20
2e9196b0637074cad609be8e4e890aa3e889209af8c2b55ce8097981000bf53f
// 查看網段詳細信息
? docker network inspect network20
創建Docker卷
docker的使用原則之一:
不要在容器內保存業務數據,而應該保存在宿主機中
。
實現方式:通過目錄映射,把宿主機的目錄映射到容器內,運行容器時,把數據保存在映射目錄中,也就是保存在宿主機中。當容器發生故障時,只需把故障容器刪除掉,重新啟動一個容器,把宿主機的目錄映射給新容器。
pxc運行在容器中,無法直接使用映射目錄,會發生閃退。需要借助Docker卷完成映射。
// 創建一個docker卷,自定義名稱為 volume-mysql-1
? docker volume create --name volume-mysql-1
// 可以查看數據卷在宿主機上當真實目錄
? docker volume inspect volume-mysql-1
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/volume-mysql-1/_data", // 數據卷在宿主機真實的路徑
"Name": "volume-mysql-1", // 數據卷名稱
"Options": {},
"Scope": "local"
}
]
創建PXC容器
- 命令分解
// -d 創建出的容器后臺運行
docker run -d
// -p 端口映射,[宿主機端口]:[容器端口]
-p 3311:3306
// -e 啟動參數,MYSQL_ROOT_PASSWORD數據庫root密碼
-e MYSQL_ROOT_PASSWORD=123456
// CLUSTER_NAME集群名稱
-e CLUSTER_NAME=pxc-test
// XTRABACKUP_PASSWORD數據庫間節點同步密碼
-e XTRABACKUP_PASSWORD=123456
// -v 目錄映射,[宿主機目錄(數據卷)]:[容器目錄]
-v volume-mysql-1:/var/lib/mysql
// 最高權限
--privileged
// --name 容器名稱
--name mysql-node1
// --net 給容器指定網段,指定IP
--net network20 --ip 172.20.0.2
// 鏡像名
pxc
執行指令創建第一個pxc節點
// 創建第一個pxc節點 mysql-node1
? docker run -d -p 3311:3306 -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=pxc-test -e XTRABACKUP_PASSWORD=123456 -v volume-mysql-1:/var/lib/mysql --privileged --name mysql-node1 --net network20 --ip 172.20.0.2 pxc
注意:容器創建很快就會完成,但是容器內mysql數據庫的初始化大概需要2分鐘左右,一定要等到mysql初始化完成后,再創建第2個容器,否則第2個容器會發生閃退!
判斷mysql-node1是否完成初始化,可以在宿主機終端執行指令:docker exec -it mysql-node1 mysql -uroot -p
,看是否連接成功。
創建第2-5個pxc節點,與第1個節點略有區別:
- 修改映射宿主機端口號(-p)
- 修改容器名稱 (--name)
- 修改映射的數據卷 (-v)
- 修改分配的IP地址 (--ip)
- 增加一個參數用于加入集群,和第一個pxc節點進行同步:
-e CLUSTER_JOIN=mysql-node1
- 除第1個容器以外,其余mysql初始化時間非常短,無需等待
// 創建pxc容器 mysql-node2
? docker run -d -p 3312:3306 -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=pxc-test -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=mysql-node1 -v volume-mysql-2:/var/lib/mysql --privileged --name mysql-node2 --net network20 --ip 172.20.0.3 pxc
// 創建pxc容器 mysql-node3
? docker run -d -p 3313:3306 -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=pxc-test -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=mysql-node1 -v volume-mysql-3:/var/lib/mysql --privileged --name mysql-node3 --net network20 --ip 172.20.0.4 pxc
// 創建pxc容器 mysql-node4
? docker run -d -p 3314:3306 -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=pxc-test -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=mysql-node1 -v volume-mysql-4:/var/lib/mysql --privileged --name mysql-node4 --net network20 --ip 172.20.0.5 pxc
// 創建pxc容器 mysql-node5
? docker run -d -p 3315:3306 -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=pxc-test -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=mysql-node1 -v volume-mysql-5:/var/lib/mysql --privileged --name mysql-node5 --net network20 --ip 172.20.0.6 pxc
檢測pxc集群的數據同步
可在宿主機上直接登陸某個容器的mysql客戶端;也可以使用mysql可視化工具,如Navicat等遠程登陸,遠程登陸的需要防火墻開放端口。
以下演示宿主機終端驗證方法:
// 登陸mysql-node1節點的mysql終端,創建db=demo,table=user
? docker exec -it mysql-node1 mysql -uroot -p
mysql> create database demo;
mysql> use demo
Database changed
Query OK, 1 row affected (0.02 sec)
mysql> create table student(id int unsigned not null auto_increment, name varchar(50) not null default '', primary key (id)) engine=innodb;
Query OK, 0 rows affected (0.04 sec)
mysql> exit
Bye
// 退出mysql-node1,登陸mysql-node2
? docker exec -it mysql-node2 mysql -uroot -p
mysql> use demo
Database changed
mysql> show tables;
+----------------+
| Tables_in_demo |
+----------------+
| student |
+----------------+
1 row in set (0.01 sec)
// 其它節點同mysql-node2
任意節點寫入新數據,其它節點都會同步。至此,pxc集群搭建完成。
haproxy配置負載均衡
負載均衡簡單介紹
負載均衡可以使應用數據均勻的落在pxc集群的每一個節點上。如果不使用負載均衡,單節點處理所有請求,會導致該節點負載高、性能差;其它節點卻空閑浪費。
haproxy做負載均衡器,它不是數據庫,只是一個轉發件。
Docker安裝Haproxy鏡像
// 拉取鏡像
? docker pull haproxy
// 查看鏡像
? docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/haproxy latest f3abd21f393a 3 days ago 72.1 MB
pxc latest 70b3670450ef 4 weeks ago 408 MB
創建haproxy配置文件
// 宿主機上創建haproxy配置文件,路徑自己指定,之后創建容器會用到
? touch /home/softconf/haproxy/haproxy.cfg
// haproxy.conf寫入下列內容,具體配置需要修改
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:admin123456
#數據庫負載均衡
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.20.0.2:3306 check weight 1 maxconn 2000
server MySQL_2 172.20.0.3:3306 check weight 1 maxconn 2000
server MySQL_3 172.20.0.4:3306 check weight 1 maxconn 2000
server MySQL_4 172.20.0.5:3306 check weight 1 maxconn 2000
server MySQL_5 172.20.0.6:3306 check weight 1 maxconn 2000
#使用keepalive檢測死鏈
option tcpka
haproxy.cnf 與pxc相關配置 重點查看listen proxy-mysql
創建haproxy容器
// -p 端口號 8888 :haproxy后臺監控界面端口,與haproxy.cnf中的配置一致
// -p 端口號 3306 :haproxy對外提供負載均衡服務端口,可以直接通過該端口連接到pxc集群
// -v 目錄映射,把宿主機的配置文件所在目錄映射到容器的工作目錄中
// --name 容器名,建議帶數字編號1,高可用時haproxy需要配置成雙節點
// --net 網段需要和pxc集群在同一網段中
// --ip 可以指定IP,當不指定時docker虛擬機會默認分配一個
? docker run -it -d -p 4001:8888 -p 4002:3306 -v /home/softconf/haproxy:/usr/local/etc/haproxy --name mysql-haproxy1 --privileged --net=network20 haproxy
// 進入容器中,榮國配置文件啟動 haproxy
? docker exec -it mysql-haproxy1 bash
root@0672cb121dde:/# haproxy -f /usr/local/etc/haproxy/haproxy.cfg
創建mysql的haproxy用戶
進入pxc某個節點,在mysql中創建haproxy用戶。haproxy中間件需要使用該賬號登陸數據庫,發送心跳檢測。
// 登陸一個pxc節點的mysql終端
? docker exec -it mysql-node2 mysql -uroot -p
mysql> use mysql
Database changed
mysql> create user 'haproxy'@'%' identified by '';
mysql> flush privileges;
驗證haproxy
通過瀏覽器訪問haproxy監控頁面,遠程訪問需要開放端口(CentOS7使用firewalld打開關閉防火墻與端口)
- 訪問地址:
http://宿主機IP:4001/dbs
- 訪問路徑配置文件中:
stats uri /dbs
- 用戶名、密碼在配置文件中:
stats auth admin:admin123456
haproxy監控頁面
在監控見面中可以看到5個節點都是啟動狀態,當暫停/停止一個pxc節點時,監控界面的down節點狀態(顏色)發生變化。由于haproxy會將請求發送至其它可用節點,此時pxc集群仍然可用。
// 終端執行命令,暫停一個節點
? haproxy docker pause mysql-node2
mysql客戶端連接haproxy
// 宿主機上連接mysql客戶端
// -P 端口號,haproxy的3306端口映射到宿主機的4002端口
// -p 密碼,pxc集群中的mysql密碼
? haproxy mysql -h127.0.0.1 -P4002 -uroot -p
// 或通過navicat工具連接,-h為宿主機的公網IP
// 進入mysql后,操作的所有數據都同步到pxc集群的全部節點
...
TODO : 集群高可用
單節點的Haproxy不具備高可用,必須要有冗余設計。
keepalived與haproxy安裝在同一個容器中,搶占虛擬IP。
阿里云服務器不支持虛擬IP,keepalived實現高可用待實現
Tips
Keepalived+mysql 雙主一般來說,有幾個需要注意的點,原文地址:MySQL 高可用性keepalived+mysql雙主
1.采用 keepalived 作為高可用方案時,兩個節點最好都設置成 BACKUP模式,避免因為意外情況下(比如 腦裂)相互搶占導致往兩個節點寫入相同數據而引發沖突;
2.把兩個節點的 auto_increment_increment(自增步長)和 auto_increment_offset(自增起始值)設成不同值。其目的是為了避免 master 節點意外宕機時,可能會有部分 binlog 未能及時復制到slave上被應用,從而會導致slave新寫入數據的自增值和原先master上沖突了,因此一開始就使其錯開;當然了,如果有合適的容錯機制能解決主從自增 ID 沖突的話,也可以不這么做;
3.slave 節點服務器配置不要太差,否則更容易導致復制延遲。作為熱備節點的 slave 服務器,硬件配置不能低于 master 節點;
4.如果對延遲問題很敏感的話,可考慮使用 MariaDB 分支版本,或者直接上線 MySQL 5.7 最新版本,利用多線程復制的方式可以很大程度降低復制延遲;