Mycat基礎(chǔ)入門

一魂务、Mycat簡介

1.1 什么是Mycat

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)讀寫分離校镐。

Mycat是基于阿里開源的Cobar產(chǎn)品而研發(fā)亿扁,Cobar的穩(wěn)定性、可靠性鸟廓、優(yōu)秀的架構(gòu)和性能以及眾多成熟的使用案例使得MyCat變得非常的強(qiáng)大从祝。

Mycat發(fā)展到目前的版本,已經(jīng)不是一個單純的MySQL代理了引谜,它的后端可以支持MySQL牍陌、SQL Server、Oracle员咽、DB2毒涧、PostgreSQL等主流數(shù)據(jù)庫,也支持MongoDB這種新型NoSQL方式的存儲贝室,未來還會支持更多類型的存儲契讲。而在最終用戶看來,無論是哪種存儲方式滑频,在MyCat里捡偏,都是一個傳統(tǒng)的數(shù)據(jù)庫表,支持標(biāo)準(zhǔn)的SQL語句進(jìn)行數(shù)據(jù)的操作峡迷,這樣一來银伟,對前端業(yè)務(wù)系統(tǒng)來說你虹,可以大幅降低開發(fā)難度,提高開發(fā)速度彤避。

Mycat官網(wǎng)
Mycat電子書籍

1.2 使用Mycat后的結(jié)構(gòu)圖
使用Mycat后的結(jié)構(gòu)圖

二傅物、Mycat中的概念

2.1 切分

邏輯上的切分,在物理層面琉预,是使用多庫董饰、多表來實現(xiàn)切分的。

2.1.1 Mycat垂直拆分

垂直分庫是根據(jù)數(shù)據(jù)庫里面的數(shù)據(jù)表的業(yè)務(wù)進(jìn)行拆分圆米,比如:一個數(shù)據(jù)庫里面既存在用戶數(shù)據(jù)尖阔,又存在訂單數(shù)據(jù),那么垂直拆分可以把用戶數(shù)據(jù)放入到用戶庫榨咐,把訂單數(shù)據(jù)放到訂單庫。

垂直分表是對數(shù)據(jù)表進(jìn)行垂直拆分的一種方式谴供,常見是把一個多字段的大表按常用字段和非常用字段進(jìn)行拆分块茁,每個表里面的數(shù)據(jù)記錄數(shù)一般情況下是相同的,只是字段不一樣桂肌,使用主鍵關(guān)聯(lián)数焊。
比如原始用戶表是:

原始用戶表

垂直拆分后的表是:

垂直拆分后的表

垂直拆分的優(yōu)點是:

  • 可以使得數(shù)據(jù)變小,一個數(shù)據(jù)塊(block)就能存放更多的數(shù)據(jù)崎场,在查詢時就會減少I/O次數(shù)(每次查詢時讀取的Block就少)
  • 可以達(dá)到最大化利用Cache的目的佩耳,具體在垂直拆分的時候可以將不常變的字段放一起,將經(jīng)常改變的放一起
  • 數(shù)據(jù)維護(hù)簡單

缺點是:

  • 主鍵出現(xiàn)冗余谭跨,需要管理冗余例
  • 會引起表連接JOIN操作(增加CPU開銷)可以通過在業(yè)務(wù)服務(wù)器上進(jìn)行join來減少數(shù)據(jù)庫壓力
  • 依然存在單表數(shù)據(jù)量過大的問題(需要水平拆分)
  • 事務(wù)處理復(fù)雜
2.1.2 Mycat水平拆分

水平拆分是通過某種策略將數(shù)據(jù)分片來存儲干厚,有庫內(nèi)分表、分庫兩部分螃宙,每片數(shù)據(jù)會分散到不同的MySQL表或庫蛮瞄,達(dá)到分布式的效果,能夠支持非常大的數(shù)據(jù)量谆扎。

水平拆分表如下:

水平拆分表

實際情況中往往會是垂直拆分和水平拆分的結(jié)合挂捅,即將Users_A_M和Users_N_Z再拆成Users和UserExtras,這樣一共四張表堂湖。

水平拆分的優(yōu)點是:

  • 不存在單庫大數(shù)據(jù)和高并發(fā)的性能瓶頸
  • 應(yīng)用端改造較少
  • 提高了系統(tǒng)的穩(wěn)定性和負(fù)載能力

缺點是:

  • 分片事務(wù)一致性難以解決
  • 跨節(jié)點Join性能差闲先,邏輯復(fù)雜
  • 數(shù)據(jù)多次擴(kuò)展難度跟維護(hù)量極大
2.2 邏輯庫 & 邏輯表
  • 邏輯庫-Schema:Mycat中定義的database是邏輯上存在的,但是物理上是不存在的无蜂。
  • 邏輯表-table:Mycat中定義的table是邏輯上存在的伺糠,但是物理上是不存在的。
2.3 數(shù)據(jù)主機(jī) & 數(shù)據(jù)節(jié)點
  • 數(shù)據(jù)主機(jī)-dataHost:是物理MySQL存放的主機(jī)地址酱讶,可以使用主機(jī)名退盯、IP、域名定義。
  • 數(shù)據(jù)節(jié)點-dataNode:配置物理的database渊迁,數(shù)據(jù)保存的物理節(jié)點就是database慰照。
2.4 分片規(guī)則

當(dāng)控制數(shù)據(jù)的時候,如何訪問物理database和table琉朽,就是訪問dataHost和dataNode的算法毒租。在MyCat處理具體的數(shù)據(jù)CRUD的時候,如何訪問dataHost和dataNode的算法箱叁,如哈希算法墅垮、crc32算法等。

三耕漱、Mycat的使用

3.1 讀寫分離

原理:需要搭建主從模式算色,讓主數(shù)據(jù)庫(master)處理事務(wù)性增、改螟够、刪操作灾梦,而從數(shù)據(jù)庫(slave)處理查詢操作。

Mycat配合數(shù)據(jù)庫本身的復(fù)制功能妓笙,可以解決讀寫分離的問題若河。

3.2 主從備份
3.2.1 主從備份概念

主從備份就是一種主備模式的數(shù)據(jù)庫應(yīng)用。主庫數(shù)據(jù)與備庫數(shù)據(jù)完全一致寞宫;實現(xiàn)數(shù)據(jù)的多重備份萧福,保證數(shù)據(jù)的安全;可以在master[InnoDB]和slave[MyISAM]中使用不同的數(shù)據(jù)庫引擎辈赋,實現(xiàn)讀寫的分離鲫忍。

備注:InnoDB支持事物,MyISAM不支持事物钥屈,MyISAM查詢效率更高饲窿。

3.2.2 MySQL5.5、5.6版本后本身支持主從備份

MySQL5.5焕蹄、5.6版本后本身支持主從備份逾雄,在老舊版本的MySQL數(shù)據(jù)庫系統(tǒng)中,不支持主從備份腻脏,需要安裝額外的RPM包鸦泳,如果需要安裝RPM包,只能在一個位置節(jié)點安裝永品。

3.2.3 主從備份目的
  • 實現(xiàn)主備模式:保證數(shù)據(jù)的安全做鹰,盡量避免數(shù)據(jù)丟失的可能。
  • 實現(xiàn)讀寫分離:使用不同的數(shù)據(jù)庫引擎鼎姐,實現(xiàn)讀寫分離钾麸,提高所有操作的效率更振。
3.2.4 主從模式下的邏輯圖

基于日志來實現(xiàn)主從數(shù)據(jù)同步

主從模式下的邏輯圖
3.3 MySQL的主從模式搭建
3.3.1 安裝MySQL

已安裝
主庫:47.115.26.11
從庫:47.105.146.74

3.3.2 主從備份配置-master[主庫]配置

1、修改master的配置文件

vi /etc/mysql/mysql.conf.d/mysqld.cnf

注意:該配置文件由于系統(tǒng)環(huán)境不同饭尝,安裝方式不同肯腕,版本不同,因此目錄钥平、配置文件名也可能不相同实撒。

2、添加server_id
server_id是MySQL服務(wù)唯一標(biāo)識涉瘾,可任意配置知态,只要是數(shù)字即可,但master唯一標(biāo)識數(shù)字必須小于slave唯一標(biāo)識數(shù)字立叛。

3负敏、log_bin
開啟日志功能以及日志文件命名,log_bin=master_log秘蛇,變量的值就是日志文件名稱原在,是日志文件名稱的主體,MySQL數(shù)據(jù)庫自動增加文件名后綴和文件類型彤叉。

log_bin=/var/log/mysql/master_log
server_id=1
修改mysqld.cnf

4、重啟MySQL

sudo service mysql restart

5村怪、訪問MySQL

mysql -u root -p

6秽浇、創(chuàng)建用戶
在MySQL數(shù)據(jù)庫中,為不存在的用戶授權(quán)甚负,會自動創(chuàng)建對應(yīng)用戶并授權(quán)(不需要先創(chuàng)建用戶再授權(quán))柬焕,當(dāng)前我們要創(chuàng)建的用戶是從庫訪問主庫使用的用戶。

IP地址不能寫%梭域,因為主從備份中斑举,當(dāng)前創(chuàng)建的用戶是給從庫slave訪問主庫master使用的,用戶必須有指定的訪問地址病涨,不能是通用地址富玷。

grant all privileges on *.* to 'myslave'@'47.105.146.74' identified by 'myslave@123AC' with grant option;
flush privileges;

7、查看用戶

use mysql;
select host,user from user;
查看用戶

8既穆、查看master信息

show master status;
查看master信息

9缅疟、關(guān)閉防火墻或在防火墻中開放3306端口

3.3.3 主從備份配置-slave[從庫]配置

1拌倍、修改master的配置文件

vi /etc/mysql/mysql.conf.d/mysqld.cnf

2、添加server_id
server_id是MySQL服務(wù)唯一標(biāo)識,可任意配置荚虚,只要是數(shù)字即可,但master唯一標(biāo)識數(shù)字必須小于slave唯一標(biāo)識數(shù)字续徽。

server_id=2

3畏妖、重啟MySQL

sudo service mysql restart

4傅瞻、訪問MySQL

mysql -u root -p

5、停止slave功能

stop slave;

6盲憎、配置主庫信息
需要修改的數(shù)據(jù)是依據(jù)master信息修改的嗅骄,IP是master所在物理機(jī)IP,用戶名和密碼是master提供的slave訪問用戶名和密碼焙畔,日志文件是在master中查看的主庫信息提供的掸读,在master中使用show master status查看日志文件名稱。

查看master信息
// 在從庫中配置主庫信息

change master to master_host='47.115.26.11',master_user='myslave',master_password='myslave@123AC',master_log_file='master_log.000001';

7宏多、啟動slave功能

start slave;

8儿惫、查看slave配置

show slave status \G;
查看slave配置
3.4 測試主從數(shù)據(jù)同步

1、在主庫中創(chuàng)建數(shù)據(jù)

create database master_slave_test_db character set utf8mb4;

2伸但、查看主庫中的數(shù)據(jù)庫

show databases;
查看主庫中的數(shù)據(jù)庫

可以查看到到剛才創(chuàng)建的master_slave_test_db 數(shù)據(jù)庫

3肾请、查看從庫中的數(shù)據(jù)庫

show databases;
查看從庫中的數(shù)據(jù)庫

可以查看到到剛才在主庫中創(chuàng)建的master_slave_test_db 數(shù)據(jù)庫,說明從庫已經(jīng)同步到主庫信息了更胖。

注意:如果發(fā)現(xiàn)從庫沒有同步到主庫的信息铛铁,檢查一下master_log_file的文件名配置的是否正確并檢查slave配置信息是否有異常。

//檢查master_log_file的文件名配置的是否正確

// 1却妨、在主庫中執(zhí)行
show master status;

// 2饵逐、在從庫中執(zhí)行
show slave status \G;
同步失敗原因舉例

重點:根據(jù)異常信息對數(shù)據(jù)庫進(jìn)行了處理后(如補(bǔ)充從庫中的數(shù)據(jù)表、字段等)彪标,需要停止slave倍权,重新配置主庫信息,再啟動slave捞烟,否則會一直同步失敗薄声。

4、在主庫中創(chuàng)建數(shù)據(jù)表并查看

use master_slave_test_db;
create table t_user(id int,name varchar(45));
show tables;
在主庫中創(chuàng)建數(shù)據(jù)表并查看

5题画、查看從庫中的數(shù)據(jù)表

use master_slave_test_db;
show tables;
查看從庫中的數(shù)據(jù)表

四默辨、安裝Mycat

4.1 安裝并配置JDK

省略

4.2 在主庫和從庫上都需要處理

1、開放3306端口
2苍息、保證root用戶可以被Mycat訪問

grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option;

flush privileges;
4.3 解壓上傳的Mycat壓縮包

MyCat我將安裝到39.108.250.186這臺機(jī)器上

scp D:/temp/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz root@39.108.250.186:/data/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
4.4 解壓
tar -zxf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
4.5 注意事項

1缩幸、將Mycat下載到本地后,在windows 10上竞思,如果設(shè)置了隱藏后綴名桌粉,文件名不會顯示后綴.gz,因此上傳到遠(yuǎn)程服務(wù)器時,要把文件名.gz加上衙四。

2铃肯、將Mycat下載到本地后,不能先用解壓工具解壓传蹈,再壓縮成.zip文件再上傳到服務(wù)器押逼,這樣傳到服務(wù)器步藕,再解壓是無法運行Mycat的

4.5 Mycat目錄介紹
  • bin目錄里是啟動腳本
  • conf目錄里是配置文件
  • catlet為MyCat的一個擴(kuò)展功能
  • lib目錄里是MyCat和它的依賴jar
  • logs目錄里是console.log用來保存控制日志,mycatlog用來保存mycat的log4j日志

五挑格、Mycat配置文件

MyCat的架構(gòu)其實很好理解咙冗,Mycat是代理,Mycat后面就是物理數(shù)據(jù)庫漂彤,和Web服務(wù)器的Nginx類似雾消。對于使用者來說,訪問的都是Mycat挫望,不會接觸到后端的數(shù)據(jù)庫立润,我們現(xiàn)在做一個主從、讀寫分離媳板,結(jié)構(gòu)如下圖

結(jié)構(gòu)圖

Mycat的配置文件都在conf目錄里面桑腮,這里介紹幾個常用的文件

  • server.xml :Mycat的配置文件,設(shè)置賬號蛉幸、參數(shù)等破讨;
  • schema.xml:Mycat對應(yīng)的物理數(shù)據(jù)庫和數(shù)據(jù)庫表的配置;
  • rule.xml:Mycat分片(分庫分表)規(guī)則奕纫;
5.1 server.xml
5.1.1 server.xml 內(nèi)容
  省略……
        <user name="root" defaultAccount="true">
                <property name="password">123456</property>
                <property name="schemas">TESTDB</property>

                <!-- 表級 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>

        <user name="user">
                <property name="password">user</property>
                <property name="schemas">TESTDB</property>
                <property name="readOnly">true</property>
        </user>
省略……

如Mycat中的用戶提陶,用戶可以訪問的邏輯庫,可以訪問的邏輯表匹层,服務(wù)端口號等

  • user:用戶配置節(jié)點隙笆;
  • name:登錄的用戶名,也就是連接Mycat的用戶名又固;
  • password:登錄的密碼,也就是連接Mycat的密碼煤率;
  • schemas:邏輯庫名仰冠,這里會和schema.xml中的配置關(guān)聯(lián),多個用逗號分開蝶糯,例如需要這個用戶管理兩個數(shù)據(jù)庫db1,db2洋只,則配置db1,db2
  • privileges:配置用戶針對表的增刪改查的權(quán)限;

Mycat的server.xml配置文件默認(rèn)配置了一個賬號root昼捍,密碼是123456识虚,數(shù)據(jù)庫是TESTDB,讀寫權(quán)限都有,沒有針對表做任何特殊的權(quán)限妒茬。

5.1.2 配置權(quán)限

dml權(quán)限順序為:insert(新增)担锤、update(修改)、select(查詢)乍钻、delete(刪除),0000~1111,0為禁止權(quán)限肛循,1為開啟權(quán)限铭腕。

5.2 schema.xml
5.2.1 schema.xml內(nèi)容

schema.xml是最主要的配置文件,首先看默認(rèn)的配置文件

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

        <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
                <!-- auto sharding by id (long) -->
                <table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />

                <!-- global table is auto cloned to all defined data nodes ,so can join
                        with any table whose sharding node is in the same data node -->
                <table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />
                <table name="goods" primaryKey="ID" type="global" dataNode="dn1,dn2" />
                <!-- random sharding using mod sharind rule -->
                <table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3"
                           rule="mod-long" />
                <!-- <table name="dual" primaryKey="ID" dataNode="dnx,dnoracle2" type="global"
                        needAddLimit="false"/> <table name="worker" primaryKey="ID" dataNode="jdbc_dn1,jdbc_dn2,jdbc_dn3"
                        rule="mod-long" /> -->
                <table name="employee" primaryKey="ID" dataNode="dn1,dn2"
                           rule="sharding-by-intfile" />
                <table name="customer" primaryKey="ID" dataNode="dn1,dn2"
                           rule="sharding-by-intfile">
                        <childTable name="orders" primaryKey="ID" joinKey="customer_id"
                                                parentKey="id">
                                <childTable name="order_items" joinKey="order_id"
                                                        parentKey="id" />
                        </childTable>
                        <childTable name="customer_addr" primaryKey="ID" joinKey="customer_id"
                                                parentKey="id" />
                </table>
                <!-- <table name="oc_call" primaryKey="ID" dataNode="dn1$0-743" rule="latest-month-calldate"
                        /> -->
        </schema>
        <!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
                /> -->
        <dataNode name="dn1" dataHost="localhost1" database="db1" />
        <dataNode name="dn2" dataHost="localhost1" database="db2" />
        <dataNode name="dn3" dataHost="localhost1" database="db3" />
        <!--<dataNode name="dn4" dataHost="sequoiadb1" database="SAMPLE" />
         <dataNode name="jdbc_dn1" dataHost="jdbchost" database="db1" />
        <dataNode       name="jdbc_dn2" dataHost="jdbchost" database="db2" />
        <dataNode name="jdbc_dn3"       dataHost="jdbchost" database="db3" /> -->
        <dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100" maxRetryCount="4">
                <heartbeat>select user()</heartbeat>
                <!-- can have multi write hosts -->
                <writeHost host="hostM1" url="localhost:3306" user="root"
                                   password="123">
                        <!-- can have multi read hosts -->
                        <readHost host="hostS2" url="localhost:3306" user="root" password="123" />
                </writeHost>

               <writeHost host="hostS1" url="localhost:3306" user="root"
                                   password="123" />
                <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
        </dataHost>
       
</mycat:schema>

在配置文件中可以定義讀寫分離多糠,邏輯庫累舷,邏輯表,dataHost夹孔,dataNode等信息被盈。

  • schema:配置邏輯庫,name與server.xml中schema對應(yīng)搭伤;
  • dataNode:定義數(shù)據(jù)節(jié)點的標(biāo)簽只怎,也就是分庫相關(guān)配置;
  • dataHost:物理數(shù)據(jù)庫闷畸,真正存儲數(shù)據(jù)的數(shù)據(jù)庫尝盼;
5.2.2 節(jié)點與屬性介紹
5.2.2.1 標(biāo)簽schema

配置邏輯庫的標(biāo)簽

1、屬性name
邏輯庫名稱

2佑菩、屬性checkSQLshema
是否檢測SQL語法中的schema信息盾沫,如:Mycat邏輯庫名稱A,dataNode名稱B殿漠;
SQL:select * from A.table;
checkSQLshema值是true,Mycat發(fā)送到數(shù)據(jù)庫的SQL是:select * from table;
checkSQLshema值是false,Mycat發(fā)送到數(shù)據(jù)庫的SQL是:select * from A.table;

3赴精、屬性sqlMaxLimit
Mycat在執(zhí)行SQL的時候,如果SQL語句中沒有l(wèi)imit子句绞幌,自動增加limit子句蕾哟,避免一次性得到過多的數(shù)據(jù),影響效率莲蜘,limit子句的限制數(shù)量默認(rèn)配置為100谭确,如果SQL中有具體的limit子句,當(dāng)前屬性失效票渠。

5.2.2.2 標(biāo)簽table

定義邏輯表的標(biāo)簽

1逐哈、屬性name
邏輯表名

2、屬性dataNode
數(shù)據(jù)節(jié)點名稱问顷,即物理數(shù)據(jù)庫中的database名稱昂秃,多個名稱使用逗號分隔。

3杜窄、屬性rule
分片規(guī)則名稱肠骆,具體的規(guī)則名稱參考rule.xml配置文件。

5.2.2.3 標(biāo)簽dataNode

定義數(shù)據(jù)節(jié)點的標(biāo)簽

1塞耕、屬性name
數(shù)據(jù)節(jié)點名稱蚀腿,是定義的邏輯名稱,對應(yīng)具體的物理數(shù)據(jù)庫database

2扫外、屬性dataHost
引用dataHost標(biāo)簽的name值唯咬,代表使用的物理數(shù)據(jù)庫所在位置和配置信息

3纱注、屬性database
在dataHost物理機(jī)中,具體的物理數(shù)據(jù)庫database名稱

5.2.2.4 標(biāo)簽dataHost

定義數(shù)據(jù)主機(jī)的標(biāo)簽

1胆胰、屬性name
定義邏輯上的數(shù)據(jù)主機(jī)名稱

2狞贱、屬性maxCon/minCon
最大連接數(shù),max connections
最小連接數(shù)蜀涨,min connections

3瞎嬉、屬性dbType
數(shù)據(jù)庫類型:mysql數(shù)據(jù)庫

4、屬性dbDriver
數(shù)據(jù)庫驅(qū)動類型厚柳,native氧枣,使用mycat提供的本地驅(qū)動。

5.3 rule.xml
5.3.1 rule.xml內(nèi)容
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
        <tableRule name="rule1">
                <rule>
                        <columns>id</columns>
                        <algorithm>func1</algorithm>
                </rule>
        </tableRule>

        <tableRule name="rule2">
                <rule>
                        <columns>user_id</columns>
                        <algorithm>func1</algorithm>
                </rule>
        </tableRule>

        <tableRule name="sharding-by-intfile">
                <rule>
                        <columns>sharding_id</columns>
                        <algorithm>hash-int</algorithm>
                </rule>
        </tableRule>
        <tableRule name="auto-sharding-long">
                <rule>
                        <columns>id</columns>
                        <algorithm>rang-long</algorithm>
                </rule>
        </tableRule>
        <tableRule name="mod-long">
                <rule>
                        <columns>id</columns>
                        <algorithm>mod-long</algorithm>
                </rule>
        </tableRule>
        <tableRule name="sharding-by-murmur">
                <rule>
                        <columns>id</columns>
                        <algorithm>murmur</algorithm>
                </rule>
        </tableRule>
        <tableRule name="crc32slot">
         <rule>
                        <columns>id</columns>
                        <algorithm>crc32slot</algorithm>
                </rule>
        </tableRule>
        <tableRule name="sharding-by-month">
                <rule>
                        <columns>create_time</columns>
                        <algorithm>partbymonth</algorithm>
                </rule>
        </tableRule>
        <tableRule name="latest-month-calldate">
                <rule>
                        <columns>calldate</columns>
                        <algorithm>latestMonth</algorithm>
                </rule>
        </tableRule>

        <tableRule name="auto-sharding-rang-mod">
                <rule>
                        <columns>id</columns>
                        <algorithm>rang-mod</algorithm>
                </rule>
        </tableRule>

        <tableRule name="jch">
                <rule>
                        <columns>id</columns>
                        <algorithm>jump-consistent-hash</algorithm>
                </rule>
        </tableRule>

        <function name="murmur"
                class="io.mycat.route.function.PartitionByMurmurHash">
                <property name="seed">0</property><!-- 默認(rèn)是0 -->
                <property name="count">2</property><!-- 要分片的數(shù)據(jù)庫節(jié)點數(shù)量别垮,必須指定便监,否則沒法分片 -->
                <property name="virtualBucketTimes">160</property><!-- 一個實際的數(shù)據(jù)庫節(jié)點被映射為這么多虛擬節(jié)點,默認(rèn)是160倍碳想,也就是虛擬節(jié)點數(shù)是物理節(jié)點數(shù)的160倍 -->
                <!-- <property name="weightMapFile">weightMapFile</property> 節(jié)點的權(quán)重烧董,沒有指定權(quán)重的節(jié)點默認(rèn)是1。以properties文件的格式填寫胧奔,以從0開始到count-1的整數(shù)值也就是節(jié)點索引為key逊移,以節(jié)點權(quán)重值為值。所有權(quán)重值必須是正整數(shù)龙填,否則以1代替 -->
                <!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property>
                        用于測試時觀察各物理節(jié)點與虛擬節(jié)點的分布情況胳泉,如果指定了這個屬性,會把虛擬節(jié)點的murmur hash值與物理節(jié)點的映射按行輸出到這個文件岩遗,沒有默認(rèn)值扇商,如果不指定,就不會輸出任何東西 -->
        </function>

        <function name="crc32slot"
                          class="io.mycat.route.function.PartitionByCRC32PreSlot">
                <property name="count">2</property><!-- 要分片的數(shù)據(jù)庫節(jié)點數(shù)量宿礁,必須指定案铺,否則沒法分片 -->
        </function>
        <function name="hash-int"
                class="io.mycat.route.function.PartitionByFileMap">

         <function name="hash-int"
                class="io.mycat.route.function.PartitionByFileMap">
                <property name="mapFile">partition-hash-int.txt</property>
        </function>
        <function name="rang-long"
                class="io.mycat.route.function.AutoPartitionByLong">
                <property name="mapFile">autopartition-long.txt</property>
        </function>
        <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
                <!-- how many data nodes -->
                <property name="count">3</property>
        </function>

        <function name="func1" class="io.mycat.route.function.PartitionByLong">
                <property name="partitionCount">8</property>
                <property name="partitionLength">128</property>
        </function>
        <function name="latestMonth"
                class="io.mycat.route.function.LatestMonthPartion">
                <property name="splitOneDay">24</property>
        </function>
        <function name="partbymonth"
                class="io.mycat.route.function.PartitionByMonth">
                <property name="dateFormat">yyyy-MM-dd</property>
                <property name="sBeginDate">2015-01-01</property>
        </function>

        <function name="rang-mod" class="io.mycat.route.function.PartitionByRangeMod">
                <property name="mapFile">partition-range-mod.txt</property>
        </function>

        <function name="jump-consistent-hash" class="io.mycat.route.function.PartitionByJumpConsistentHash">
                <property name="totalBuckets">3</property>
        </function>
</mycat:rule>

rule.xml是用于定義分片規(guī)則的配置文件,Mycat默認(rèn)的分片規(guī)則是auto-sharding-long:以500萬為單位實現(xiàn)分片規(guī)則窘拯。邏輯庫A對應(yīng)dataNode-db1和db2红且,1 ~ 500萬保存在db1中坝茎,500萬零1 ~ 1000萬保存在db2中涤姊,1000萬零1 ~ 1500萬保存在db1中,以此類推嗤放。

六思喊、實現(xiàn)讀寫分離

6.1 配置讀寫分離
6.1.1 schema.xml配置
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

    <schema name="mysql_master_slave_db" checkSQLschema="false" sqlMaxLimit="100">
    
        <table name="t_user" dataNode="dn1" />
        
    </schema>

    <dataNode name="dn1" dataHost="localhost1" database="master_slave_test_db" />

    <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3"
              writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM1" url="47.115.26.11:3306" user="root" password="your password">
            <readHost host="hostS2" url="47.105.146.74:3306" user="root" password="your password" />
        </writeHost>
    
    </dataHost>
</mycat:schema>
6.1.2 balance
  • 0:不開啟讀寫分離機(jī)制,所有讀操作都發(fā)送到當(dāng)前可用的writeHost上次酌;
  • 1:全部的readHost與stand by writeHost參與select 語句的負(fù)載均衡恨课;
  • 2:所有讀操作都隨機(jī)的在writeHost舆乔、readHost上分發(fā);
  • 3:所有讀請求隨機(jī)的分發(fā)到writeHost對應(yīng)的readHost上執(zhí)行剂公,writeHost不負(fù)擔(dān)讀壓力希俩;
6.1.3 server.xml配置(部分)
<user name="root">
        <property name="password">123456</property>
        <property name="schemas">mysql_master_slave_db</property>
        
        <!-- 表級 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>

    <user name="user">
        <property name="password">user</property>
        <property name="schemas">mysql_master_slave_db</property>
        <property name="readOnly">true</property>
    </user>
6.2 Mycat命令
// 啟動
bin/mycat start

//停止
bin/mycat stop

//重啟
bin/mycat restart

//查看狀態(tài)
bin/mycat status

6.3 訪問Mycat方式

可以使用命令行訪問或客戶端軟件訪問,和連接MySQL一樣纲辽,Mycat的端口是8066,管理端口默認(rèn)為9066颜武。

1、用命令行訪問

mysql -uroot -p123456 -P9066 -h127.0.0.1
image.png

2拖吼、用客戶端軟件訪問

我用MySQL Workbench連接Mycat鳞上,一直提示密碼錯誤,后來換成用Navicat去連Mycat就連成功了吊档,估計是MySQL Workbench連接Mycat有問題篙议。

MySQL Workbench連接失敗

用Navicat連接Mycat成功


用Navicat連接Mycat成功

同時也用Navicat連接主庫(master)和從庫(slave)


Navicat連接主庫、從庫
6.4 查看Mycat日志

logs/wrapper.log日志中記錄的是所有Mycat操作怠硼,查看的時候主要看異常信息caused by信息

6.5 測試讀寫分離
6.5.1 操作mycat插入數(shù)據(jù)

我們連接mycat鬼贱,并在mysql_master_slave_db數(shù)據(jù)庫的t_user表中插入兩條數(shù)據(jù)

insert into t_user(id,name) values(1,'張三');
insert into t_user(id,name) values(2,'李四');

select * from t_user;
mycat插入數(shù)據(jù)
6.5.2 操作master、slave查看數(shù)據(jù)

master

master

slave


slave

我們可以看到拒名,master吩愧、slave庫中都已經(jīng)能查到剛才插入的兩條數(shù)據(jù)了。數(shù)據(jù)插入的時的邏輯大致是這樣的:操作mycat--->插入語句走的是master數(shù)據(jù)庫--->數(shù)據(jù)插入到master后增显,slave庫再同步該數(shù)據(jù)(同步是通過Binary log雁佳、Relay log實現(xiàn)的)。

6.5.3 驗證讀操作查詢的是slave庫

我們通過mycat執(zhí)行查詢操作同云,查到的數(shù)據(jù)是兩條糖权,那這兩條到底是從master中查詢到的,還是從slave庫中查詢到的呢炸站?我們可以這樣操作星澳,直接操作slave庫,將李四改成王五旱易,我們通過mycat再來查數(shù)據(jù)

修改slave數(shù)據(jù)
查看mycat數(shù)據(jù)

到此禁偎,我們的讀寫分離就實現(xiàn)好了。

七阀坏、Mycat分庫

7.1 分片規(guī)則
7.1.1 auto-sharding-long 范圍約定

以500萬為單位實現(xiàn)分片規(guī)則如暖。邏輯庫A對應(yīng)dataNode-db1和db2,1500萬保存在db1中,500萬零11000萬保存在db2中忌堂,1000萬零1~1500萬保存在db1中盒至,以此類推。

7.1.2 crc32slot規(guī)則

在CRUD操作時,根據(jù)具體數(shù)據(jù)的crc32算法計算枷遂,數(shù)據(jù)應(yīng)該保存在哪一個dataNode中

7.2 配置分片規(guī)則需要注意的地方

1樱衷、<columns> id </columns> 中推薦配置主鍵列

2、所有的tableRule只能使用一次酒唉,如果需要為多個表配置相同的分片規(guī)則矩桂,那么需要在此重新定義該規(guī)則。

3痪伦、在crc32slot算法中的分片數(shù)量(數(shù)據(jù)庫數(shù)量)一旦給定耍鬓,Mycat會將該分片數(shù)量和slor的取值范圍保存到文件中,在修改分片數(shù)量時是不會生效的流妻,需要將該文件刪除牲蜀,文件位置位于conf目錄中的ruledata目錄中。

7.3 配置分庫

需求:
1绅这、在master中創(chuàng)建3個數(shù)據(jù)庫涣达;
2、在Mycat中配置分庫

7.3.1 創(chuàng)建數(shù)據(jù)庫
create database demo1 default character set utf8;
create database demo2 default character set utf8;
create database demo3 default character set utf8;

slave也會自動同步創(chuàng)建好這三個庫

創(chuàng)建數(shù)據(jù)庫
7.3.2 創(chuàng)建t_user表

在master的三個庫中創(chuàng)建t_user表

create table `t_user`(
    `id` int(11) not null,
    `name` varchar(30) default null,
    primary key (`id`)
)engine = InnoDB default charset=utf8;
在master的三個庫中創(chuàng)建t_user表
7.3.3 修改配置文件

1证薇、schema.xml

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

    <schema name="mysql_master_slave_db" checkSQLschema="false" sqlMaxLimit="100">
    
        <table name="t_user" dataNode="dn1,dn2,dn3" rule="crc32slot"/>
        
    </schema>

    <dataNode name="dn1" dataHost="localhost1" database="demo1" />
    <dataNode name="dn2" dataHost="localhost1" database="demo2" />
    <dataNode name="dn3" dataHost="localhost1" database="demo3" />

    <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3"
              writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM1" url="47.115.26.11:3306" user="root" password="your password">
            <readHost host="hostS2" url="47.105.146.74:3306" user="root" password="your password" />
        </writeHost>
    
    </dataHost>
</mycat:schema>

2度苔、rule.xml
將crc32slot 分片數(shù)量改成3

    <function name="crc32slot"
              class="io.mycat.route.function.PartitionByCRC32PreSlot">
        <property name="count">3</property><!-- 要分片的數(shù)據(jù)庫節(jié)點數(shù)量,必須指定浑度,否則沒法分片 -->
    </function>

3寇窑、重啟Mycat

cd /data/mycat

bin/mycat restart

bin/mycat status
7.4 出現(xiàn)_slot列問題

我們現(xiàn)在操作mycat往t_user表里插入數(shù)據(jù)

insert into t_user(id,name) values(1,'admin');
image.png

執(zhí)行結(jié)果是插入失敗,提示Unknown column '_slot' in 'field list'箩张,這個錯誤的原因是甩骏,當(dāng)我們用分庫的方式去做數(shù)據(jù)存儲時,Mycat會在我們的數(shù)據(jù)表中自動添加_slot這一個列先慷,這一列記錄的就是通過crc32slot算法計算出來的值饮笛。我們剛才是直接操作master來創(chuàng)建的t_user表,這樣t_user表中就不會有_slot這一列论熙。

當(dāng)我們使用Mycat后福青,我們對所有表的創(chuàng)建應(yīng)該在Mycat中完成。正確的操作流程是:先在mycat中配置邏輯庫脓诡、邏輯表无午,然后在mycat中創(chuàng)建物理表,master庫中會自動創(chuàng)建物理表祝谚,slave會自動同步宪迟。

7.5 解決_slot列問題

1、現(xiàn)在我們操作master將三個數(shù)據(jù)庫里的t_user刪除(slave庫中的t_user表也會自動刪除)

2踊跟、我們操作mycat,執(zhí)行t_user建表語句

mycat建表

3踩验、我們再去查看master和slave,可以看到三個庫中都已經(jīng)有t_user表了,并且多了_slot列

master查看t_user表
7.6 插入數(shù)據(jù)商玫,實現(xiàn)數(shù)據(jù)分片

1箕憾、操作mycat 執(zhí)行插入SQL

insert into t_user(id,name) values(1,'admin');
操作mycat 執(zhí)行插入SQL

操作master,我們發(fā)現(xiàn)剛才這條數(shù)據(jù)插入到demo2這個庫中了

demo1
demo2
demo3

2拳昌、操作mycat 我們再插入一條數(shù)據(jù)

insert into t_user(id,name) values(2,'張三');

我們發(fā)現(xiàn)插入的還是demo2庫中袭异,但隨著ID值的變化,后面的數(shù)據(jù)會被分?jǐn)偟搅硗鈨蓚€庫中炬藤,到此御铃,分庫的功能我們就實現(xiàn)了。

7.7 注意事項

1沈矿、使用Mycat實現(xiàn)分庫時上真,先在Mycat中定義邏輯庫與邏輯表,然后在Mycat的鏈接中執(zhí)行創(chuàng)建表的命令必須要在Mycat中運行羹膳。因為Mycat在創(chuàng)建表時睡互,會在表中添加一個新的列,列名為_slot陵像。

2就珠、使用Mycat插入數(shù)據(jù)時,語句中必須要指定所有的列醒颖,即便是一個完全項插入也不能省略列名妻怎。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市泞歉,隨后出現(xiàn)的幾起案子逼侦,更是在濱河造成了極大的恐慌,老刑警劉巖腰耙,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件偿洁,死亡現(xiàn)場離奇詭異,居然都是意外死亡沟优,警方通過查閱死者的電腦和手機(jī)涕滋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挠阁,“玉大人宾肺,你說我怎么就攤上這事∏炙祝” “怎么了锨用?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長隘谣。 經(jīng)常有香客問我增拥,道長啄巧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任掌栅,我火速辦了婚禮秩仆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘猾封。我一直安慰自己澄耍,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布晌缘。 她就那樣靜靜地躺著齐莲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪磷箕。 梳的紋絲不亂的頭發(fā)上选酗,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機(jī)與錄音岳枷,去河邊找鬼星掰。 笑死,一個胖子當(dāng)著我的面吹牛嫩舟,可吹牛的內(nèi)容都是我干的氢烘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼家厌,長吁一口氣:“原來是場噩夢啊……” “哼播玖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起饭于,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蜀踏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后掰吕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體果覆,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年殖熟,在試婚紗的時候發(fā)現(xiàn)自己被綠了局待。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡菱属,死狀恐怖钳榨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情纽门,我是刑警寧澤薛耻,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站赏陵,受9級特大地震影響饼齿,放射性物質(zhì)發(fā)生泄漏饲漾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一缕溉、第九天 我趴在偏房一處隱蔽的房頂上張望考传。 院中可真熱鬧,春花似錦倒淫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至运翼,卻和暖如春返干,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背血淌。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工矩欠, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人悠夯。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓癌淮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親沦补。 傳聞我的和親對象是個殘疾皇子乳蓄,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355