Docker部署MySQL 8.0配置主從同步,Docker部署Mycat配置讀寫分離,數據庫分片

  • 首先準備一臺centos服務器

安裝docker環境:

參考:https://www.runoob.com/docker/centos-docker-install.html

  • docker部署MySQL

注意:創建docker的文件掛載目錄,用docker安裝MySQL的話必須讓容器的存儲目錄掛載到宿主機,不然容器遇到故障有可能數據就沒了.

在宿主機上創建兩個文件夾:

/etc/mysql/conf.d 存放配置文件

/etc/mysql/data 存放MySQL數據

我用的是daocloud家的MySQL鏡像,也可以用官方的,都一樣

docker run --name mysql 
-v /etc/mysql/conf.d:/etc/mysql/conf.d 
-v /etc/mysql/data:/var/lib/mysql
-e MYSQL_ROOT_PASSWORD=123456 -d daocloud.io/mysql:8.0.11

該命令會自動拉取鏡像,並運行,命令中兩行-v的意思就是冒號前面是宿主機的目錄,冒號後是容器的目錄

-e是該鏡像自定義的一個環境變量,可以初始化MySQL的登錄密碼

容器運行起來之後,進入容器,修改加密方式和配置遠程登錄:

然後登錄MySQL

mysql -u root -p123456

因爲MySQL8.0版本的密碼加密方式跟5.7版本不一樣了,這裏還是改成5.7版本的密碼加密方式,不然的話,navicat這類客戶端連接工具是連不上的,從庫連接主庫也可能會有問題

mysql> UPDATE user set host='%' where user='root';
刷新:
mysql> flush privileges;
授權:
mysql> GRANT ALL ON *.* TO 'root'@'%';
mysql> ALTER USER 'root'@'%' IDENTIFIED BY '123456' PASSWORD EXPIRE NEVER;
mysql> ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

因爲我們要做主從和讀寫分離,所以至少需要兩臺以上的MySQL,參照上面的步驟再部署兩個MySQL就可以了

 

  • Docker部署Mycat

環境準備:jdk1.7以上,我這裏用的1.8

mycat下載地址:http://www.mycat.org.cn/

在服務器root目錄新建文件夾:mycat

 Dockerfile的內容如下:

FROM docker.io/centos
COPY ./jdk-8u201-linux-x64.tar.gz /usr/local/
RUN tar -zxvf /usr/local/jdk-8u201-linux-x64.tar.gz -C /usr/local/
ENV JAVA_HOME=/usr/local/jdk1.8.0_201
ENV PATH=$PATH:$JAVA_HOME/bin
ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
COPY ./Mycat-server-1.6.7.3-release-20190927161129-linux.tar.gz  /usr/local/
RUN tar -zxvf /usr/local/Mycat-server-1.6.7.3-release-20190927161129-linux.tar.gz -C /usr/local/
ENV MYCAT_HOME=/usr/local/mycat
VOLUME ["/usr/local/mycat/conf","/usr/local/mycat/log"]
RUN source /etc/profile
RUN source ~/.bash_profile
EXPOSE 8066
CMD ["/usr/local/mycat/bin/mycat", "console"]

Dockerfile的內容很好理解,就是將宿主機的兩個安裝包拷貝到容器中的/usr/local目錄,然後解壓安裝包配置jdk環境變量 

VOLUME ["/usr/local/mycat/conf","/usr/local/mycat/log"]  是容器需要掛載的目錄,我們mycat的配置文件肯定需要掛載到宿主機;

配置數據庫分片:

scheme.xml和server.xml這兩個文件可以從安裝包的默認配置文件中拷貝出來

我這裏是一臺服務器Docker部署了兩個MySQL,另外一臺部署了一個,所以scheme.xml看起來是這樣的:

<?xml version="2.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
        <schema name="blog" checkSQLschema="true" sqlMaxLimit="100">
                <!-- auto sharding by id (long) -->
                <table name="article" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
        </schema>
        <dataNode name="dn1" dataHost="localhost1" database="blog" />
        <dataNode name="dn2" dataHost="localhost2" database="blog" />
        <dataNode name="dn3" dataHost="localhost3" database="blog" />
        <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <!-- can have multi write hosts -->
                <writeHost host="hostM1" url="172.17.0.5:3306" user="root"
                                   password="123456">
                </writeHost>
        </dataHost>
         <dataHost name="localhost2" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <!-- can have multi write hosts -->
                <writeHost host="hostM1" url="192.168.1.107:3306" user="root"
                                   password="123456">
                </writeHost>
        </dataHost>
       <dataHost name="localhost3" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <!-- can have multi write hosts -->
                <writeHost host="hostM1" url="172.17.0.3:3306" user="root"
                                   password="123456">
                </writeHost>
        </dataHost>
</mycat:schema>

 server.xml只需要改user就可以了:

這裏是mycat的登錄用戶名和密碼,都是user

如果有多臺或者多個實例,可以參考官方的配置拓展一下就可以了,這裏不再細說

啓動容器:

 docker run -d --name mycat --restart=always \
  -p 8066:8066 \
  -v /home/mycat/conf:/usr/local/mycat/conf \
  -v /home/mycat/logs:/usr/local/mycat/logs \
  mycat:1.0

查看mycat日誌:

docker logs [容器id]

如果看到日誌最後一行是Running Mycat-server...  則代表啓動成功,然後現在就可以用數據庫連接工具連接mycat了

 插入數據測試一下:

用navicat連接mycat,選擇相應的數據庫,賬戶密碼就是剛剛配置的server.xml裏面的user,user

 任意插入id不同的數據,邏輯表看到就是三條,但是這三條數據是分佈在不同的物理表,可以查看到:

id一定要差異大一點,不然可能還是分到同一個數據庫了,因爲我們選的規則就是auto-sharding-long

如果id太大,就需要新增數據節點了:

Mycat 分片規則

分片規則概述

在數據切分處理中,特別是水平切分中,中間件最終要的兩個處理過程就是數據的切分、數據的聚合。選擇合適的切分規則,至

關重要,因爲它決定了後續數據聚合的難易程度,甚至可以避免跨庫的數據聚合處理。

前面講了數據切分中重要的幾條原則,其中有幾條是數據冗餘表分組(Table Group),這都是業務上規避跨庫join的很好的方

式,但不是所有的業務場景都適合這樣的規則,因此本章將講述如何選擇合適的切分規則。

a. Mycat全局表

如果你的業務中有些數據類似於數據字典,比如配置文件的配置,常用業務的配置或者數據量不大很少變動的表,這些表往往不

是特別大,而且大部分的業務場景都會用到,那麼這種表適合於Mycat全局表,無須對數據進行切分,只要在所有的分片上保存一

份數據即可,Mycat 在Join操作中,業務表與全局表進行Join聚合會優先選擇相同分片內的全局表join,避免跨庫Join,在進行

數據插入操作時,mycat將把數據分發到全局表對應的所有分片執行,在進行數據讀取時候將會隨機獲取一個節點讀取數據。

目前Mycat沒有做全局表的數據一致性檢查,後續版本1.4之後可能會提供全局表一致性檢查,檢查每個分片的數據一致性。

全局表的配置如下

<table name="t_area" primaryKey="id" type="global" dataNode="dn1,dn2" />

b. ER分片表

有一類業務,例如訂單(order)跟訂單明細(order_detail),明細表會依賴於訂單,也就是說會存在表的主從關係,這類似業務

的切分可以抽象出合適的切分規則,比如根據用戶ID切分,其他相關的表都依賴於用戶ID,再或者根據訂單ID切分,總之部分業務

總會可以抽象出父子關係的表。這類表適用於ER分片表,子表的記錄與所關聯的父表記錄存放在同一個數據分片上,避免數據

Join跨庫操作。

以order與order_detail例子爲例,schema.xml中定義如下的分片配置,order,order_detail 根據order_id進行數據切分,保證相

同order_id的數據分到同一個分片上,在進行數據插入操作時,Mycat會獲取order所在的分片,然後將order_detail也插入到

order所在的分片。

<table name="order" dataNode="dn$1-32" rule="mod-long">

<childTable name="order_detail" primaryKey="id" joinKey="order_id" parentKey="order_id" /></table>

c. 多對多關聯

有一類業務場景是 “主表A+關係表+主表B”,舉例來說就是商戶會員+訂單+商戶,對應這類業務,如何切分?

從會員的角度,如果需要查詢會員購買的訂單,那按照會員進行切分即可,但是如果要查詢商戶當天售出的訂單,

那又需要按照商戶做切分,可是如果既要按照會員又要按照商戶切分,幾乎是無法實現,這類業務如何選擇切分規則非常難。目

前還暫時無法很好支持這種模式下的3個表之間的關聯。目前總的原則是需要從業務角度來看,關係表更偏向哪個表,即“A的關

系”還是“B的關係”,來決定關係表跟從那個方向存儲,未來Mycat版本中將考慮將中間表進行雙向複製,以實現從A-關係表

以及B-關係表的雙向關聯查詢如下圖所示:

d. 主鍵分片vs 非主鍵分片

當你沒人任何字段可以作爲分片字段的時候,主鍵分片就是唯一選擇,其優點是按照主鍵的查詢最快,當採用自動增長的序列號

作爲主鍵時,還能比較均勻的將數據分片在不同的節點上。

若有某個合適的業務字段比較合適作爲分片字段,則建議採用此業務字段分片,選擇分片字段的條件如下:

1. 儘可能的比較均勻分佈數據到各個節點上;

2. 該業務字段是最頻繁的或者最重要的查詢條件。

常見的除了主鍵之外的其他可能分片字段有“訂單創建時間”、“店鋪類別”或“所在省”等。當你找到某個合適的業務字段作

爲分片字段以後,不必糾結於“犧牲了按主鍵查詢記錄的性能”,因爲在這種情況下,MyCAT提供了“主鍵到分片”的內存緩存

機制,熱點數據按照主鍵查詢,絲毫不損失性能。

<table name="t_user" primaryKey="user_id" dataNode="dn$1-32" rule="mod-long">

<childTable name="t_user_detail" primaryKey="id" joinKey="user_id" parentKey="user_id" />

</table>

對於非主鍵分片的table,填寫屬性primaryKey,此時MyCAT會將你根據主鍵查詢的SQL語句的第一次執行結果進行分析,確定

該Table 的某個主鍵在什麼分片上,並進行主鍵到分片ID的緩存。第二次或後續查詢mycat會優先從緩存中查詢是否有id–>node

即主鍵到分片的映射,如果有直接查詢,通過此種方法提高了非主鍵分片的查詢性能。

本節主要講了如何去分片,如何選擇合適分片的規則,總之儘量規避跨庫Join是一條最重要的原則,下一節將介紹Mycat目前已有的分片規則,每種規則都有特定的場景,分析每種規則去選擇合適的應用到項目中。

 

  • MySQL主從複製和讀寫分離

主庫在我們啓動docker的時候,掛載了配置文件到宿主機,所以配置不用再進入容器修改了

在宿主機目錄/etc/mysql/conf.d修改my.cnf文件

[mysqld]
sql_mode=STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
# 配置需要主從的數據庫
binlog-do-db=blog
# binlog忽略的數據庫
binlog-ignore-db=mysql
# 啓用二進制日誌
log-bin=mysql-bin
# 服務器唯一id,一般爲ip後綴
server-id=15

pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
secure-file-priv= NULL

然後重啓容器:

docker restart  [容器id]

創建用戶並授權:

GRANT ALL PRIVILEGES ON *.* TO 'slave'@'%';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* to 'slave'@'%';
FLUSH PRIVILEGES;

查看主庫狀態:

show master status;

記住File字段和Position字段

  • 從庫配置

一樣也是在宿主機的文件掛載目錄修改配置,參考上面主庫的修改方式,只是要注意server-id必須跟主庫不一樣;

然後連接從庫,可以用navicat這類工具連接,然後執行命令:

change master to master_host='172.17.0.2',master_port=3306,master_user='slave',master_password='123456',master_log_file='mysql-bin.000005',master_log_pos=155 

master_log_file就是剛剛show master status出來的File字段值,master_log_pos就是Position字段的值,分別表示binlog日誌的文件名和位置;注意master_host的值,一定要正確,如果是單臺機器部署了多個Docker容器,這個host不能配localhost或者其他,要配Docker容器的ip,可以這樣查看宿主機所有的容器ip:

docker inspect -f '{{.Name}} - {{.NetworkSettings.IPAddress }}' $(docker ps -aq)

啓動從庫複製功能:

start slave; 
show slave status;

如果Slave_IO_Running不是yes,那就要檢查主庫的ip端口,賬戶密碼是否正確 ;

如果Slave_SQL_Running不是yes,那就stop slave然後在navicat執行命令set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;再start slave就可以了

至此,主從複製就配置好了,然後測試一下在navicat下,主庫手動插入一條數據,然後查一下從庫,也有一條相同的數據了;(從庫需要有同樣的數據庫才能插入成功)

讀寫分離:

還是上面分片的配置文件scheme.xml

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
        <schema name="blog" checkSQLschema="true" sqlMaxLimit="100">
                <!-- auto sharding by id (long) -->
                <!-- autoIncrement=true 表示該表使用主鍵自增長策略 -->
                <table name="article" dataNode="dn1,dn2,dn3" autoIncrement="true" rule="auto-sharding-long" />
        </schema>
        <dataNode name="dn1" dataHost="localhost1" database="blog" />
        <dataNode name="dn2" dataHost="localhost2" database="blog" />
        <dataNode name="dn3" dataHost="localhost3" database="blog" />
        <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3"
                          writeType="1" dbType="mysql" dbDriver="native" switchType="2"  slaveThreshold="100">
                <heartbeat>show slave status</heartbeat>
                <!-- can have multi write hosts -->
                <writeHost host="hostM1" url="172.17.0.5:3306" user="root"
                                   password="123456">
                <readHost host="hostS" url="172.17.0.3:3306" user="root"
                        password="123456" />
                </writeHost>
        </dataHost>
         <dataHost name="localhost2" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <!-- can have multi write hosts -->
                <writeHost host="hostM1" url="192.168.1.107:3306" user="root"
                                   password="123456">
                </writeHost>
        </dataHost>
       <dataHost name="localhost3" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <!-- can have multi write hosts -->
                <writeHost host="hostM1" url="172.17.0.3:3306" user="root"
                                   password="123456">
                </writeHost>
        </dataHost>
</mycat:schema>

在datahost節點下新增了一個readhost

參數含義:

Balance參數設置:
1. balance=“0”, 所有讀操作都發送到當前可用的writeHost上。
2. balance=“1”,所有讀操作都隨機的發送到readHost。
3. balance=“2”,所有讀操作都隨機的在writeHost、readhost上分發
4. balance=”3”,所有讀請求隨機的分發到wiriterHost對應的readhost執行,writerHost不負擔讀壓力
WriteType參數設置:
1. writeType=“0”, 所有寫操作都發送到可用的writeHost上。
2. writeType=“1”,所有寫操作都隨機的發送到readHost。
3. writeType=“2”,所有寫操作都隨機的在writeHost、readhost分上發。
 “readHost是從屬於writeHost的,即意味着它從那個writeHost獲取同步數據,因此,當它所屬的writeHost宕機了,則它也不會再參與到讀寫分離中來,即“不工作了”,這是因爲此時,它的數據已經“不可靠”了。基於這個考慮,目前mycat 1.3和1.4版本中,若想支持MySQL一主一從的標準配置,並且在主節點宕機的情況下,從節點還能讀取數據,則需要在Mycat裏配置爲兩個writeHost並設置banlance=1。”
switchType 目前有三種選擇:
-1:表示不自動切換
1 :默認值,自動切換
2 :基於MySQL主從同步的狀態決定是否切換

“Mycat心跳檢查語句配置爲 show slave status ,dataHost 上定義兩個新屬性: switchType="2" 與slaveThreshold="100",此時意味着開啓MySQL主從複製狀態綁定的讀寫分離與切換機制。Mycat心跳機制通過檢測 show slave status 中的 "Seconds_Behind_Master", "Slave_IO_Running", "Slave_SQL_Running" 三個字段來確定當前主從同步的狀態以及Seconds_Behind_Master主從複製時延。“

 

如何測試讀寫分離是否成功呢?

可以這樣,我們配置的是讀從庫,寫主庫,從庫會去主動同步主庫的binlog,所以在navicat中,我們把從庫的數據刪幾條

主庫:

從庫:

balance配置的是3,意思就是主庫不承擔讀的壓力,所有的讀請求都會分發到從庫;

那select * from article where title='測試2'就查不出來,'測試2'這條數據只在主庫纔有;

如果還是能查出來,就檢查一下balance是不是配錯了

好了,剩下的就自己玩了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章