MySQL叢集搭建方案(PXC)

豐臣正一發表於2020-08-31

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

為什麼要搭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';

訪問http://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介紹:https://hub.docker.com/_/percona

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

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

最後

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

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

相關文章