MyCat 1.6.7(一)MySQL高可用及分庫分表

簡介

MyCat 是目前最流行的基于 java 語言編寫的數(shù)據(jù)庫中間件,是一個實現(xiàn)了 MySQL 協(xié)議的服務(wù)器沃于,前端用戶可以把它看作是一個數(shù)據(jù)庫代理涩咖,用 MySQL 客戶端工具和命令行訪問海诲,而其后端可以用 MySQL 原生協(xié)議與多個 MySQL 服務(wù)器通信,也可以用 JDBC 協(xié)議與大多數(shù)主流數(shù)據(jù)庫服務(wù)器通信檩互,其核心功能是分庫分表特幔。配合數(shù)據(jù)庫的主從模式還可實現(xiàn)讀寫分離。官方學(xué)習(xí)地址

MyCat2 已經(jīng)可以使用闸昨,目前僅支持java8
垂直分庫 就是微服務(wù)的形式蚯斯,把一個服務(wù)單元拆到一個庫中
垂直分表 把一個大表,字段多的表饵较,拆分成多個小表拍嵌,或按照查詢邏輯拆分主要信息表或次要信息表
水平分庫 把數(shù)據(jù)庫集群,數(shù)據(jù)通過hash 或 取模 的方式散到你的數(shù)據(jù)庫節(jié)點中
水平分表 只針對大表進行切分循诉,按一定的邏輯進行切分

功能

1.讀寫分離

2.數(shù)據(jù)分片横辆,垂直拆分(分庫)、水平拆分(分表)茄猫、垂直+水平拆分(分庫分表)

3.多數(shù)據(jù)源整合

原理

MyCat 的原理種最重要的一個動詞時”攔截“狈蚤,它攔截了用戶發(fā)送過來的SQL語句,首先對SQL語句做了一些特定的分析:如分片分析划纽、路由分析脆侮、讀寫分離分析、緩存分析等阿浓,然后將此SQL發(fā)往后端的真實數(shù)據(jù)庫他嚷,并將返回的結(jié)果做適當(dāng)?shù)奶幚恚罱K再返回給用戶

這種方式把數(shù)據(jù)庫的分布式從代碼中解耦出來芭毙,程序員察覺不出來后臺使用MyCat還是MySQL

安裝及操作

github 地址,這里要找的是打包過的文件下載卸耘,不要下載源碼退敦,除非你要看源碼或改。

# 下載
wget http://dl.mycat.org.cn/1.6.7.6/20210730131311/Mycat-server-1.6.7.6-release-20210730131311-linux.tar.gz
#解壓
tar -xvf Mycat-server-1.6.7.6-release-20210730131311-linux.tar.gz
# 移動到指定文件夾
mv mycat/ /opt/software/

啟動

# 控制臺啟動蚣抗,確認(rèn)啟動過程不會出錯
bin/mycat console
# 后臺啟動
bin/mycat start

配置文件介紹:
1.schema.xml 定義邏輯庫侈百,表、分片節(jié)點等內(nèi)容
2.rule.xml 定義分片規(guī)則
3.server.xml 定義用戶以及系統(tǒng)相關(guān)變量翰铡,如端口等

MyCat連接MySQL換驅(qū)動成8.X

  1. 上傳 mysql-connector-java-8.0.19.jar 到 mycat 的 lib 目錄下
  2. 給文件賦權(quán) chmod 777 mysql-connector-java-8.0.19.jar
  3. 重新啟動钝域。mycat 會自動檢測驅(qū)動,所以不需要我們操心锭魔,如果遇到如下提示例证,則替換驅(qū)動成功
Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.

登錄MyCat

修改 server.xml

<!-- 連接mycat的用戶信息 -->
<user name="mycat" defaultAccount="true">
        <!-- 密碼 -->
        <property name="password">123456</property>
        <!-- 邏輯庫名稱 -->
        <property name="schemas">TESTDB</property>
        <!-- 默認(rèn)邏輯庫  -->
        <property name="defaultSchema">TESTDB</property>
        <!--No MyCAT Database selected 錯誤前會嘗試使用該schema作為schema,不設(shè)置則為null,報錯 -->
        <!-- 表級 DML 權(quán)限設(shè)置 -->
        <!--            
        <privileges check="false">
                <schema name="TESTDB" dml="0110" >
                        <table name="tb01" dml="0000"></table>
                        <table name="tb02" dml="1111"></table>
                </schema>
        </privileges>           
         -->
</user>

配置個基本的連接迷捧,以便登上去查庫中的表

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
        <!-- 在server.xml中被指定的邏輯庫 -->
        <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
        </schema>
        <!-- 對應(yīng)schema中的 DataNode织咧,database 是真正物理上的數(shù)據(jù)庫  -->
        <dataNode name="dn1" dataHost="host1" database="my_sql_test" />
        <!-- name對應(yīng) dataNode 的 datatHost  -->
        <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
        </dataHost>
</mycat:schema>

登錄

# 登錄運維管理窗口
mysql -u賬號 -p密碼 -P 9066 -h IP
# 查看數(shù)據(jù)庫
show database;
# 查看命令
show @@help

# 登錄數(shù)據(jù)窗口
mysql -u賬號 -p密碼 -P 8066 -h IP
# 如
mysql -umycat -p123456 -P8066 -h192.168.81.104 --default-auth=mysql_native_password

--default-auth=mysql_native_password 是因為 mycat 使用的是5.7以下的加密方式登錄

搭建讀寫分離

本文這里使用二進制復(fù)制胀葱,其余復(fù)制可以參考我以前所寫Mysql-8.0.2 主從復(fù)制(GTID)Mysql-8.0.2 高可用MGR笙蒙,建議可以先使用二進制方式抵屿。

二進制日志復(fù)制

主機配置

修改 /etc/my.cnf

# 主服務(wù)器唯一ID
server-id=1
# 啟用二進制日志
log-bin=mysql-bin
# 設(shè)置不要復(fù)制的數(shù)據(jù)庫(可設(shè)置多個)
binlog-ignore-db=mysql
# binlog-ignore-db=information_schema
# 設(shè)置需要復(fù)制的數(shù)據(jù)庫,不配置代表所有,但切記配置不要復(fù)制的庫捅位,建議基礎(chǔ)庫都不排除掉
binlog-do-db=test1
# 設(shè)置binlog格式
binlog_format=STATEMENT

binlog 日志有三種格式

  • STATEMENT 會把sql寫到日志中轧葛,并且?guī)в袝r間,所以從的時間和主的時間必須一致
  • ROW 不記錄寫SQL艇搀,只記錄每行的改變
  • MIXED 切換 STATEMENT 和 ROW

從機配置

server-id=2
# 啟用中繼日志
relay-log=mysql-relay

重啟主機朝群、從機服務(wù)

授權(quán)

主機
# 創(chuàng)建用戶
CREATE USER 賬號@'%' IDENTIFIED BY '密碼';
# 授權(quán)
GRANT REPLICATION SLAVE ON *.* TO 賬號@'%';
# 查看主機的狀態(tài)
mysql> show master status;
+---------------+-----------+--------------+------------------+-----------------------------------------------+
| File          | Position  | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set                             |
+---------------+-----------+--------------+------------------+-----------------------------------------------+
| binlog.000021 | 372357328 |    test1     |       mysql      |                                               |
+---------------+-----------+--------------+------------------+-----------------------------------------------+
  • File binlog 文件
  • Position 接入位置,372357328 之前的數(shù)據(jù)不會復(fù)制
  • Binlog_Do_DB 要復(fù)制的庫
  • Binlog_Ignore_DB 不復(fù)制的庫
從機

建議做之前操作中符,可以把之前的主從配置信息干掉耐床,也就清潔一下夜涕。

# 停止復(fù)制
stop slave;
# 重置復(fù)制信息
reset master;

開始配置

# 配置復(fù)制信息
CHANGE MASTER TO
    MASTER_HOST = '192.168.81.104',
    MASTER_PORT = 3306,
    MASTER_USER = 'repl',
    MASTER_PASSWORD = 'Repl@123',
    MASTER_LOF_FILE='binlog.000021',
    MASTER_LOF_POS=372357328;
# 開始復(fù)制
start slave;
# 查看從機狀態(tài)
show slave status\G;

mycat配置

修改 schema.xml

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
        <!-- 在server.xml中被指定的邏輯庫 -->
        <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
        </schema>
        <!-- 對應(yīng)schema中的 DataNode,database 是真正物理上的數(shù)據(jù)庫  -->
        <dataNode name="dn1" dataHost="host1" database="my_sql_test" />
        <!-- name對應(yīng) dataNode 的 datatHost  -->
        <dataHost name="host1" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021">
                        <!-- 定義讀主機  -->
                        <readHost host="hostS1" url="jdbc:mysql://192.168.81.105:3306" user="dev_fqr" password="Dev@fqr2021" ></readHost>
                </writeHost>
        </dataHost>
</mycat:schema>

dataNode 的 database 屬性,為MySQL 真實的數(shù)據(jù)庫名稱停撞。

dataHost 的 balance 屬性,通過此屬性配置讀寫分離的類型

  • balance="0" 不開啟讀寫分離機制瘫拣,所有讀操作都發(fā)送到當(dāng)前可用的 writeHost
  • balance="1" 全部的 readHost 與 stand by writeHost 參與 select 語句的負(fù)載均衡搏明,簡單來說,當(dāng)雙主雙從模式(M1->S1,M2->S2郭膛,并且M1與M2互為主備)晨抡,正常情況下,M2则剃,S1耘柱,S2都參與 select 語句的負(fù)載均衡。
  • balance="2" 所有讀操作都隨機的在 writeHost棍现、readHost 上分發(fā)
  • balance="3" 所有讀請求隨機的分發(fā)到 readHost 執(zhí)行调煎,writeHost 不負(fù)擔(dān)讀壓力

dataHost 的 writeType 屬性:

  • writeType="0" 所有寫操作發(fā)送到配置的第一個 writeHost,第一個掛了切到還生存的第二個
  • writeType="1" 所有操作都隨機的發(fā)送到配置的 writeHost己肮,1.5以后廢棄不推薦

writeType 重新啟動后以切換后的為準(zhǔn)士袄,切換記錄在配置文件中:dnindex.properties

dataHost 的 switchType 屬性:

  • switchType="1" 默認(rèn)值,自動切換
  • switchType="-1" 不自動切換
  • switchType="2" 基于MySQL 主從同步的狀態(tài)決定是否切換

雙主雙從

主(M)1配置

在以上的主配置中添加

# 在作為從數(shù)據(jù)庫的時候谎僻,有寫入操作也要更新二進制日志文件
log-slave-updates
# 表示自增長字段每次遞增的量娄柳,指自己字段的起始值,其默認(rèn)值是1艘绍,取值范圍是1~65535(主要是區(qū)分M1赤拒,M2的自增)
auto-increment-increment=2
# 表示自增長字段從哪個數(shù)開始,指字段一次遞增多少鞍盗,他的取值范圍是1~65535
auto-increment-offset=1
主(M)2配置

和主1配置不同的是

server-id=3
# 表示自增長字段從哪個數(shù)開始需了,指字段一次遞增多少跳昼,他的取值范圍是1~65535
auto-increment-offset=2

兩臺主機都要創(chuàng)建一個復(fù)制用戶并授權(quán)。

從(S)1肋乍,2

延用之前的從配置鹅颊,但是注意 server-id 一定不一樣,配置完成后需要執(zhí)行以上從機步驟墓造。關(guān)系為 S1->(復(fù)制)M1,S2->M2堪伍。

主1主2相互復(fù)制

主1和主2相互執(zhí)行命令

CHANGE MASTER TO
    MASTER_HOST = '192.168.81.xxx',
    MASTER_PORT = 3306,
    MASTER_USER = 'repl',
    MASTER_PASSWORD = 'Repl@123',
    MASTER_LOF_FILE='binlog.xxxx',
    MASTER_LOF_POS=xxxxx;
# 啟動
start slave;
修改MyCat文件
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
        <!-- 在server.xml中被指定的邏輯庫 -->
        <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
        </schema>
        <!-- 對應(yīng)schema中的 DataNode,database 是真正物理上的數(shù)據(jù)庫  -->
        <dataNode name="dn1" dataHost="host1" database="my_sql_test" />
        <!-- name對應(yīng) dataNode 的 datatHost  -->
        <dataHost name="host1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主1機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021">
                        <!-- 定義讀主1從1機  -->
                        <readHost host="hostS1" url="jdbc:mysql://192.168.81.105:3306" user="dev_fqr" password="Dev@fqr2021" ></readHost>
                </writeHost>
                <!-- 定義寫主2機 -->
                <writeHost host="hostM2" url="jdbc:mysql://192.168.81.106:3306" user="dev_fqr" password="Dev@fqr2021">
                        <!-- 定義讀主2從2機  -->
                        <readHost host="hostS2" url="jdbc:mysql://192.168.81.107:3306" user="dev_fqr" password="Dev@fqr2021" ></readHost>
                </writeHost>
        </dataHost>
</mycat:schema>

垂直切分(分庫)

垂直切分就是微服務(wù)的分庫操作觅闽,如 用戶表帝雇、積分表等在一個庫,被劃分為用戶服務(wù)蛉拙;訂單表尸闸、明細(xì)表、訂單快照表等在一個庫中孕锄,被劃分為訂單服務(wù)吮廉。

修改schema.xml配置

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
        <!-- 在server.xml中被指定的邏輯庫 -->
        <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
            <!-- 配置表,所有對 customer 表的操作都會走 dn2 -->
            <table name="customer" dataNode="dn2"></table>
        </schema>
        <!-- 對應(yīng)schema中的 DataNode畸肆,database 是真正物理上的數(shù)據(jù)庫  -->
        <dataNode name="dn1" dataHost="host1" database="orders" />
        <dataNode name="dn2" dataHost="host2" database="users" />
        <!-- name對應(yīng) dataNode 的 datatHost  -->
        <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主1機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
        </dataHost>
        <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主1機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.105:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
        </dataHost>
</mycat:schema>

table 標(biāo)簽的 name 屬性宦芦,代表實際庫中的表,對所有mycat里customer的操作都會走指定的 dataNode.

水平拆分(分表)

修改schema.xml文件

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
        <!-- 在server.xml中被指定的邏輯庫 -->
        <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
            <!-- 配置表 -->
            <table name="customer" dataNode="dn2"></table>
            <!-- 配置表 -->
            <table name="orders" dataNode="dn1,dn3" rule="mod_rule"></table>
        </schema>
        <!-- 對應(yīng)schema中的 DataNode轴脐,database 是真正物理上的數(shù)據(jù)庫  -->
        <dataNode name="dn1" dataHost="host1" database="orders" />
        <dataNode name="dn3" dataHost="host3" database="orders" />
        <dataNode name="dn2" dataHost="host2" database="users" />
        <!-- name對應(yīng) dataNode 的 datatHost  -->
        <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主1機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
        </dataHost>
        <dataHost name="host3" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主1機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.106:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
        </dataHost>
        <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主1機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.105:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
        </dataHost>
</mycat:schema>

修改rule.xml文件

<!-- 分片規(guī)則 -->
<tableRule name="mod_rule">
        <rule>
                <!-- 指定分片的列 -->
                <columns>customer_id</columns>
                <!-- 指定分片算法调卑,為function的name -->
                <algorithm>mod-long</algorithm>
        </rule>
</tableRule>
<!-- 具體的分片算法指定類 -->
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
        <!-- 數(shù)據(jù)節(jié)點,根據(jù)你要分片的數(shù)量(機器數(shù)量) -->
        <property name="count">2</property>
</function>

tableRule 表規(guī)則大咱,其中name屬性就是 schema.xml table標(biāo)簽的 rule屬性

Mycat的分片 "join"

orders 訂單表已經(jīng)進行分表操作了恬涧,和它關(guān)聯(lián)的 orders_detail 訂單詳情表如何進行 join 查詢?其實我們也要對 orders_detail 進行分片操作徽级。

ER表

Mycat借鑒了NewSQL領(lǐng)域的新秀 Foundation DB 的設(shè)計思路气破,F(xiàn)oundation DB 創(chuàng)新性的提出了 Table Group 的概念,其將子表的存儲位置依賴于主表餐抢,并且物理上緊鄰存放,因此徹底解決了 JOIN 的效率和性能問題低匙,根據(jù)這一思路旷痕,提出了基于 E-R 關(guān)系的數(shù)據(jù)分片策略,子表的記錄與所關(guān)聯(lián)的父表記錄存放在同一個數(shù)據(jù)分片上顽冶。

修改 schema.xml 配置

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
        <!-- 在server.xml中被指定的邏輯庫 -->
        <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
            <!-- 配置表 -->
            <table name="customer" dataNode="dn2"></table>
            <!-- 配置表 -->
            <table name="orders" dataNode="dn1,dn3" rule="mod_rule">
                <!-- join表的name欺抗,該表的(primaryKey)主鍵,該表的(joinKey)外鍵强重,對應(yīng)主表的(parentKey)ID -->
                <childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id" />
            </table>
        </schema>
        <!-- 對應(yīng)schema中的 DataNode绞呈,database 是真正物理上的數(shù)據(jù)庫  -->
        <dataNode name="dn1" dataHost="host1" database="orders" />
        <dataNode name="dn3" dataHost="host3" database="orders" />
        <dataNode name="dn2" dataHost="host2" database="users" />
        <!-- name對應(yīng) dataNode 的 datatHost  -->
        <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主1機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
        </dataHost>
        <dataHost name="host3" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主1機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.106:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
        </dataHost>
        <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主1機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.105:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
        </dataHost>
</mycat:schema>

childTable 為要join的子表

全局表

在分片的情況下贸人,當(dāng)業(yè)務(wù)表因為規(guī)模而進行分片以后,業(yè)務(wù)表與這些附屬的字典表之間的關(guān)聯(lián)佃声,就成了比較棘手的問題艺智,考慮到字典表具有以下幾個特性:

  1. 變動部頻繁
  2. 數(shù)據(jù)量總體變化不大
  3. 數(shù)據(jù)規(guī)模不大,很少有超過數(shù)十萬條記錄

鑒于此圾亏,Mycat定義了一種特殊的表十拣,稱之為"全局表",全局表具有以下特性:

  1. 全局表插入志鹃、更新操作會實時在所有節(jié)點上執(zhí)行夭问,保持各個分片的數(shù)據(jù)一致性
  2. 全局表的查詢操作,只從一個節(jié)點獲取
  3. 全局表可以跟任何一個表進行JOIN操作

將字典或者符合字典特性的一些表定義為全局表曹铃,則從另外一個方面缰趋,很好的解決了數(shù)據(jù)JOIN的難題。通過全局表+基于E-R關(guān)系的分片策略陕见,MyCat 可以滿足 80%以上的企業(yè)應(yīng)用開發(fā)秘血。

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
        <!-- 在server.xml中被指定的邏輯庫 -->
        <schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
            <!-- 配置表 -->
            <table name="customer" dataNode="dn2"></table>
            <!-- 配置表 -->
            <table name="orders" dataNode="dn1,dn3" rule="mod_rule">
                <!-- join表的name,該表的(primaryKey)主鍵淳玩,該表的(joinKey)外鍵直撤,對應(yīng)主表的(parentKey)ID -->
                <childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id" />
            </table>
            <!-- 全局表,name="表名"  dataNode="指定節(jié)點" type="全局global" -->
            <table name="dict_order_type" dataNode="dn1,dn2,dn3" type="global"></table>
        </schema>
        <!-- 對應(yīng)schema中的 DataNode,database 是真正物理上的數(shù)據(jù)庫  -->
        <dataNode name="dn1" dataHost="host1" database="orders" />
        <dataNode name="dn3" dataHost="host3" database="orders" />
        <dataNode name="dn2" dataHost="host2" database="users" />
        <!-- name對應(yīng) dataNode 的 datatHost  -->
        <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主1機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.104:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
        </dataHost>
        <dataHost name="host3" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主1機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.106:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
        </dataHost>
        <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
                <!-- 心跳檢測  -->
                <heartbeat>select user()</heartbeat>
                <!-- 定義寫主1機 -->
                <writeHost host="hostM1" url="jdbc:mysql://192.168.81.105:3306" user="dev_fqr" password="Dev@fqr2021"></writeHost>
        </dataHost>
</mycat:schema>

常用分片規(guī)則

  1. 取模蜕着,此規(guī)則為對分片字段求模運算谋竖。也是水平分表最常用規(guī)則
  2. 分片枚舉,通過在配置文件中配置可能的枚舉ID承匣,自己配置分片蓖乘,本規(guī)則適用于特定的場景,比如有些有任務(wù)需要按照省份或區(qū)縣來做報錯韧骗,而全國省份區(qū)縣固定的嘉抒,這類業(yè)務(wù)使用本條規(guī)則。
# 修改 schema.xml 
<table name="orders" dataNode="dn1,dn3" rule="sharding_by_intfile"></table>

# 修改 rule.xml
<!-- 分片規(guī)則 -->
<tableRule name="mod_rule">
        <rule>
                <!-- 指定分片的列 -->
                <columns>areacode</columns>
                <!-- 指定分片算法袍暴,為function的name -->
                <algorithm>hash-int</algorithm>
        </rule>
</tableRule>
<!-- 具體的分片算法指定類 -->
<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
        <!-- 標(biāo)識配置文件 -->
        <property name="mapFile">partition-hash-int.txt</property>
        <!-- type:0為int類型些侍,非0為String類型 -->
        <property name="type">1</property>
        <!-- 默認(rèn)節(jié)點:小于 0 表示不設(shè)置默認(rèn)節(jié)點,大于等于0表示設(shè)置默認(rèn)節(jié)點政模,
          配置文件找不到枚舉值岗宣,就讓他路由到默認(rèn)節(jié)點找,沒有設(shè)置默認(rèn)節(jié)點淋样,在文件找不到耗式,就報錯 -->
        <property name="defaultNode">0</property>
</function>

# 修改partition-hash-int.txt文件,添加如下
# 找到區(qū)域編號110的,認(rèn)為是第1個數(shù)據(jù)節(jié)點(dn1)
110=0
# 找到區(qū)域編號120的刊咳,認(rèn)為是第2個數(shù)據(jù)節(jié)點(dn3)
120=1
  1. 范圍約定彪见,此分片適用于,提前規(guī)劃好分片字段某個范圍屬于哪個分片娱挨。
# 修改 schema.xml
<table name="payment_info" dataNode="dn1,dn2" rule="auto_sharding_long"></table>

# 修改 rule.xml
<!-- 分片規(guī)則 -->
<tableRule name="auto_sharding_long">
        <rule>
                <!-- 指定分片的列 -->
                <columns>order_id</columns>
                <!-- 指定分片算法余指,為function的name -->
                <algorithm>rang-long</algorithm>
        </rule>
</tableRule>
<!-- 具體的分片算法指定類 -->
<function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
        <!-- 定義范圍 -->
        <property name="mapFile">autopartition-long.txt</property>
        <!-- 不在范圍找默認(rèn)節(jié)點 -->
        <property name="defaultNode">0</property>
</function>
# 修改autopartition-long.txt文件,不在配置文件默認(rèn)找第0個節(jié)點(dn1)
# 0-102 到第1個節(jié)點(dn1)
0-102=0
# 103-200到第2個節(jié)點(dn2)
103-200=1
  1. 按時間分片
# 修改 schema.xml
<table name="login_info" dataNode="dn1,dn2" rule="sharding_by_date"></table>

# 修改 rule.xml
<!-- 分片規(guī)則 -->
<tableRule name="sharding_by_date">
        <rule>
                <!-- 指定分片的列 -->
                <columns>create_time</columns>
                <!-- 指定分片算法让蕾,為function的name -->
                <algorithm>partbyday</algorithm>
        </rule>
</tableRule>
<!-- 具體的分片算法指定類 -->
<function name="partbyday" class="io.mycat.route.function.PartitionByDate">
        <!-- 格式化時間 -->
        <property name="dateFormat">yyyy-MM-dd</property>
        <!-- 開始日期 -->
        <property name="sBeginDate">2021-01-01</property>
        <!-- 結(jié)束日期浪规,結(jié)束日期一定是 節(jié)點*分區(qū)天數(shù),
             也就是我2個節(jié)點探孝,分區(qū)天數(shù)3笋婿,1-3號到dn1,3-6號到dn2顿颅,6-9號的話又分到dn1缸濒;
             如果不設(shè)置結(jié)束日期,則6-9號要分到dn3粱腻,沒有dn3則報錯
         -->
        <property name="sEndDate">2021-01-31</property>
        <!-- 分區(qū)天數(shù) -->
        <property name="sPartionDay">2</property>
</function>

全局序列

在實現(xiàn)分庫分表的情況下庇配,數(shù)據(jù)庫自增主鍵已無法保證自增主鍵的全局唯一,為此绍些,Mycat 提供了全局的 sequence 捞慌,并且提供了包含本地配置和數(shù)據(jù)庫配置等多種實現(xiàn)方式

本地文件

此方式 Mycat 將 sequence 配置到文件中,當(dāng)使用到 sequence 中的配置后柬批,Mycat 會更下 classpath 中的sequence_conf.properties 文件中 sequence 當(dāng)前的值

優(yōu)點:本地加載啸澡,讀取速度快
缺點:抗風(fēng)險能力差,Mycat所在主機宕機后氮帐,無法讀取本地文件嗅虏。

時間戳方式

全局序列 ID=64位二進制(42(毫秒)+5(機器ID)+5(業(yè)務(wù)編碼)+12(重復(fù)累加))換算成十進制為18位的long類型,每秒可以并發(fā)12位二進制的累加上沐。

優(yōu)點:配置簡單
缺點:18位ID過長

數(shù)據(jù)庫方式

利用數(shù)據(jù)庫一個表來進行技術(shù)累加皮服。但是并不是每次生成序列都讀寫數(shù)據(jù)庫,這樣效率太低参咙。Mycat 會預(yù)加載一部分號碼段到 Mycat 的內(nèi)存中龄广,這樣大部分讀寫序列都是在內(nèi)存中完成的。如果內(nèi)存中的號碼段用完了 Mycat 會再向數(shù)據(jù)庫要一次蕴侧。

注意:
MYCAT_SEQUENCE 表和以下的 3 個function蜀细,需要放在同一個節(jié)點上。function請直接在具體節(jié)點的數(shù)據(jù)庫上執(zhí)行戈盈,如果執(zhí)行的時候報:
you might want to use the less safe log_bin_trust_function_creators variable
需要對數(shù)據(jù)庫做如下設(shè)置:
windows下my.ini[mysqld]加上log_bin_trust_function_creators=1
linux下/etc/my.cnf下my.ini[mysqld]加上log_bin_trust_function_creators=1
修改完后,即可在mysql數(shù)據(jù)庫中執(zhí)行下面的函數(shù)。

1. 創(chuàng)建全局序列表
CREATE TABLE MYCAT_SEQUENCE(
    - sequence名稱塘娶,最好為表名
    name varchar(50) NOT NULL,
    -  當(dāng)前value归斤,起始值
    current_value INT NOT NULL,
    -  增長步長! 可理解為mycat在數(shù)據(jù)庫中一次讀取多少個 sequence. 當(dāng)這些用完后, 下次再從數(shù)據(jù)庫中讀取。
    increment INT NOT NULL DEFAULT 100,
    PRIMARY KEY(name)
)ENGINE=INNODB;

# 往表中插入數(shù)據(jù)
INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ('orders',1, 1000);
INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES ('users',1, 1000);

2. 創(chuàng)建全局序列所需函數(shù)
- 獲取當(dāng)前sequence的值 (返回當(dāng)前值,增量)
DROP FUNCTION IF EXISTS mycat_seq_currval;
DELIMITER
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf-8
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
SET retval=“-999999999,null”;
SELECT concat(CAST(current_value AS CHAR),“,”,CAST(increment AS CHAR)) INTO retval FROM MYCAT_SEQUENCE WHERE name = seq_name;
RETURN retval;
END
DELIMITER;

- 設(shè)置sequence值
DROP FUNCTION IF EXISTS mycat_seq_setval;
DELIMITER
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),value INTEGER) RETURNS varchar(64) CHARSET utf-8
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = value
WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END
DELIMITER;

– 獲取下一個sequence值
DROP FUNCTION IF EXISTS mycat_seq_nextval;
DELIMITER
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf-8
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = current_value + increment WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END
DELIMITER;

3. sequence_db_conf.properties相關(guān)配置,指定sequence相關(guān)配置在哪個節(jié)點上
orders=dn1
users=dn1

4. server.xml配置:
<system>
    <!-- 0本地文件 1數(shù)據(jù)庫方式 2時間戳方式 -->
    <property name="sequnceHandlerType">1</property>
</system>

5.插入數(shù)據(jù)
insert into orders(id,title,price) values(next value for MYCATSEQ_ORDERS,'手機','2000.00')刁岸;
insert into (id,name) values(next value for MYCATSEQ_USERS,'張三')脏里;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市虹曙,隨后出現(xiàn)的幾起案子迫横,更是在濱河造成了極大的恐慌,老刑警劉巖酝碳,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矾踱,死亡現(xiàn)場離奇詭異,居然都是意外死亡疏哗,警方通過查閱死者的電腦和手機呛讲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來返奉,“玉大人贝搁,你說我怎么就攤上這事⊙科” “怎么了雷逆?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長污尉。 經(jīng)常有香客問我膀哲,道長,這世上最難降的妖魔是什么十厢? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任等太,我火速辦了婚禮,結(jié)果婚禮上蛮放,老公的妹妹穿的比我還像新娘缩抡。我一直安慰自己,他們只是感情好包颁,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布瞻想。 她就那樣靜靜地躺著,像睡著了一般娩嚼。 火紅的嫁衣襯著肌膚如雪蘑险。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天岳悟,我揣著相機與錄音佃迄,去河邊找鬼泼差。 笑死,一個胖子當(dāng)著我的面吹牛呵俏,可吹牛的內(nèi)容都是我干的堆缘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼普碎,長吁一口氣:“原來是場噩夢啊……” “哼吼肥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起麻车,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缀皱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后动猬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體啤斗,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年枣察,在試婚紗的時候發(fā)現(xiàn)自己被綠了争占。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡序目,死狀恐怖臂痕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情猿涨,我是刑警寧澤握童,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站叛赚,受9級特大地震影響澡绩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜俺附,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一肥卡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧事镣,春花似錦步鉴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至随闪,卻和暖如春阳似,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背铐伴。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工撮奏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留俏讹,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓挽荡,卻偏偏與公主長得像藐石,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子定拟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容