Mycat問題總結


Mycat問題總結

一丶自增主鍵設置

Mycat提供了幾種設置自增主鍵的方式

  • 本地文件方式
  • 數據庫方式
  • 服務器時間戳方式
  • 分布式ZK-ID生成器
    第一種和第二種只適合單點設置,對於集群不適用。第四種方式適用,但是需要增加zk服務器,維護成本較高,或者由於某些原因不能用zk,此方式也會受到約束,故采用服務器時間戳的方式生成自增主鍵ID。
    以下為配置方法
    1. 修改server.xml,設置為時間戳格式
    <property name="sequnceHandlerType">2</property>
    
    1. 修改sepuence_time_conf.properties,設置組合形式
    WORKID=0-31 任意整數
    DATAACENTERID=0-31 任意整數
    
    1. 修改schema.xml,設置主鍵ID為自增
    <table name="sam_test" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3" rule="sharding-by-pattern" />
    

二丶按日期(天)分片

  1. 在查詢時,應該具體到某一天去查詢
```
例如:SELECT * FROM table WHERE create_time = '2019-01-01';
```
這樣查詢數據只會去查某一個節點


2. 如果需要查詢時間段,應該用between...and,不能用>=或者<=,區別如下

 ```
 SELECT * from alan_test WHERE create_date = '2019-01-01';
 ```

SELECT * FROM table WHERE create_time between '2019-01-01' and '2019-01-12';


按天分片,需要創建結束時間,到結束時間之后的數據會循環計算,具體存到哪個分片。

三丶固定分片Hash算法和取模分片的區別

  • 固定分片Hash算法類似於十進制的求模運算,區別在於是二進制的操作,是取id的二進制低10位,即id二進制&1111111111。
    此算法的優點在於如果按照 10 進制取模運算,在連續插入 1-10 時候 1-10會被分到1-10個分片,增大了插入的事務控制難度,而此算法根據二進制則可能會分到連續的分片,減少插入事務事務控制難度。但是該方法插入時計算量大,效率較低。
  • 取模運算這種配置非常明確即根據 id進行十進制求模預算,相比固定分片hash。
    此種在批量插入時可能存在批量插入單事務插入多數據分片,增大事務一致性難度,效率高。

四丶修改配置文件注意

注意:修改server.xml等配置文件時,一定要注意編碼格式。如果增加注釋或者增加中文注釋,一定要確保編碼格式和之前的編碼一樣,一般都為UTF-8,否則會出現以下異常

WrapperSimpleApp: Encountered an error running main: java.lang.ExceptionInInitializerError
INFO   | jvm 1    | 2019/01/17 08:26:35 | java.lang.ExceptionInInitializerError
INFO   | jvm 1    | 2019/01/17 08:26:35 | 	at io.mycat.MycatStartup.main(MycatStartup.java:53)
INFO   | jvm 1    | 2019/01/17 08:26:35 | 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
INFO   | jvm 1    | 2019/01/17 08:26:35 | 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
INFO   | jvm 1    | 2019/01/17 08:26:35 | 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
INFO   | jvm 1    | 2019/01/17 08:26:35 | 	at java.lang.reflect.Method.invoke(Method.java:606)
INFO   | jvm 1    | 2019/01/17 08:26:35 | 	at org.tanukisoftware.wrapper.WrapperSimpleApp.run(WrapperSimpleApp.java:240)
INFO   | jvm 1    | 2019/01/17 08:26:35 | 	at java.lang.Thread.run(Thread.java:744)
INFO   | jvm 1    | 2019/01/17 08:26:35 | Caused by: io.mycat.config.util.ConfigException: com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 1 of 1-byte UTF-8 sequence.

五丶應用指定某個分片

此規則是在運行階段,由應用自主決定數據存到哪個分片上面,此方法為直接根據字符子串(必須是數字)計算分區號。配置規則如下,修改rule.xml

<tableRule name="sharding-by-substring">
	<rule>
		<columns>user_id</columns>
		<algorithm>sharding-by-substring</algorithm>
	</rule>
</tableRule>
<function name="sharding-by-substring" class="io.mycat.route.function.PartitionDirectBySubString">
	<property name="startIndex">0</property><!-- zero-based -->
	<property name="size">2</property>127
	<property name="partitionCount">8</property>
	<property name="defaultPartition">0</property>
</function>

配置說明:
上面 columns 標識將要分片的表字段,algorithm 分片函數
此方法為直接根據字符子串(必須是數字)計算分區號(由應用傳遞參數,顯式指定分區號)。
例如 id=05-100000002
在此配置中代表根據 id 中從 startIndex=0,開始,截取 siz=2 位數字即 05,05 就是獲取的分區,如果沒傳默認分配到 defaultPartition
注意:由於字符子串必須為數字,所以在存入該字段值且該字段為int或者long類型時,首字符不能為0,在配置截取規則時,也不能配置從0開始。

六丶使用EXPLAIN查看路由結果

Mycat提供的EXPLAIN語句並不是用來查看執行計划的,而是用來查看路由結果的,如果要查詢真正的執行計划,拿到路由結果里面的sql語句,到具體的實例上面查看就行了。例如下面的語句,就被路由到了3個庫

explain SELECT * from alan_test WHERE create_date > '2019-01-01 10:00:00' and create_date < '2019-01-12 18:00:00';

EXPLAIN不支持查看insert語句並且使用Mycat生成id的sql語句。這個很好理解,因為無法路由。如果使用會報如下異常

insert sql using mycat seq,you must provide primaryKey value for explain

七丶根據按日期(天)分片,在mycat中執行以下sql報錯

INSERT INTO item(value,indate) VALUES(1,NOW());

錯誤信息如下:

[Err] 1064 - columnValue:'2019-01-17 09:40:01' Please check if the format satisfied.

將NOW()改為字符串可執行成功

八丶使用程序insert數據(以下過程是通過程序執行)

  1. 執行以下sql可以保存成功

    insert into item (indate, value) values (?, ?)	
    
  2. 執行查詢語句

    select item0_.id as id1_0_, item0_.indate as indate2_0_, item0_.value as value3_0_ from item item0_
    
  3. 再次執行第一步sql保存失敗,錯誤信息如下:

    Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
    	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957) ~[mysql-connector-java-5.1.38.jar:5.1.38]
    	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:896) ~[mysql-connector-java-5.1.38.jar:5.1.38]
    	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:885) ~[mysql-connector-java-5.1.38.jar:5.1.38]
    	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860) ~[mysql-connector-java-5.1.38.jar:5.1.38]
    	at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2040) ~[mysql-connector-java-5.1.38.jar:5.1.38]
    	at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2009) ~[mysql-connector-java-5.1.38.jar:5.1.38]
    	at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5094) ~[mysql-connector-java-5.1.38.jar:5.1.38]
    	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1994) ~[mysql-connector-java-5.1.38.jar:5.1.38]
    	at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:204) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    	... 117 common frames omitted
    

9.一致性Hash分片

一致性 hash 預算有效解決了分布式數據的擴容問題。

10.按單月小時拆分

分片字段必須為字符串格式,否則分片不成功,默認存到第一個分片里面;
保存的時間格式必須為‘yyyymmddHH’格式,不能多也不能少字符,否則分片不成功,默認存到第一個分片里面;

11.范圍求模分片

該分片方法,有個非常大的優勢,就是對擴容,原數據無需遷移

<tableRule name="auto-sharding-rang-mod">
        <rule>
            <columns>time_id</columns>
            <algorithm>rang-mod</algorithm>
        </rule>
    </tableRule>
<function name="rang-mod"class="io.mycat.route.function.PartitionByRangeMod">
        <propertyname="mapFile">partition-range-mod.txt</property>
        <propertyname="defaultNode">0</property>
    </function>

partition-range-mod.txt 文件中的內容:

#1451577600000 是 2016-01-01 00:00:00 的long值
#1467302399000 是 2016-06-30 23:59:59 的long值
#1483199999000 是 2016-12-31 26:59:59 的long值
1451577600000-1467302399000=2
1467302399001-1483199999000=2

上面的一個條目[1451577600000-1467302399000=2]代表一個分片組,開始范圍--結束范圍=該分片組有多少個分片(DataNode)。也就是我給出的方案是,2016上半年的數據存入分片組1,分片組1包含(dn1,dn2)兩個節點,2016年下半年的數據,存入分片組2,(dn3,dn4),那2017年的數據怎么辦呢,我們可以增加分片組來實現,也可修改配置文件,使用原來的1,2,3,4這樣來配置,實現擴容時,不需要對原數據進行遷移。

12.日期范圍hash分片

思想與范圍求模一致,當由於日期在取模會有數據集中問題,所以改成 hash 方法。
先根據日期分組,再根據時間 hash 使得短期內數據分布的更均勻
優點可以避免擴容時的數據遷移,又可以一定程度上避免范圍分片的熱點問題
要求日期格式盡量精確些,不然達不到局部均勻的目的

<tableRule name="rangeDateHash">
  <rule>
    <columns>col_date</columns>
    <algorithm>range-date-hash</algorithm>
  </rule>
</tableRule>
<function name="range-date-hash" class="io.mycat.route.function.PartitionByRangeDateHash">
  <property name="sBeginDate">2014-01-01 00:00:00</property>
  <property name="sPartionDay">3</property>
  <property name="dateFormat">yyyy-MM-dd HH:mm:ss</property>
  <property name="groupPartionSize">6</property>
</function>
    1. 參數說明:
      -- sBeginDate 代表開始時間
      -- sPartionDay 代表多少天分一個分片
      -- groupPartionSize 代表分片組的大小
    1. 詳細解釋:從sBeginDate時間開始計算,每sPartionDay天的數據為一個分片組,每個分片組可以分布在groupPartionSize個分片上面。上面的例子最多可以有三天進行分片,如果超出則會拋出以下異常
Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Can't find a valid data node for specified node index :ALAN_TEST -> RANGE_DATE -> 2019-01-11 12:00:00 -> Index : 4
The error may involve com.mycat.test.model.AlanTest.insert-Inline
The error occurred while setting parameters

13.冷熱數據分片

根據日期查詢日志數據 冷熱數據分布 ,最近 n 個月的到實時交易庫查詢,超過 n 個月的按照 m 天分片。

<tableRule name="sharding-by-date">
  <rule>
    <columns>create_time</columns>
    <algorithm>sharding-by-hotdate</algorithm>
  </rule>
</tableRule>
<function name="sharding-by-hotdate"  class="io.mycat.route.function.PartitionByHotDate">
  <property name="dateFormat">yyyy-MM-dd</property>
  <property name="sLastDay">10</property>
  <property name="sPartionDay">30</property>132
</function>

參數說明:

  • dataFormat:時間格式化。按照給定的格式對參數進行格式化,方便計算具體的時間段
  • sLastDay:熱數據的天數。從當前服務器時間開始計算,之前sLastDay天的數據和之后所有的數據,全部為熱數據。
  • sPartionDay:冷數據的分片天數(按照天數分片)。冷數據按照這個范圍進行分片,例如上面的規則配置,今天是2019年1月21日,往前推10天為2019年1月12日,則2019年1月12日之前的數據為冷數據,該批冷數據的分片規則為30天一個分片,即2018-12-12至2019-01-11的數據放入第2個分片,2018-11-12至2018-12-11的數據放入第2個分片...以此類推,如果數據庫分區不夠,則在保存的時候會拋出以下異常
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Can't find a valid data node for specified node index :ALAN_TEST -> CREATE_DATE -> 2018-11-09 12:00:00 -> Index : 3

14.修改數據

mycat中分片表中的分片字段是不能更新的,而Jpa(底層hibernate)默認是更新全字段。所以會產生沖突,拋出如下異常

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Sharding column can't be updated ALAN_TEST->RANGE_DATE
14.1解決方案
  • 對實體類增加注解:@Column(updatable=false)
  • 或者修改實體映射文件
<property name="age" update="false"></property>

15.多條件查詢

多條件查詢,AND語句連接,只要有一個條件為分片的字段,那么會按照分片表進行查詢,和條件的順序沒有關系。

16.join語句

目前支持的規則為,只有當分片規則相同,並且兩個表的數據分布到了同一個分片數據庫中,那么根據join查詢出來的數據是完整的。
如果分片規則相同,分片不同,查詢出來的數據是不完整的,即左連接只能查詢左表數據,由連接只能查詢右表數據。 內連接和inner數據都不能查詢出來。

17.數據庫表名大小寫

最好采用數據庫表名小寫,因為如果采用大寫,邏輯庫中生成的為小寫表名,在分片庫中生成的為大寫表名,這樣會導致mycat找不到表而發生錯誤


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM