使用mycat實現mysql讀寫分離
一、mycat概述
1、mycat
mycat是一個開源的分散式資料庫中介軟體,是一個實現了MySQL 協議的的Server,前端使用者可以把它看作是一個數據庫代理,用MySQL 客戶端工具和命令列訪問,而其後端可以用MySQL 原生(Native)協議與多個MySQL 伺服器通訊,也可以用JDBC 協議與大多數主流資料庫伺服器通訊,其核心功能是分表分庫,即將一個大表水平分割為N 個小表,儲存在後端MySQL 伺服器裡或者其他資料庫裡。官網地址為http://www.mycat.io/。
2、原理
Mycat 的原理的核心是“攔截”,它攔截了使用者傳送過來的SQL 語句,首先對SQL 語句做了一些特定的分析:如分片分析、路由分析、讀寫分離分析、快取分析等,然後將此SQL 發往後端的真實資料庫,並將返回的結果做適當的處理,最終再返回給使用者。
3、mycat的主要特性
(1)支援 SQL 92標準
(2)支援Mysql叢集,可以作為Proxy使用
(3)支援JDBC連線多資料庫
(4)支援各種資料庫,包括Mysql 、mongodb、oracle、sqlserver 、hive 、db2 、 postgresql。
(5)支援galera for mysql叢集,percona-cluster或者mariadb cluster,提供高可用性資料分片叢集
(6)自動故障切換,高可用性
(7)支援讀寫分離,支援Mysql雙主多從,以及一主多從的模式
(8)支援全域性表,資料自動分片到多個節點,用於高效表關聯查詢
(9)支援獨有的基於E-R 關係的分片策略,實現了高效的表關聯查詢
(10)支援一致性Hash分片,有效解決分片擴容難題
(11)多平臺支援,部署和實施簡單
(12)支援Catelet開發,類似資料庫儲存過程,用於跨分片複雜SQL的人工智慧編碼實現
(13)支援NIO與AIO兩種網路通訊機制,Windows下建議AIO,Linux下目前建議NIO
(14)支援Mysql儲存過程呼叫
(15)以外掛方式支援SQL攔截和改寫
(16)支援自增長主鍵、支援Oracle的Sequence機制
4、mycat的應用場景
(1)單純的讀寫分離,此時配置最為簡單,支援讀寫分離,主從切換;
(2)分表分庫,對於超過1000 萬的表進行分片,最大支援1000 億的單表分片;
(3)多租戶應用,每個應用一個庫,但應用程式只連線Mycat,從而不改造程式本身,實現多租戶化;
(4)報表系統,藉助於Mycat 的分表能力,處理大規模報表的統計;
(5)替代Hbase,分析大資料;
(6)作為海量資料實時查詢的一種簡單有效方案
二、mycat的安裝
1、安裝前環境準備
(1)安裝java jdk1.7及以上版本
(2)確保本機的hostname在/etc/hosts裡存在
(3)需要安裝mysql環境
2、下載安裝mycat
(1)下載安裝mycat
# 下載mycat
]# wget http://dl.mycat.io/1.6-RELEASE/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
# 解壓並拷貝至/etc/local目錄下即可使用
]# tar -xf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
]# mv mycat /usr/local/
(2)mycat工作目錄說明
Bin:程式存放目錄
Conf:配置檔案存放目錄,主要的配置檔案有server.xml(Mycat伺服器引數調整和使用者授權的配置檔案),schema.xml(邏輯庫定義和表以及分片定義的配置檔案),rule.xml(分片規則的配置檔案)
lIb:主要存放mycat依賴的一些jar檔案
Logs:日誌檔案存放目錄,日誌每天會進行切割
(3)mycat的啟動
啟動mycat時直接執行mycat的bin目錄下的mycat即可啟動mycat。Mycat啟動後預設監聽8066(資料埠)和9066(管理埠)兩個埠。
# 啟動mysql
]# bin/mycat start
Starting Mycat-server...
(4)登入mycat
登入mycat同登入mysql類似,但需要指定主機和埠。登入的使用者為在server.xml配置檔案中定義的使用者。
]# mysql -h127.0.0.1 -uuser -puser -P8066
三、配置mycat
1、與mycat相關的一些概念
(1)資料庫中介軟體
Mycat沒有儲存引擎,所以並不是完全意義的分散式資料庫系統,而是介於資料庫與應用之間,進行資料處理與互動的中間服務。
(2)邏輯庫(schema)
對實際應用來說,並不需要知道中介軟體的存在,業務開發人員只需要知道資料庫的概念,所以資料庫中介軟體可以被看做是一個或多個數據庫叢集構成的邏輯庫。
(3)邏輯表
邏輯表:分散式資料庫中,對應用來說,讀寫資料的表就是邏輯表。邏輯表,可以是資料切分後,分佈在一個或多個分片庫中,也可以不做資料切分,不分片,只有一個表構成。
分片表:指那些原有的很大資料的表,需要切分到多個數據庫的表,這樣,每個分片都有一部分資料,所有分片構成了完整的資料。
非分片表:不需要進行資料切分的表。
ER 表:子表的記錄與所關聯的父表記錄存放在同一個資料分片上,即子表依賴於父表,通過表分組(Table Group)保證資料Join 不會跨庫操作。
全域性表:所有將字典表或者符合字典表特性的一些表定義為全域性表
(4)分片節點(dataNode)
資料切分後,一個大表被分到不同的分片資料庫上面,每個表分片所在的資料庫就是分片節點。
(5)節點主機(dataHost)
一個或多個分片節點(dataNode)所在的機器就是節點主機(dataHost)。
(6)分片規則(rule)
一個大表被分成若干個分片表,就需要一定的規則,這樣按照某種業務規則把資料分到某個分片的規則就是分片規則。
(7)全域性序列號(sequence)
資料切分後,原有的關係資料庫中的主鍵約束在分散式條件下將無法使用,因此需要引入外部機制保證資料唯一性標識,這種保證全域性性的資料唯一標識的機制就是全域性序列號(sequence)。
2、schema.xml檔案的配置
(1)schema標籤的配置
schema標籤用於定義MyCat例項中的邏輯庫,MyCat可以有多個邏輯庫,每個邏輯庫都有自己的相關配置。可以使用 schema 標籤來劃分這些不同的邏輯庫。 如果不配置 schema 標籤,所有的表配置,會屬於同一個預設的邏輯庫。
需要配置的屬性:
name:定義邏輯資料庫庫名
dataNode:用於繫結邏輯庫到某個具體的資料節點上
checkSQLschema:值為true時,會將操作語句中的邏輯庫名去掉,如果庫名不是定義的邏輯庫名則會發往後端資料庫;值false時,則會把語句原封不動的發往最終的MySQL執行。
sqlMaxLimit:當該schema中有分片表時,才會生效 當該值設定為某個數值時。每條執行的SQL語句,如果沒有加上limit語句,MyCat也會自動的加上所對應的值。
(2)table標籤
Table標籤寫在schema標籤中,Table 標籤定義了MyCat中的邏輯表,所有需要拆分的表都需要在這個標籤中定義。
配置屬性:
Name:定義需要拆分的表的表名
Rule:該屬性用於指定邏輯表要使用的規則名字,規則名字在rule.xml中定義,必須與tableRule標籤中name屬性屬性值一一對應。
dataNode:要拆分到的資料節點名稱
Type:該屬性定義了邏輯表的型別,目前邏輯表只有“全域性表”和”普通表”兩種型別
(3)dataNode標籤
dataNode 標籤定義了MyCat中的資料節點,用於繫結邏輯庫到某個具體的database。一個dataNode標籤就是一個獨立的資料分片。
配置屬性:
Name:定義資料節點的名字,這個名字需要是唯一的,我們需要在table標籤上應用這個名字,來建立表與分片對應的關係。
dataHost:該屬性用於定義該分片屬於哪個資料庫例項的,屬性值是引用dataHost標籤上定義的name屬性。
Database:該屬性用於定義該分片屬性哪個具體資料庫例項上的具體庫
(4)dataHost標籤
該標籤在mycat邏輯庫中作為最底層的標籤存在,直接定義了具體的資料庫例項、讀寫分離配置和心跳語句
配置屬性:
name:唯一標識dataHost標籤,供上層的標籤使用。
maxCon:指定每個讀寫例項連線池的最大連線
minCon:指定每個讀寫例項連線池的最小連線,初始化連線池的大小
balance:負載均衡型別,目前的取值有3種:當balance="0", 不開啟讀寫分離機制,所有讀操作都發送到當前可用的writeHost上;當balance="1",全部的readHost與stand by writeHost參與select語句的負載均衡;balance="2",所有讀操作都隨機的在writeHost、readhost上分發。
writeType:寫操作的負載均衡配置,目前的取值有2種:當writeType="0", 所有寫操作傳送到配置的第一個writeHost,第一個掛了切到還生存的第二個writeHost,重新啟動後已切換後的為準;當writeType=“1”,所有寫操作都隨機的傳送到配置的writeHost,但不推薦使用。
switchType:當master故障時是否自動切換,當值為”-1”時表示不自動切換,”1”為預設值,表示自動切換,當值為”2”時基於MySQL主從同步的狀態決定是否切換,心跳語句為 show slave status。
tempReadHostAvailable:如果配置了這個屬性writeHost 下面的readHost 仍舊可用,預設0 可配置(0、1)
(5)heartbeat標籤
Heartbeat標籤寫在dataHost標籤內,這個標籤內指明用於和後端資料庫進行心跳檢查的語句。
(6)writeHost標籤、readHost標籤
這兩個標籤都指定後端資料庫的相關配置給mycat,用於例項化後端連線池。writeHost標籤寫在dataHost標籤內,readHost標籤寫在writeHost標籤內,用於指定寫例項下的讀例項。
在一個dataHost內可以定義多個writeHost和readHost。但是,如果writeHost指定的後端資料庫宕機,那麼這個writeHost繫結的所有readHost都將不可用。另一方面,由於這個writeHost宕機系統會自動的檢測到,並切換到備用的writeHost上去。
配置屬性:
host:用於標識不同例項,一般writeHost使用*M1,readHost用*S1
url:後端例項連線地址,如果是使用native的dbDriver,則一般為address:port這種形式。用JDBC或其他的dbDriver,則需要特殊指定。
user:後端儲存例項需要的使用者名稱字
password:後端儲存例項需要的密碼
weight:權重 配置在readhost 中作為讀節點的權重
schema.xml配置檔案如下:
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="testdb" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
<table name="tb_item" dataNode="dn1,dn2" rule="auto-sharding-long" />
</schema>
<dataNode name="dn1" dataHost="localhost1" database="course" />
<dataNode name="dn2" dataHost="localhost1" database="course2" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="M1" url="192.168.16.151:3306" user="testuser" password="mysql">
<!-- can have multi read hosts -->
<readHost host="S1" url="192.168.16.152:3306" user="testuser" password="mysql" />
</writeHost>
</dataHost>
</mycat:schema>
3、server.xml檔案的配置
server.xml中用於定義登入mycat的使用者和許可權,定義一個登陸的使用者配置檔案如下:
<user name="test">
<property name="password">test</property>
<property name="schemas">testdb</property>
<property name="readOnly">true</property>
<property name="benchmark">11111</property>
<property name="usingDecrypt">1</property>
<privileges check="false">
<schema name="TESTDB" dml="0010" showTables="custome/mysql">
<table name="tbl_user" dml="0110"></table>
<table name="tbl_dynamic" dml="1111"></table>
</schema>
</privileges>
</user>
(1)user標籤配置
User標籤用來設定登陸的使用者及使用者登入許可權
配置屬性:
name:user標籤中name屬性用來來指定使用者名稱;
password:指定密碼;
readOnly:職位true 或false來限制使用者是否只是可讀的;
schemas:控制使用者可訪問的schema,同時訪問多個schema的話使用逗號隔開
(3)其他的一些配置(定義在system標籤下)
packetHeaderSize : 指定Mysql協議中的報文頭長度。預設4。
maxPacketSize : 指定Mysql協議可以攜帶的資料最大長度。預設16M。
idleTimeout : 指定連線的空閒超時時間。預設30分鐘,單位毫秒。
charset : 連線的初始化字符集。預設為utf8。
txIsolation : 前端連線的初始化事務隔離級別,只在初始化的時候使用,後續會根據客戶端傳遞過來的屬性對後端資料庫連線進行同步
sqlExecuteTimeout:SQL執行超時的時間,預設時間為300秒,單位秒。
(3)與服務相關的一些配置(定義在system標籤下)
bindIp : mycat服務監聽的IP地址,預設值為0.0.0.0。
serverPort : 定義mycat的使用埠,預設值為8066
managerPort : 定義mycat的管理埠,預設值為9066。
4、rule.xml檔案的配置
rule.xml裡面定義了對錶進行拆分所涉及到的規則。我們可以靈活的對錶使用不同的分片演算法,或者對錶使用相同的演算法但具體的引數不同。這個檔案裡面主要有tableRule和function這兩個標籤。在具體使用過程中可以按照需求新增tableRule和function。
(1)tableRule標籤
這個標籤用來定義表規則。屬性及巢狀的一些子標籤的作用如下:
name:指定唯一的名字,用於標識不同的表規則。
rule標籤:指定對物理表中的哪一列進行拆分和使用什麼路由演算法。
columns標籤:指定要拆分的列名字。
algorithm標籤:使用function標籤中的name屬性。連線表規則和具體路由演算法。 多個表規則可以連線到同一個路由演算法上。table標籤內使用。讓邏輯表使用這個規則進行分片。
<tableRule name="auto-sharding-long">
<rule>
<columns>id</columns>
<algorithm>rang-long</algorithm>
</rule>
</tableRule>
(2)function標籤
主要的屬性及子標籤的作用如下:
name:指定演算法的名字。
class:制定路由演算法具體的類名字
property:具體演算法需要用到的一些屬性。
四、mycat的分片
在資料切分處理中,特別是水平切分中,中介軟體最終要的兩個處理過程就是資料的切分、資料的聚合。選擇合適的切分規則,至關重要,因為它決定了後續資料聚合的難易程度,甚至可以避免跨庫的資料聚合處理。
1、全域性表
如果你的業務中有些資料類似於資料字典,比如配置檔案的配置,常用業務的配置或者資料量不大很少變動的表,這些表往往不是特別大,而且大部分的業務場景都會用到,那麼這種表適合於Mycat 全域性表,無須對資料進行切分,只要在所有的分片上儲存一份資料即可,Mycat 在Join 操作中,業務表與全域性表進行Join 聚合會優先選擇相同分片內的全域性表join,避免跨庫Join,在進行資料插入操作時,mycat 將把資料分發到全域性表對應的所有分片執行,在進行資料讀取時候將會隨機獲取一個節點讀取資料。
全域性表的配置:在schema.xml表的table標籤中通過type="global"配置,配置如下:
<table name="t_area" primaryKey="id" type="global" dataNode="dn1,dn2" />
2、常用的分片規則
(1)、ER 分片表
在ER 分片表,子表的記錄與所關聯的父表記錄需存放在同一個資料分片上,避免資料Join 跨庫操作。在ER分片表中要指定join連線的列名,一般為外來鍵。
ER分片表的配置如下:
<table name=“orders” dataNode=“dn1,dn2" rule="mod-long">
<childTable name="order_detail" primaryKey="id" joinKey="order_id" parentKey="order_id" />
</table>
上面的配置中order_detail 根據order_id進行資料切分,保證相同order_id的資料分到同一個分片上,在進行資料插入操作時,Mycat會獲取order所在的分片,然後將order_detail也插入到order所在的分片。
(2)、分片列舉
通過在配置檔案中配置可能的列舉id,自己配置分片,此分片規則適用提前規劃好分片欄位某個範圍屬於哪個分片。
rule.xml中的配置如下:
<tableRule name="auto-sharding-long">
<rule>
<columns>user_id</columns>
<algorithm>rang-long</algorithm>
</rule>
</tableRule>
<function name="rang-long" class="org.opencloudb.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txt</property>
<property name="defaultNode">0</property>
</function>
上面配置中各子標籤及屬性含義:
columns:標識將要分片的表字段
algorithm:分片函式
mapFile:配置檔案路徑
defaultNode:超過範圍後的預設節點
在schema.xml的table標籤中配置如下:
<table name="orders" dataNode="dn1,dn2" rule="auto-sharding-long"> </table>
partition-hash-int.txt 配置:
10000=0
10010=1 DEFAULT_NODE=1
(3)、取模分片
取摸分片是對分片欄位求摸運算,然後根據取摸的結果將資料存放在不同的分片上。server.xml配置如下:
<tableRule name="mod-long">
<rule>
<columns>user_id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<function name="mod-long" class="org.opencloudb.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">3</property>
</function>
各欄位的配置同上面的配置相同,count用來表示儲存在幾個分片中。
(4)按月份
按月份列分割槽 ,每個自然月為一個分片,配置例項如下:
<tableRule name="sharding-by-month">
<rule>
<columns>create_time</columns>
<algorithm>sharding-by-month</algorithm>
</rule>
</tableRule>
<function name="sharding-by-month" class="org.opencloudb.route.function.PartitionByMonth">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2014-01-01</property>
</function>
tableRule標籤中的欄位同上面相同,function標籤欄位屬性如下:
dateFormat:日期字串格式
sBeginDate:開始日期
3、使用分片時要注意的事項
(1)能不分則不分,1000萬以內的表,不建議分片,通過合適的索引,讀寫分離等方式,可以很好的解決效能問題。
(2)分片數量儘量少
(3)分片規則需要慎重選擇
(4)儘量不要在一個事務中的SQL跨越多個分片
(5)查詢條件儘量優化,儘量避免Select * 的方式
五、使用mycat配置mysql讀寫分離
1、準備工作
(1)mysql節點的及mycat節點的準備
主機名 |
IP地址 |
作用 |
版本 |
複製使用者 |
Mycats使用使用者 |
mysql-master |
192.168.16.151 |
Mysql主 |
5.7.23 |
repl |
root |
mysql-slave01 |
192.168.16.152 |
Mysql從 |
5.7.23 |
root |
|
MYCAT |
192.168.16.155 |
Mycat節點 |
1.6 |
dayi |
(2)拓撲結構
2、配置主從同步
(1)配置主庫
# 在主庫上建立用於複製的使用者
mysql> CREATE USER 'repl'@'192.168.16.%' IDENTIFIED BY 'replication';
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.16.%';
# 配置主庫的server-id及開啟binglog,配置完成後需要重啟mysql
[mysqld]
log-bin=mysql-bin
server-id=1
# mysql操作表時不區分大小寫,不配置使用mycat時可能會報錯
lower_case_table_names=1
# 設定字符集及需要同步的庫
replicate-do-db=course
character-set-server=utf8
init_connect='SET AUTOCOMMIT=0;set names utf8'
# 鎖定所有的表,防止寫入
mysql> FLUSH TABLES WITH READ LOCK;
# 獲取當前日誌資訊
mysql> SHOW MASTER STATUS\G
*************************** 1. row ***************************
File: mysql-bin.000001
Position: 1594
# 將主庫上的資料匯出並傳到從庫
~]# mysqldump --all-databases --master-data -u root -p > dbdump.db
~]# scp dbdump.db [email protected]:/data/mysql/data
# 釋放主庫鎖
mysql> unlock tables;
(2)配置從庫
# 配置從庫的server-id並重啟重庫
[mysqld]
server-id=2
# 設定字符集及需要同步的庫
replicate-do-db=course
character-set-server=utf8
init_connect='SET AUTOCOMMIT=0;set names utf8'
# mysql操作表時不區分大小寫,不配置使用mycat時可能會報錯
lower_case_table_names=1
# 在從庫上匯入主庫匯出的資料
~]# mysql -uroot -p </data/mysql/data/dbdump.db
# 登入資料庫開啟主從同步
mysql> reset slave;
mysql> CHANGE MASTER TO
-> MASTER_HOST='192.168.16.151',
-> MASTER_PORT=3306,
-> MASTER_USER='repl',
-> MASTER_PASSWORD='replication',
-> MASTER_LOG_FILE='mysql-bin.000003',
-> MASTER_LOG_POS=194;
mysql> start slave;
3、配置mycat
(1)配置schema.xml檔案
Schema.xml檔案的配置內容如下
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<!--定義邏輯庫,TESTDB一定要大寫。由於沒有對錶分片,不需要定義table,並且讓語句原封不動的發往後端-->
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
</schema>
<!--資料節點dn1,對應的主機c1,對應是資料庫db1 -->
<dataNode name="dn0" dataHost="node1" database="course" />
<!-- 定義主機C1,開啟讀寫分離機制-->
<dataHost name="node1" maxCon="1000" minCon="10" balance="1" writeType="0" switchType="1" dbType="mysql" dbDriver="native">
<!--定義心跳檢測機制-->
<heartbeat>select user()</heartbeat>
<!--定義MySQL的寫的資料,master1 -->
<writeHost host="M1" url="192.168.16.151:3306" user="root" password="[email protected]">
<!--定義MySQL讀的資料庫,slave1 -->
<readHost host="S1" url="192.168.16.152:3306" user="root" password="[email protected]" />
</writeHost>
</dataHost>
</mycat:schema>
(2)配置server.xml
通過server.xml定義登入mycat的庫以及登入使用者,定義的邏輯庫名與schema.xml中schema標籤中的name欄位定義的庫名要相同。新增定義一個登入使用者的配置檔案如下:
<!--配置使用者名稱-->
<user name="root">
<!--配置密碼-->
<property name="password">dayi123</property>
<!--配置邏輯庫-->
<property name="schemas">testdb</property>
</user>
(3)使用mycat
由於沒有使用分片功能所以不用配置rule.xml,配置完成後重啟mycat後即可使用。
# 重啟mycat
]# ./mycat restart
# 登入mycat
[[email protected] bin]# mysql -h192.168.16.155 -uroot -p -P8066
# 通過mycat操作資料庫
mysql> use TESTDB
Database changed
mysql> show tables;
+------------------+
| Tables_in_course |
+------------------+
| course |
| dept |
| score |
| student |
六、管理mycat
Mycat安裝完成後預設會監聽兩個埠,8066為資料埠,9066為管理埠登入方式同mysal登入方式類似。
# 登入mycat管理埠
]# mysql -h127.0.0.1 -uuser -puser -P9066
Mycat的主要管理命令如下:
show @@help; 檢視所有的命令
reload @@config_all; 該命令用於更新配置檔案
show @@database; 該命令用於顯示MyCAT的資料庫的列表,對應schema.xml配置檔案的schema子節點。
show @@datanode; 該命令用於顯示MyCAT的資料節點的列表,對應schema.xml配置檔案的dataNode節點
show @@heartbeat:該命令用於報告心跳狀態
show @@connection:該命令用於獲取Mycat的前端連線狀態,即應用與mycat的連線
kill @@connection id,id,id :用於殺掉連線。
show @@cache; 檢視mycat快取;SQLRouteCache為sql路由快取。 TableID2DataNodeCache為快取表主鍵與分片對應關係。 ER_SQL2PARENTID :為快取ER分片中子表與父表關係。
show @@datasource; 檢視資料來源狀態,如果配置了主從,或者多主可以切換。
switch @@datasource name:index:切換資料來源,name為schema中配置的dataHost 中name。index為schema中配置的dataHost 的writeHost index 位標(按照配置順序從上到下的一次順 序,從0開始)。