schema.xml管理邏輯庫,分片表,分片借點和分片主機等信息
server.xml是系統參數的配置文件。
sequence是全局序列的配置文件
log4j.xml是mycat的日志輸出配置文件
mycat從1.5版本開始支持兩種配置方式:zookeeper和本地xml方式。默認以本地加載xml方式啟動。如果需要配置成zookeeper方式啟動,把zk.conf文件中的loadfromzk參數設置成true。
server.xml配置文件
1.user標簽
<user name="root">
<property name="password">123456</property>
<property name="schemas">TESTDB,db1,db2</property>
<property name="readOnly">true</property>
<property name="benchmark">11111</property>
<property name="usingDecrypt">1</property>
<!-- 表級 DML æ~]~Cé~Y~P設置 -->
<!--
<privileges check="false">
<schema name="TESTDB" dml="0110" >
<table name="tb01" dml="0000"></table>
<table name="tb02" dml="1111"></table>
</schema>
</privileges>
-->
</user>
該用戶只能訪問TESTDB,db1,db2。若要在schema.xml中定義TESTDB,則TESTDB必須現在server.xml中定義。
benchmark屬性,限制整體連接數量,設為0表示不限制連接數量
usingDecrypt屬性,開啟密碼加密功能。默認值為0,表示不開啟加密。
2.system標簽
charset屬性(沒在1.6release里找到),<system><property name="charset">utf8</property></system>
如果需要配置特殊字符幾如utf8mb4,則可以在index_to_charset.properties中配置,如224=utf8mb4
show variables like "coll%";
show variables like "chara%";
processors屬性,指定系統可用的線程數量,默認值為機器cpu核心x每個核心運行線程的數量,會影響processorBufferPool,processorBufferLocalPercent,processorExecutor屬性。NIOProcessor的個數也有processors屬性決定。
processorBufferChunk屬性,指定每次分配Socket Direct Buffer的默認值為4096個字節,也會影響BufferPool的長度,如果一次性獲取的字節過多而導致buffer不夠用,則會經常出現警告,可以適當調大processorBufferChunk值
processorBufferPool屬性,指定BufferPool的計算比例。由於每次執行NIO讀、寫操作都需要使用到buffer,系統初始化的時候會建立一定長度的buffer池來加快讀、寫的效率,減少建立buffer的時間。
Mycat中有兩個主要的buffer池:
- BufferPool
- ThreadLocalPool
BufferPool由ThreadLocalPool組合而成,每次從BufferPool中獲取buffer都會優先獲取ThreadLocalPool中的buffer,未命中之后才會去獲取BufferPool中的buffer。也就是說ThreadLocalPool是作為BufferPool的二級緩存,每個線程內部自己使用的。當然,這其中還有一些限制條件需要線程的名字是由$_開頭。然而,BufferPool上的buffer則是每個NIOProcessor都共享的。
默認這個屬性的值為: 默認bufferChunkSize(4096) * processors屬性 * 1000
假設系統線程數為4,其他都為屬性的默認值,則:
bufferPool = 4096 * 4 * 1000
BufferPool的總長度 : 4000 = 16384000 / 4096
6 processorBufferLocalPercent屬性
前面提到了ThreadLocalPool。這個屬性就是用來控制分配這個pool的大小用的,但其也並不是一個准確的值,也是一個比例值。這個屬性默認值為100。
線程緩存百分比 = bufferLocalPercent / processors屬性。
例如,系統可以同時運行4個線程,使用默認值,則根據公式每個線程的百分比為25。最后根據這個百分比來計算出具體的ThreadLocalPool的長度公式如下:
ThreadLocalPool的長度 = 線程緩存百分比 * BufferPool長度 / 100
假設BufferPool的長度為 4000,其他保持默認值。
那么最后每個線程建立上的ThreadLocalPool的長度為: 1000 = 25 * 4000 / 100
7 processorExecutor屬性
這個屬性主要用於指定NIOProcessor上共享的businessExecutor固定線程池大小。mycat在需要處理一些異步邏輯的時候會把任務提交到這個線程池中。新版本中這個連接池的使用頻率不是很大了,可以設置一個較小的值。
8 sequnceHandlerType屬性
指定使用Mycat全局序列的類型。0為本地文件方式,1為數據庫方式,2為時間戳序列方式,3為分布式ZK ID生成器,4為zk遞增id生成。
從1.6增加 兩種ZK的全局ID生成算法。
9 TCP連接相關屬性
- StandardSocketOptions.SO_RCVBUF
- StandardSocketOptions.SO_SNDBUF
- StandardSocketOptions.TCP_NODELAY
以上這三個屬性,分別由:
frontSocketSoRcvbuf 默認值: 1024 * 1024
frontSocketSoSndbuf 默認值: 4 * 1024 * 1024 frontSocketNoDelay 默認值: 1 backSocketSoRcvbuf 默認值: 4 * 1024 * 1024 backSocketSoSndbuf 默認值: 1024 * 1024 backSocketNoDelay 默認值: 1
各自設置前后端TCP連接參數。Mycat在每次建立前、后端連接的時候都會使用這些參數初始化連接。可以按系統要求適當的調整這些buffer的大小。TCP連接參數的定義,可以查看Javadoc。
10 Mysql連接相關屬性
初始化mysql前后端連接所涉及到的一些屬性:
packetHeaderSize : 指定Mysql協議中的報文頭長度。默認4。
maxPacketSize : 指定Mysql協議可以攜帶的數據最大長度。默認16M。
idleTimeout : 指定連接的空閑超時時間。某連接在發起空閑檢查下,發現距離上次使用超過了空閑時間,那么這個連接會被回收,就是被直接的關閉掉。默認30分鍾,單位毫秒。
charset : 連接的初始化字符集。默認為utf8。
txIsolation : 前端連接的初始化事務隔離級別,只在初始化的時候使用,后續會根據客戶端傳遞過來的屬性對后端數據庫連接進行同步。默認為REPEATED_READ,設置值為數字默認3。
READ_UNCOMMITTED = 1;
READ_COMMITTED = 2;
REPEATED_READ = 3;
SERIALIZABLE = 4;
sqlExecuteTimeout:SQL執行超時的時間,Mycat會檢查連接上最后一次執行SQL的時間,若超過這個時間則會直接關閉這連接。默認時間為300秒,單位秒。
11 心跳屬性
mycat中有幾個周期性的任務來異步的處理一些我需要的工作。這些屬性就在系統調優的過程中也是比不可少的。
processorCheckPeriod : 清理NIOProcessor上前后端空閑、超時和關閉連接的間隔時間。默認是1秒,單位毫秒。。
dataNodeIdleCheckPeriod : 對后端連接進行空閑、超時檢查的時間間隔,默認是300秒,單位毫秒。
dataNodeHeartbeatPeriod : 對后端所有讀、寫庫發起心跳的間隔時間,默認是10秒,單位毫秒。
12 服務相關屬性
這里介紹一個與服務相關的屬性,主要會影響外部系統對myact的感知。
bindIp : mycat服務監聽的IP地址,默認值為0.0.0.0。
serverPort : 定義mycat的使用端口,默認值為8066。
managerPort : 定義mycat的管理端口,默認值為9066。
13 fakeMySQLVersion
mycat模擬的mysql版本號,默認值為5.6版本,如非特需,不要修改這個值,目前支持設置5.5,5.6版本,其他版本可能會有問題。
此特性從1.6版本開始支持。
14 全局表一致性檢測
<property name="useGlobleTableCheck">0</property> <!-- 1為開啟全加班一致性檢測、0為關閉 -->
- 1
- 1
原理通過在全局表增加_MYCAT_OP_TIME字段來進行一致性檢測,類型為bigint,create語句通過mycat執行會自動加上這個字段,其他情況請自己手工添加。
此特性從1.6版本開始支持。
“增加mycat新任務,全局表定義中,需要有一個時間戳字段,每次記錄的update,insert,確保 時間字段賦值,並且mycat增加定時檢測邏輯,檢測記錄總量,以及最新時間戳的匹配,簡單有效的發現全局表不一致的問題。/ 測試修復類 / 1.5&2.0 /12.9 /leader-us”
全局表一致性定時檢測主要分為兩個部分:
- SQL攔截部分
主要實現對所有全局表中記錄進行修改的語句進行攔截,比如:
ServerParse.INSERT, ServerParse.UPDATE, ServerParse.REPLACE(mycat-server不支持)
對所有對全局表的 insert, update操作進行攔截,首先判斷該全局表是否存在一個記錄時間戳的內部列_mycat_op_time:
public class GlobalTableUtil{ /** 全局表 保存修改時間戳的字段名,用於全局表一致性檢查 */ public static final String GLOBAL_TABLE_MYCAT_COLUMN = "_mycat_op_time"; 如果不存在,輸出警告,哪個db的哪個全局表沒有內部列: if(innerColumnNotExist.size() > 0){ for(SQLQueryResult<Map<String, String>> map : innerColumnNotExist){ if(tableName.equalsIgnoreCase(map.getTableName())){ StringBuilder warnStr = new StringBuilder(); if(map != null) warnStr.append(map.getDataNode()).append("."); warnStr.append(tableName).append(" inner column: ") .append(GlobalTableUtil.GLOBAL_TABLE_MYCAT_COLUMN) .append(" is not exist."); LOGGER.warn(warnStr.toString()); return sql; } } }
然后返回原始sql. 不需要進行攔截。
如果存在一個記錄時間戳的內部列,那么對該 insert或者update語句進行SQL攔截修改:
if(sqlType == ServerParse.INSERT){ sql = convertInsertSQL(sql, tableName); } if(sqlType == ServerParse.UPDATE){ sql = convertUpdateSQL(sql, tableName); }
1.1 insert語句的攔截邏輯
對所有對全局表進行insert的sql語句,進行改寫,比如下面的user是全局表:
insert into user(id,name) valueS(1111,'dig'), (1111, 'dig'), 90 (1111,'dig') , (1111,'dig'); 會被改寫成: insert into user(id,name, _mycat_op_time) valueS(1111,'dig', 1450423751170), (1111, 'dig', 1450423751170), (1111,'dig', 1450423751170) , (1111,'dig', 1450423751170);
其中_mycat_op_time 是內部列的名稱:
public static final String GLOBAL_TABLE_MYCAT_COLUMN = "_mycat_op_time";
- 1
- 1
而1450423751170 是在插入時在 mycat-server上生成的一個時間戳對應的long整數(對應到數據庫是bigint)。然后該語句發送給所有db在其全局表中進行插入。
如果insert語句自帶了內部列_mycat_op_time,比如:
insert into user(id,name, _mycat_op_time) valueS(1111,'dig',13545);
- 1
- 2
- 1
- 2
那么會輸出警告,並且也進行攔截改寫成如下形式:
insert into user(id,name, _mycat_op_time) valueS(1111,'dig', 1450423751170);
- 1
- 2
- 1
- 2
然后發送給所有db在其全局表中進行插入。
對mycat-server不支持的sql語句,本攔截器,不進行任何操作,直接返回原始sql。如果在攔截過程中發生任何異常,也返回原始sql語句,不進行任何修改操作。保證該攔截不會影響系統原有的健壯性。
1.2 update語句的攔截邏輯
Update語句的攔截邏輯和insert語句原理是相似的。也是判斷是否有內部列。
如果沒有輸出警告信息,如果有則進行攔截。
對全局表 user 的如下update:
update user set name='dddd',pwd='aaa' where id=2
- 1
- 2
- 1
- 2
會被改寫成:
update user set name='dddd',pwd='aaa', _mycat_op_time=1450423751170 where id=2
- 1
- 2
- 1
- 2
如果原始sql帶有_mycat_op_time 那么進行警告,然后替換它的值,比如:
update user set name='dddd',pwd='aaa', _mycat_op_time=1111 where id=2;
- 1
- 2
- 1
- 2
會被改寫成:
update user set name='dddd',pwd='aaa', _mycat_op_time=1450423751170 where id=2;
- 1
- 2
- 1
- 2
然后將語句發送給所有的全局表進行執行。
這樣的話,如果有哪個表上的insert,update執行失敗,那么內部列_mycat_op_time 的最大值,以及全局表的記錄總數就會不一致。Delete語句也一樣,只是無需攔截。下面的檢查機制就是根據這個原理來操作的。
- 一致性的定時檢測
在MycatServer的startup中引入一個定時檢查任務:
timer.schedule(glableTableConsistencyCheck(), 0L, 1000 * 1000L); // 全局表一致性檢查任務 private TimerTask glableTableConsistencyCheck() { return new TimerTask() { @Override public void run() { timerExecutor.execute(new Runnable() { @Override public void run() { GlobalTableUtil.consistencyCheck(); } }); } };
其實現在GlobalTableUtil 類中:
該類首先獲得所有的全局表:
static { getGlobalTable(); // 初始化 globalTableMap }
其實現,參見代碼。
GlobalTableUtil.consistencyCheck() 的實現,主要思路是,首先根據所有的全局表,找到對應的PhysicalDBNode,然后找到對應的PhysicalDatasource,然后對PhysicalDatasource中的所有db進行三項檢測:
2.1 檢測全局表的內部列是否存在
checker.checkInnerColumnExist();
檢測的實現是通過一個SQLJob來異步操作的,對應的SQL語句為:
select count(*) as inner_col_exist from information_schema.columns where column_name=' _mycat_op_time' and table_name='user' and table_schema='db1';
- 1
- 1
如果返回的inner_col_exist 大於0,那么就表示存在內部列,如果等於0,那么就表示不存在內部列。
如果PhysicalDatasource上某個db的全局表沒有內部列,那么將這些db記錄在一個list中,然后在 SQL 攔截過程中進行判斷,如果是全局表,但是沒有內部列,那么就輸出警告,不對SQL進行攔截改寫,因為該全局表沒有內部列,無需改寫SQL。在第一項檢測完成之后,才能進行第二項檢測。
2.2 檢測全局表的記錄總數
checker.checkRecordCout();
檢查過程是類似的,都是通過SQLjob來完成的,只是對應的語句不一樣:
select count(*) as record_count from user; (假設user表為全局表)
2.3 檢測全局表的時間戳的最大值
checker.checkMaxTimeStamp();
檢查過程是類似的,都是通過SQLjob來完成的,只是對應的語句不一樣:
select max(_mycat_op_time) as max_timestamp from user (假設user表為全局表) 三項檢查完成之后,就獲得了如下所示的結果: 全局表的記錄總數(user表為全局表,並且系統有三個db): db1. user.record_count: 43546565 db2. user.record_count: 43546565 db3. user.record_count: 43546565 全局表的最大時間戳: 93 db1. user.max_timestamp: 1450578802241 db2. user.max_timestamp: 1450578802241 db3. user.max_timestamp: 1450578802241
然后前端,比如 mycat-eye 就可以將該結果顯示出來。目前直接在log中輸出,也可以考慮引入像H2這樣的Java實現的嵌入式數據庫來記錄該結果。H2實現為僅僅一個jar包,十分適合作為mycat-server層面的一個非文件存儲方式。有一些信息如果存在在文件中,查詢起來不太方便,比如上面的檢測結果就是如此。
實際的SQLJob的執行,主要參照了原有的heartbeat的實現,主要在下面兩個類中:
MySQLConsistencyChecker
MySQLConsistencyHelper
具體可以參考代碼,和heartbeat的實現基本是一樣的。
每一次定時檢查,會對所有全局表進行上述三項檢測。
總結成一句:
SQL的攔截實現記錄全局表被修改時的時間戳;定時任務實現對全局表記錄總數和時間戳最大值的獲取。
- 如何使用全局表一致性檢測
1> 在所有全局表中增加一個 bigint 的內部列,列名為
_mycat_op_time,(alter table t add column _mycat_op_time bigint [not null default 0]); 同時建議在該列上建立索引(alter table t add index _op_idx(_mycat_op_time))
- 1
- 1
2> 在對全局表進行crud時,最好將內部列當作不存在一樣,也就是最好不要對內部列update,insert等操作,不然會在Log中進行警告:不用操作內部列;
3> 因為全局表多了一個內部列,所以在對全局表進行insert時,必須攜帶列名,也就是insert into t(id,name) values(xx,xx),不能使用insert into t values(xx,xx); 因為會報錯:列數不對。這是唯一的一個小問題。未來可能會fix掉。
15 分布式事務開關
<!--分布式事務開關,0為不過濾分布式事務,1為過濾分布式事務(如果分布式事務內只涉及全局表,則不過濾),2為不過濾分布式事務,但是記錄分布式事務日志--> <property name="handleDistributedTransactions">0</property>
- 1
- 1
主要應用場景,主要為了控制是否允許跨庫事務。
此特性從1.6版本開始支持。
16 Off Heap for Mycat
此特性從1.6版本開始支持。 1
1.使用非堆內存(Direct Memory)處理跨分片結果集的Merge/order by/group by/limit。
2.通過server.xml中的useOffHeapForMerge參數配置是否啟用非堆內存處理跨分片結果集
3.Mycat內存分層管理:
a.結果集處理內存
b.系統預留內存
c.網絡處理內存共三塊,
其中網絡處理內存部分全部為Direct Memory,結果集內存分為Direct Memory 和 HeapMemory.
但目前僅使用Direct Memory。系統預留內存為 On Heap Memory。JVM參數,必須設置-XX:MaxDirectMemorySize和 -Xmx
例如:-Xmx1024m -Xmn512m -XX:MaxDirectMemorySize=2048m -Xss256K -XX:+UseParallelGC
上述分層可以避免OOM問題,以及減少Full GC回收時間,提高mycat響應速度。
4.使用TimeSort 和RadixSort,跨分片結果集合並排序使用PriorityQueue,其中經測試RadixSort適合LONG,INT,SHORT,Float,Double,String數據類型排序,性能優越
5.Java obj連續內存存取,二進制序列化和反序列化,使用緩存友好的數據結構Map和Row
6.支持內存和外存並存的排序方式,結果集排序可以達上億規模。此時應注意:
- a.此時前端和后端空閑連接超時檢測時間應該設置大些,避免空閑檢測關閉front或者backend
connection,造成Mysqlclient連接丟失時結果集無法正確。 - b.設置-Xmn值盡可能大些,新生代使用UseParallelGC垃圾回收器,-Xss設置512K比較合適,物理內存足夠時,MaxDirectMemorySize盡可能設置大些,可以加快結果集處理時間,
例如:
-Xmx1024m -Xmn512m -XX:MaxDirectMemorySize=2048m -Xss256k -XX:+UseParallelGC
schema.xml,涵蓋了mycat的邏輯庫,表,分片規則,分片節點和數據源。
1.schema標簽:<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100"></schema>
schema 標簽用於定義MyCat實例中的邏輯庫,MyCat可以有多個邏輯庫,每個邏輯庫都有自己的相關配置。可以使用 schema 標簽來划分這些不同的邏輯庫。
如果不配置 schema 標簽,所有的表配置,會屬於同一個默認的邏輯庫。
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100"> <table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" ></table> </schema> <schema name="USERDB" checkSQLschema="false" sqlMaxLimit="100"> <table name="company" dataNode="dn10,dn11,dn12" rule="auto-sharding-long" ></table> </schema>
如上所示的配置就配置了兩個不同的邏輯庫,邏輯庫的概念和MySQL數據庫中Database的概念相同,我們在查詢這兩個不同的邏輯庫中表的時候需要切換到該邏輯庫下才可以查詢到所需要的表。
如果你發現顯示該錯誤信息,需要到server.xml添加該用戶可以訪問到的schema就可以了。具體的內容待后續章節闡述。
schema標簽的相關屬性:
屬性名—值—數量限制
dataNode—任意String—(0..1)
checkSQLschema—Boolean—(1)
sqlMaxLimit—Integer—(1)
1 dataNode
該屬性用於綁定邏輯庫到某個具體的database上,1.3版本如果配置了dataNode,則不可以配置分片表,1.4可以配置默認分片,只需要配置需要分片的表即可,具體如下配置:
1.3配置:
<schema name="USERDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"> <!—里面不能配置任何表--> </schema>
- 1
- 1
1.4配置:
<schema name="USERDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn2"> <!—配置需要分片的表--> <table name=“tuser” dataNode=”dn1”/> </schema>
- 1
- 1
那么現在tuser就綁定到dn1所配置的具體database上,可以直接訪問這個database,沒有配置的表則會走默認節點dn2,這里注意沒有配置在分片里面的表工具查看無法顯示,但是可以正常使用。
2 checkSQLschema
當該值設置為 true 時,如果我們執行語句
select * from TESTDB.travelrecord;
則MyCat會把語句修改為
select * from travelrecord;
即把表示schema的字符去掉,避免發送到后端數據庫執行時報
(ERROR 1146 (42S02): Table ‘testdb.travelrecord’ doesn’t exist)。
不過,即使設置該值為 true ,如果語句所帶的是並非是schema指定的名字,例如:
select * from db1.travelrecord;
那么MyCat並不會刪除db1這個字段,如果沒有定義該庫的話則會報錯,所以在提供SQL語句的最好是不帶這個字段。
3 sqlMaxLimit
當該值設置為某個數值時。每條執行的SQL語句,如果沒有加上limit語句,MyCat也會自動的加上所對應的值。例如設置值為100,執行
select * from TESTDB.travelrecord;
的效果為和執行
select * from TESTDB.travelrecord limit 100;相同。
設置該值的話,MyCat默認會把查詢到的信息全部都展示出來,造成過多的輸出。所以,在正常使用中,還是建議加上一個值,用於減少過多的數據返回。
當然SQL語句中也顯式的指定limit的大小,不受該屬性的約束。
需要注意的是,如果運行的schema為非拆分庫的,那么該屬性不會生效。需要手動添加limit語句。
table標簽
<table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" ></table>
- 1
- 1
Table 標簽定義了MyCat中的邏輯表,所有需要拆分的表都需要在這個標簽中定義。
table標簽的相關屬性:
屬性名—值—數量限制
name—String—(1)
dataNode—String—(1..*)
rule—String—(0..1)
ruleRequired—boolean—(0..1)
primaryKey—String—(1)
type—String—(0..1)
autoIncrement—boolean—(0..1)
subTables—String—(1)
needAddLimit—boolean—(0..1)
1 name屬性
定義邏輯表的表名,這個名字就如同我在數據庫中執行create table命令指定的名字一樣,同個schema標簽中定義的名字必須唯一。
2 dataNode屬性
定義這個邏輯表所屬的dataNode, 該屬性的值需要和dataNode標簽中name屬性的值相互對應。如果需要定義的dn過多可以使用如下的方法減少配置:
<table name="travelrecord" dataNode="multipleDn$0-99,multipleDn2$100-199" rule="auto-sharding-long" ></table> <dataNode name="multipleDn" dataHost="localhost1" database="db$0-99" ></dataNode> <dataNode name="multipleDn2" dataHost="localhost1" database=" db$0-99" ></dataNode>
這里需要注意的是database屬性所指定的真實database name需要在后面添加一個,例如上面的例子中,我需要在真實的mysql上建立名稱為dbs0到dbs99的database。
3 rule屬性
該屬性用於指定邏輯表要使用的規則名字,規則名字在rule.xml中定義,必須與tableRule標簽中name屬性屬性值一一對應。
4 ruleRequired屬性
該屬性用於指定表是否綁定分片規則,如果配置為true,但沒有配置具體rule的話 ,程序會報錯。
5 primaryKey屬性
該邏輯表對應真實表的主鍵,例如:分片的規則是使用非主鍵進行分片的,那么在使用主鍵查詢的時候,就會發送查詢語句到所有配置的DN上,如果使用該屬性配置真實表的主鍵。難么MyCat會緩存主鍵與具體DN的信息,那么再次使用非主鍵進行查詢的時候就不會進行廣播式的查詢,就會直接發送語句給具體的DN,但是盡管配置該屬性,如果緩存並沒有命中的話,還是會發送語句給具體的DN,來獲得數據。
6 type屬性
該屬性定義了邏輯表的類型,目前邏輯表只有“全局表”和”普通表”兩種類型。對應的配置:
- 全局表:global
- 普通表:不指定該值為globla的所有表
7 autoIncrement屬性
mysql對非自增長主鍵,使用last_insert_id()是不會返回結果的,只會返回0。所以,只有定義了自增長主鍵的表才可以用last_insert_id()返回主鍵值。
mycat目前提供了自增長主鍵功能,但是如果對應的mysql節點上數據表,沒有定義auto_increment,那么在mycat層調用last_insert_id()也是不會返回結果的。
由於insert操作的時候沒有帶入分片鍵,mycat會先取下這個表對應的全局序列,然后賦值給分片鍵。這樣才能正常的插入到數據庫中,最后使用last_insert_id()才會返回插入的分片鍵值。
如果要使用這個功能最好配合使用數據庫模式的全局序列。
使用autoIncrement=“true” 指定這個表有使用自增長主鍵,這樣mycat才會不拋出分片鍵找不到的異常。
使用autoIncrement=“false” 來禁用這個功能,當然你也可以直接刪除掉這個屬性。默認就是禁用的。
8 subTables
使用方式添加subTables=”t_order$1-2,t_order3”
目前分表1.6以后開始支持 並且dataNode在分表條件下只能配置一個,分表條件下不支持各種條件的join語句。
9 needAddLimit屬性
指定表是否需要自動的在每個語句后面加上limit限制。由於使用了分庫分表,數據量有時會特別巨大。這時候執行查詢語句,如果恰巧又忘記了加上數量限制的話。那么查詢所有的數據出來,也夠等上一小會兒的。
所以,mycat就自動的為我們加上LIMIT 100。當然,如果語句中有limit,就不會在次添加了。
這個屬性默認為true,你也可以設置成false`禁用掉默認行為。
childTable標簽
childTable標簽用於定義E-R分片的子表。通過標簽上的屬性與父表進行關聯。
childTable標簽的相關屬性:
屬性名—值—數量限制
name—String—(1)
joinKey—String—(1)
parentKey—String—(1)
primaryKey—String—(0..1)
needAddLimit—boolean—(0..1)
1 name屬性
定義子表的表名。
2 joinKey屬性
插入子表的時候會使用這個列的值查找父表存儲的數據節點。
3 parentKey屬性
屬性指定的值一般為與父表建立關聯關系的列名。程序首先獲取joinkey的值,再通過parentKey屬性指定的列名產生查詢語句,通過執行該語句得到父表存儲在哪個分片上。從而確定子表存儲的位置。
4 primaryKey屬性
同table標簽所描述的。
5 needAddLimit屬性
同table標簽所描述的。
dataNode標簽
<dataNode name="dn1" dataHost="lch3307" database="db1" ></dataNode>
- 1
- 1
dataNode 標簽定義了MyCat中的數據節點,也就是我們通常說所的數據分片。一個dataNode標簽就是一個獨立的數據分片。
例子中所表述的意思為:使用名字為lch3307數據庫實例上的db1物理數據庫,這就組成一個數據分片,最后,我們使用名字dn1標識這個分片。
dataNode標簽的相關屬性:
屬性名—值—數量限制
name—String—(1)
dataHost—String—(1)
database—String—(1)
1 name屬性
定義數據節點的名字,這個名字需要是唯一的,我們需要在table標簽上應用這個名字,來建立表與分片對應的關系。
2 dataHost屬性
該屬性用於定義該分片屬於哪個數據庫實例的,屬性值是引用dataHost標簽上定義的name屬性。
3 database屬性
該屬性用於定義該分片屬性哪個具體數據庫實例上的具體庫,因為這里使用兩個緯度來定義分片,就是:實例+具體的庫。因為每個庫上建立的表和表結構是一樣的。所以這樣做就可以輕松的對表進行水平拆分。
dataHost標簽
作為Schema.xml中最后的一個標簽,該標簽在mycat邏輯庫中也是作為最底層的標簽存在,直接定義了具體的數據庫實例、讀寫分離配置和心跳語句。現在我們就解析下這個標簽。
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native"> <heartbeat>select user()</heartbeat> <!-- can have multi write hosts --> <writeHost host="hostM1" url="localhost:3306" user="root" password="123456"> <!-- can have multi read hosts --> <!-- <readHost host="hostS1" url="localhost:3306" user="root" password="123456" /> --> </writeHost> <!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> --> </dataHost>
dataHost標簽的相關屬性:
屬性名—值—數量限制
name—String—(1)
maxCon—Integer—(1)
minCon—Integer—(1)
balance—Integer—(1)
writeType—Integer—(1)
dbType—String—(1)
dbDriver—String—(1)
1 name屬性
唯一標識dataHost標簽,供上層的標簽使用。
2 maxCon屬性
指定每個讀寫實例連接池的最大連接。也就是說,標簽內嵌套的writeHost、readHost標簽都會使用這個屬性的值來實例化出連接池的最大連接數。
3 minCon屬性
指定每個讀寫實例連接池的最小連接,初始化連接池的大小。
4 balance屬性
負載均衡類型,目前的取值有3種:
- balance=”0”, 不開啟讀寫分離機制,所有讀操作都發送到當前可用的writeHost上。
- balance=”1”,全部的readHost與stand by writeHost參與select語句的負載均衡,簡單的說,當雙主雙從模式(M1->S1,M2->S2,並且M1與 M2互為主備),正常情況下,M2,S1,S2都參與select語句的負載均衡。
- balance=”2”,所有讀操作都隨機的在writeHost、readhost上分發。
- balance=”3”,所有讀請求隨機的分發到wiriterHost對應的readhost執行,writerHost不負擔讀壓力,注意balance=3只在1.4及其以后版本有,1.3沒有。
5 writeType屬性
負載均衡類型,目前的取值有3種:
- writeType=”0”,所有寫操作發送到配置的第一個writeHost,第一個掛了切到還生存的第二個writeHost,重新啟動后已切換后的為准,切換記錄在配置文件中:dnindex.properties
- writeType=”1”,所有寫操作都隨機的發送到配置的writeHost,1.5以后廢棄不推薦。switchType屬性
-1 表示不自動切換
1 默認值,自動切換
2 基於MySQL主從同步的狀態決定是否切換
6 dbType屬性
指定后端連接的數據庫類型,目前支持二進制的mysql協議,還有其他使用JDBC連接的數據庫。例如:mongodb、oracle、Spark等。
7 dbDriver屬性
指定連接后端數據庫使用的Driver,目前可選的值有native和JDBC。使用native的話,因為這個值執行的是二進制的mysql協議,所以可以使用mysql和maridb。其他類型的數據庫則需要使用JDBC驅動來支持。
從1.6版本開始支持postgresql的native原始協議。
如果使用JDBC的話需要將符合JDBC 4標准的驅動JAR包放到MYCAT\lib目錄下,並檢查驅動JAR包中包括如下目錄結構的文件:META-INF\services\Java.sql.Driver。在這個文件內寫上具體的Driver類名,例如:com.mysql.jdbc.Driver。
8 switchType屬性
-1 表示不自動切換
1 默認值,自動切換
2 基於MySQL主從同步的狀態決定是否切換
心跳語句為 show slave status
3 基於MySQL galary cluster的切換機制(適合集群)(1.4.1)
心跳語句為 show status like ‘wsrep%’.
9 tempReadHostAvailable屬性
如果配置了這個屬性writeHost 下面的readHost仍舊可用,默認0 可配置(0、1)。
heartbeat標簽
這個標簽內指明用於和后端數據庫進行心跳檢查的語句。例如,MYSQL可以使用select user(),Oracle可以使用select 1 from dual等。
這個標簽還有一個connectionInitSql屬性,主要是當使用Oracla數據庫時,需要執行的初始化SQL語句就這個放到這里面來。例如:alter session set nls_date_format=’yyyy-mm-dd hh24:mi:ss’
1.4主從切換的語句必須是:show slave status
1 writeHost標簽、readHost標簽
這兩個標簽都指定后端數據庫的相關配置給mycat,用於實例化后端連接池。唯一不同的是,writeHost指定寫實例、readHost指定讀實例,組着這些讀寫實例來滿足系統的要求。
在一個dataHost內可以定義多個writeHost和readHost。但是,如果writeHost指定的后端數據庫宕機,那么這個writeHost綁定的所有readHost都將不可用。另一方面,由於這個writeHost宕機系統會自動的檢測到,並切換到備用的writeHost上去。
這兩個標簽的屬性相同,這里就一起介紹。
屬性名—值—數量限制
host—String—(1)
url—String–(1)
password—String—(1)
user—String—(1)
weight—String—(1)
usingDecrypt—String—(1)
2 host屬性
用於標識不同實例,一般writeHost我們使用*M1,readHost我們用*S1。
3 url屬性
后端實例連接地址,如果是使用native的dbDriver,則一般為address:port這種形式。用JDBC或其他的dbDriver,則需要特殊指定。當使用JDBC時則可以這么寫:jdbc:mysql://localhost:3306/。
4 user屬性
后端存儲實例需要的用戶名字
5 password屬性
后端存儲實例需要的密碼
6 weight 屬性
權重 配置在readhost 中作為讀節點的權重(1.4以后)
7 usingDecrypt 屬性
是否對密碼加密默認0 否 如需要開啟配置1,同時使用加密程序對密碼加密,加密命令為:
執行mycat jar 程序(1.4.1以后):
java -cp Mycat-server-1.4.1-dev.jar org.opencloudb.util.DecryptUtil 1:host:user:password
1:host:user:password 中 1 為db端加密標志,host為dataHost 的host 名稱
10 rule.xml
rule.xml里面就定義了我們對表進行拆分所涉及到的規則定義。我們可以靈活的對表使用不同的分片算法,或者對表使用相同的算法但具體的參數不同。這個文件里面主要有tableRule和function這兩個標簽。在具體使用過程中可以按照需求添加tableRule和function。
11 tableRule標簽
這個標簽定義表規則。
定義的表規則,在schema.xml:
<tableRule name="rule1"> <rule> <columns>id</columns> <algorithm>func1</algorithm> </rule> </tableRule>
- 1
- 1
name 屬性指定唯一的名字,用於標識不同的表規則。
內嵌的rule標簽則指定對物理表中的哪一列進行拆分和使用什么路由算法。
columns 內指定要拆分的列名字。
algorithm 使用function標簽中的name屬性。連接表規則和具體路由算法。當然,多個表規則可以連接到同一個路由算法上。table標簽內使用。讓邏輯表使用這個規則進行分片。
12 function標簽
<function name="hash-int" class="org.opencloudb.route.function.PartitionByFileMap"> <property name="mapFile">partition-hash-int.txt</property> </function>
- 1
- 1
name 指定算法的名字。
class 制定路由算法具體的類名字。
property 為具體算法需要用到的一些屬性。
路由算法的配置可以查看算法章節。