MySQL集群搭建方案(PXC)

伺服器快過期了,清一點庫存,把運維這塊的知識複習下

為什麼要搭MySQL集群

技術層面上,傳統的單節點資料庫,萬一宕機了,就涼涼了。容災性能差、抗並發能力有限,數據量大的時候查詢有瓶頸。學習層面上,作為一個技術人了解一些技術相關的知識那也是無可厚非,愛折騰嘛。所以、本著「不把雞蛋放在一個籃子里」的思想,我們來一起探討學習下如何搭建MySQL集群。

MySQL集群的解決方案

關於搭建MySQL集群解決方案的操作方面,這部分知識其實是很死板的,沒有特別多的含金量,真正有含金量的是挖掘其背後實現的原理和思路,並能夠曉之以情動之以理地講出來。這裡主要介紹兩種解決方案,我們抓牢它們的側重點總結下吧。

PXC

  • 強一致性
  • 速度慢
  • 只支援InnoDB存儲引擎同步
  • 所有節點可讀寫
  • 同步機製為同步
  • 存儲資訊價值量高

Replication

  • 弱一致性

  • 速度快

  • 從節點不可寫入

  • 同步機製為非同步

  • 存儲資訊價值量不高

這裡我們主要講下PXC,當你在一個節點進行相關操作,比如說插入一條數據、它會同步到其他節點,若所有節點同步成功則插入成功、若所有節點同步失敗,則回滾並告知插入失敗,這個我們後面實踐一下就知道了。

創建MySQL集群的步驟(PXC)

(一)、拉取鏡像並重命名

# 拉取鏡像
docker pull percona/percona-xtradb-cluster

# 重名名(這步也可以不做,我就是想後面少打點字)
docker tag percona/percona-xtradb-cluster:latest pxc:latest

(二)、組網

2.1、創建網路:

命令:docker network create mysql_net

演示:

⚡ root@ataola  ~  docker network create mysql_net
79885a1c3b8a783e096a1610df08e353641bda74d0b996b4200f2ea5db3c5dbd
 ⚡ root@ataola  ~  

2.2、查看網路:

命令:docker network inspect mysql_net

演示:

⚡ root@ataola  ~  docker network inspect mysql_net
[
    {
        "Name": "mysql_net",
        "Id": "79885a1c3b8a783e096a1610df08e353641bda74d0b996b4200f2ea5db3c5dbd",
        "Created": "2020-05-30T21:26:53.852825919+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.19.0.0/16",
                    "Gateway": "172.19.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]
 ⚡ root@ataola  ~  

(三)、創建數據卷

3.1、創建數據卷

命令:docker volume create mysql_v

演示:

 ⚡ root@ataola  ~  docker volume create mysql_v1   
mysql_v1
 ⚡ root@ataola  ~  docker volume create mysql_v2
mysql_v2
 ⚡ root@ataola  ~  docker volume create mysql_v3
mysql_v3
 ⚡ root@ataola  ~  docker volume create mysql_v4
mysql_v4
 ⚡ root@ataola  ~  docker volume create mysql_v5
mysql_v5
 ⚡ root@ataola  ~  

3.2:查看數據卷

命令:docker volume inspect mysql_v

演示:

✘ ⚡ root@ataola  /home/caocao  docker volume inspect mysql_v1
[
    {
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/mysql_v1/_data",
        "Name": "mysql_v1",
        "Options": {},
        "Scope": "local"
    }
]
 ⚡ root@ataola  /home/caocao  

(四)、創建MySQL節點

4.1、主節點:

命令:docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=studypxc -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=studymysql -v mysql_v1:/var/lib/mysql --privileged --name=mysql_node1 --net=mysql_net pxc

演示:

⚡ root@ataola  ~  docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=studypxc -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=studymysql -v mysql_v1:/var/lib/mysql --privileged --name=mysql_node1 --net=mysql_net pxc
09e7715f71b4411974d862a2aa74ed0b1018fc4efb4196707576f935e1425f6b
 ⚡ root@ataola  ~  docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                   NAMES
09e7715f71b4        pxc                 "/entrypoint.sh my..."   8 seconds ago       Up 6 seconds        0.0.0.0:3306->3306/tcp, 4567-4568/tcp   mysql_node1
 ⚡ root@ataola  ~ 

4.2、從節點:

命令:docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=studypxc -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=studymysql -e CLUSTER_JOIN=mysql_node1 -v mysql_v2:/var/lib/mysql --privileged --name=mysql_node2 --net=mysql_net pxc

更改相關參數重複三次樓上操作,我們構建一個主節點外加四個從節點的mysql集群,這個時候我們執行docker ps -a看下,可以看到它們都跑起來了。

⚡ root@ataola  ~  docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                   NAMES
8d809616ea08        pxc                 "/entrypoint.sh my..."   9 seconds ago       Up 8 seconds        4567-4568/tcp, 0.0.0.0:3310->3306/tcp   mysql_node5
6dc023253205        pxc                 "/entrypoint.sh my..."   18 seconds ago      Up 17 seconds       4567-4568/tcp, 0.0.0.0:3309->3306/tcp   mysql_node4
18c232855938        pxc                 "/entrypoint.sh my..."   53 seconds ago      Up 52 seconds       4567-4568/tcp, 0.0.0.0:3308->3306/tcp   mysql_node3
6de60216270a        pxc                 "/entrypoint.sh my..."   2 minutes ago       Up 2 minutes        4567-4568/tcp, 0.0.0.0:3307->3306/tcp   mysql_node2
09e7715f71b4        pxc                 "/entrypoint.sh my..."   10 minutes ago      Up 10 minutes       0.0.0.0:3306->3306/tcp, 4567-4568/tcp   mysql_node1
 ⚡ root@ataola  ~  

然後我們可以通過docker network inspect mysql_net查看我們剛才創建集群的網路資訊

 ⚡ root@ataola  /home/caocao  docker network inspect mysql_net
[
    {
        "Name": "mysql_net",
        "Id": "79885a1c3b8a783e096a1610df08e353641bda74d0b996b4200f2ea5db3c5dbd",
        "Created": "2020-05-30T21:26:53.852825919+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.19.0.0/16",
                    "Gateway": "172.19.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "09e7715f71b4411974d862a2aa74ed0b1018fc4efb4196707576f935e1425f6b": {
                "Name": "mysql_node1",
                "EndpointID": "621bc0ec6e4adb78e72f0f78ca04d154029abe1f0bb91fc5ccd42156bfa32d52",
                "MacAddress": "02:42:ac:13:00:02",
                "IPv4Address": "172.19.0.2/16",
                "IPv6Address": ""
            },
            "0e4ef69c19b981163067ec8af0c38b6fa84c380855c22309a884f0a0ed691912": {
                "Name": "haproxy1",
                "EndpointID": "02e8c179fdb7cbc4b3e7d72f8412129da487c65a3897e70e0da5693aa0d8d500",
                "MacAddress": "02:42:ac:13:00:07",
                "IPv4Address": "172.19.0.7/16",
                "IPv6Address": ""
            },
            "18c232855938d7263b90a4ab88874676110c6197a601aa72d8bec8f52e73dd02": {
                "Name": "mysql_node3",
                "EndpointID": "010538caec3ab7aafe1c708ebebdffa43e268d68147cf4a60f86a77247b3ef86",
                "MacAddress": "02:42:ac:13:00:04",
                "IPv4Address": "172.19.0.4/16",
                "IPv6Address": ""
            },
            "6dc0232532057a65db0607c92517307ee480bec32cb6311d6615555482670c7a": {
                "Name": "mysql_node4",
                "EndpointID": "cc59fe8fc8d7d02f367ec75b1897c51bf3731dbc5dc8d70510dde34aee6d4afa",
                "MacAddress": "02:42:ac:13:00:05",
                "IPv4Address": "172.19.0.5/16",
                "IPv6Address": ""
            },
            "6de60216270a3b6f5bfbe5d94d40fa2449e443eb77b67d4bf005061dd4ff412e": {
                "Name": "mysql_node2",
                "EndpointID": "b674d25e3e6c999324de9704419b1c97f008ca6e5d27e825bc0fc61d600848ff",
                "MacAddress": "02:42:ac:13:00:03",
                "IPv4Address": "172.19.0.3/16",
                "IPv6Address": ""
            },
            "8d809616ea08d46a3febb95259d9d0672d6112dd8cbe6c29f03f49cbc44ef444": {
                "Name": "mysql_node5",
                "EndpointID": "01f0988019206e959a7099736d9995cec1676aaec360db9bd78fa61b68a87f71",
                "MacAddress": "02:42:ac:13:00:06",
                "IPv4Address": "172.19.0.6/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
 ⚡ root@ataola  /home/caocao  

至此,基於PXC解決方案MySQL集群搭建已經完成了,當然這裡涉及到的一些命令和參數具體的還是要讀者去看樓下參考文獻的官方文檔的。

負載均衡(haproxy)

在樓上的例子中,我們創建了一個MySQL集群,我們可以把它理解成一家超市。然後每個節點就是收銀台。這個時候就會有個問題了,假設那批去超市購物的人不太正常了,買完東西都擠到1號收銀台,那麼1號收銀台的收銀員她承受的壓力就會比較大,就會很焦慮。這個時候呢,超市經理拿這個大喇叭過來啊,你你你,去2號收銀台、你們去3號收銀台,購物的人很快地就付完錢回家了。haproxy就相當於這個超市經理,哪裡有空閑就調度往哪個節點去。

在理解完haproxy做的事情後,我們來實踐一番吧。

(一)、拉取鏡像

這裡我就不改名了,有興趣的童鞋自己對照pxc改個名字。

docker pull haproxy

(二)、創建haproxy配置文件

這裡其他的配置都不用動,就後面server改成你電腦的配置

# 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

(三)、創建haproxy容器

命令:docker run -it -d -p 4001:8888 -p 4002:3306 -v /root/haproxy:/usr/local/etc/haproxy --name haproxy1 --privileged --net=mysql_net haproxy

這裡把監控介面的8888埠映射到宿主機的4001,然後把資料庫負載均衡的3306埠映射到宿主機的4002

演示:

⚡ root@ataola  ~/haproxy  docker run -it -d -p 4001:8888 -p 4002:3306 -v /root/haproxy:/usr/local/etc/haproxy --name haproxy1 --privileged --net=mysql_net haproxy
0e4ef69c19b981163067ec8af0c38b6fa84c380855c22309a884f0a0ed691912
 ⚡ root@ataola  ~/haproxy  

之後我們進入到這個起起來的容器docker exec -it haproxy1 bash

執行配置命令:haproxy -f /usr/local/etc/haproxy/haproxy.cfg

(四)、創建haproxy資料庫帳號

打開MySQL資料庫,創建一個用戶CREATE USER 'haproxy'@'%' IDENTIFIED BY 'superman';

訪問//localhost:4001/dbs,就可以看到數據集群的情況。

看到這裡就說明你的haproxy搭建成功了,接下來我們進行相關的實踐。

相關實驗

實驗須知

這裡我們在創建了一個test資料庫,在資料庫中創建一張數據表為user,並添加相應的欄位和數據,具體的如下:

實驗一:在主節點和從節點都完好的情況下,分別向主節點和從節點插入數據,看看其他節點的變化。

主節點插入:

我們嘗試在主節點mysql_node1插入數據,然後去mysql_node_2去讀取數據,這裡我們就直接硬核的手排來吧(PS:初次載入時間長,如下圖)

可以看到我們從mysql_node2節點讀取到了mysql_node1主節點寫入的內容。

從節點插入:

把樓上的例子反過來,這次我們從節點插入,主節點讀取看看。

從這個實驗,我們可以印證一點的是,主從節點都是可以讀寫的。

實驗二:掛掉主節點,從節點看能不能插入

接下來我們就要開始搞事情了,把主節點停掉,再從節點插入數據看看。

命令:docker pause mysql_node1

演示:

這個時候主節點是打不開的,相當於宕機了。

我們嘗試著在從節點插入數據,發現從節點也是打不開的

這印證了上面說的強一致性,同步機製為同步, 當主節點掛了以後,其餘節點不可讀寫。

實驗三:掛掉某個從節點,看看主從節點能否插入

我們把node3和node4服務給停掉,接著我們嘗試著打開node1去插入一條張東升試試

可以看到在主節點插入數據,從節點也能夠同步。

接著我們在node2從節點插入張朝陽

可以看到從節點插入成功,也同步到了主節點。

這個時候,我們把node3和node4起起來,看下數據會不會進行一個同步

可以看到,當node3和node4恢復的時候,便會進行一個數據同步,我們便在node3和node4中看到了張東升和張朝陽。

參考文獻

percona介紹://hub.docker.com/_/percona

percona安裝://www.percona.com/doc/percona-server/8.0/installation/docker.html

Docker環境下的前後端分離項目部署與運維: //coding.imooc.com/class/219.html

最後

寫到這裡,筆者也只是記流水賬一樣,記錄了當時的操作過程並加以復現,並沒有對集群關於性能熱備份冷備份等等方面進行深入探討學習,這裡僅作拋磚引玉,有興趣的童鞋接力實踐吧!

知識共享許可協議
本作品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。