Mycat配置分庫分表(垂直分庫、水平分表)、全局序列


1. Mycat相關文章

  Linux安裝Mycat1.6.7.4並實現Mysql數據庫讀寫分離簡單配置
  Linux安裝Mysql8.0.20並配置主從復制(一主一從,雙主雙從)
  Docker部署Mysql8.0.20並配置主從復制

2. 其他分庫分表方案

  Sharding-JDBC分庫分表簡單示例

3. 垂直拆分--分庫

  一個龐大的業務系統對應一個數據庫,數據庫中存在大量的表,必然影響系統體驗度。因此,需要按照業務將表進行拆分成多個業務庫,每個業務庫只存儲相關的業務表,即可減輕單個數據庫的壓力。

  根據圖中,將教務管理數據庫拆分成:學生管理庫、課程管理庫和成績管理庫,每個庫僅存與之關聯的業務表。業務系統訪問Mycat邏輯庫,實則還是訪問一個數據庫。

  • 拆分原則
      拆分后的數據庫可能存在多個主機的數據庫服務中,因此在關聯查詢時,不可能將不同的數據庫服務進行關聯,因此需要將業務表進行歸類,將關聯緊密的表划分到一個數據庫。
      對於一個教務管理系統來說,學生表將被划分到學生管理庫,課程表、課程詳情表和課程字典表將划分到課程管理庫中。
  • 主機划分
服務器IP 備注
192.168.133.130 數據庫-1
192.168.133.131 數據庫-2
192.168.133.132/192.168.133.130 Mycat
<?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="t_student" dataNode="dn2"></table>
    </schema>
    <dataNode name="dn1" dataHost="host1" database="education" />
    <dataNode name="dn2" dataHost="host2" database="education" />
    <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM1" url="192.168.133.130:3306" user="root" password="123456"></writeHost>
    </dataHost>
    <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM2" url="192.168.133.131:3306" user="root" password="123456"></writeHost>
    </dataHost>
</mycat:schema>

  對於數據庫education,僅把表t_student划分到第二個節點,即主機2上,其余的表t_schedulet_schedule_detailt_subject_dict默認划分到第一個節點。

  • 創建數據庫
      分別在兩個主機上的Mysql上創建數據庫education
create database education;
  • 啟動Mycat
# 進入Mycat的bin目錄
./mycat console
  • 創建表
      在服務器連接Mycat或者使用Navicat等工具連接。
# 服務器連接
mysql -umycat -p -h192.168.133.132 -P8066

# 或者使用其他工具連接

# 在Mycat上創建表
DROP TABLE IF EXISTS `t_student`;
CREATE TABLE `t_student`  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NULL DEFAULT NULL COMMENT '學生姓名',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 COMMENT = '學生信息表';

DROP TABLE IF EXISTS `t_schedule`;
CREATE TABLE `t_schedule`  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `subject_code` varchar(20) NULL DEFAULT NULL COMMENT '課程編碼',
  `student_id` int(0) NULL DEFAULT NULL COMMENT '學生ID',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB COMMENT = '課程信息表';

DROP TABLE IF EXISTS `t_schedule_detail`;
CREATE TABLE `t_schedule_detail`  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `class_time` datetime(0) NULL DEFAULT NULL COMMENT '上課時間',
  `schedule_id` int(0) NULL DEFAULT NULL COMMENT '課程ID',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB COMMENT = '課程明細表';

DROP TABLE IF EXISTS `t_subject_dict`;
CREATE TABLE `t_subject_dict`  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `subject_code` varchar(20) NULL DEFAULT NULL COMMENT '課程編碼',
  `subject_name` varchar(50) NULL DEFAULT NULL COMMENT '課程名稱',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 COMMENT = '課程字典表';
  • 查詢表
# 分別在兩台主機上查詢表
mysql -uroot -p -h192.168.133.130 -P3306
use education;
show tables;

# 在Mycat上查詢表
mysql -uroot -p -h192.168.133.132 -P8066
use TESTDB;
show tables;

# 查詢表記錄
select * from t_student;
select * from t_schedule;
select * from t_schedule_detail;
select * from t_subject_dict;

4. 水平拆分--分表

  水平拆分指的是對一張表根據某個字段按照某種規則進行拆分,要求每個數據庫都存在該表,但一個數據庫只存儲符合規則的那些數據,在單表數據量大的情況下,極大效率的減少數據庫壓力,提高訪問速度。

  根據圖中,將課程管理中的課程表等相關表進行拆分,拆分到不同的數據庫服務中。

  • 拆分原則
      Mysql中,當單表的數據量超過500萬行或者大於2GB時,就需要考慮分庫分表。
      對於課程表來說,根據學生ID規則進行拆分較為合適,可以將每個學生的課程信息划分到一個數據庫服務中,便於和其他表關聯查詢。
  • 服務器划分
      和垂直拆分時服務器划分方式相同,即使用此服務器即可完成測試。
服務器IP 備注
192.168.133.130 數據庫-1
192.168.133.131 數據庫-2
192.168.133.132/192.168.133.130 Mycat
  • 配置分表
      修改Mycat的schema.xml文件,設置課程表t_schedule分表規則student_id_mod_rule(名稱自定義):
<?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="t_student" dataNode="dn2"></table>
     <table name="t_schedule" dataNode="dn1,dn2" rule="student_id_mod_rule"></table>
	</schema>
	<dataNode name="dn1" dataHost="host1" database="education" />
  <dataNode name="dn2" dataHost="host2" database="education" />
	<dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<writeHost host="hostM1" url="192.168.133.131:3306" user="root" password="3edc#EDC">
		</writeHost>
	</dataHost>
  <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<writeHost host="hostM2" url="192.168.133.130:3306" user="root" password="3edc#EDC">
		</writeHost>
	</dataHost>
 
</mycat:schema>

  修改Mycat的srule.xml文件,配置課程表分表規則student_rule

# 添加規則
<tableRule name="student_id_mod_rule">
	<rule>
		<columns>student_id</columns>
		<algorithm>mod-long</algorithm>
	</rule>
</tableRule>

# 修改mod-long規則
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
	<!-- how many data nodes -->
	<property name="count">2</property>
</function>

  新增tableRule節點,配置列和規則算法。
  修改mod-long算法的count數值,兩台主機即為2。

  • 在另一台主機上創建課程信息表
CREATE TABLE `t_schedule` (
  `id` int NOT NULL AUTO_INCREMENT,
  `subject_code` varchar(20) DEFAULT NULL COMMENT '課程編碼',
  `student_id` int DEFAULT NULL COMMENT '學生ID',
  PRIMARY KEY (`id`) USING BTREE
) COMMENT='課程信息表';
  • 啟動Mycat
# 進入Mycat的bin目錄
./mycat console
  • 插入數據
      在服務器連接Mycat或者使用Navicat等工具連接。
insert into t_schedule(id, subject_code, student_id) values(1, 'YW', 1);
insert into t_schedule(id, subject_code, student_id) values(2, 'SX', 1);
insert into t_schedule(id, subject_code, student_id) values(3, 'YY', 1);
insert into t_schedule(id, subject_code, student_id) values(4, 'YW', 2);
insert into t_schedule(id, subject_code, student_id) values(5, 'SX', 2);
insert into t_schedule(id, subject_code, student_id) values(6, 'YY', 2);
  • 測試
# 使用Mycat查詢,6條數據
select * from t_schedule;

# 使用Mysql-1查詢,3條數據,student_id均為2
select * from t_schedule;

# 使用Mysql-2查詢,3條數據,student_id均為1
select * from t_schedule;
  • 關聯表分表
      與課程表相關聯的課程詳情表在關聯查詢時可能因為外聯的數據不在同一個Mysql服務中,因此課程詳情表需要根據課程表進行拆分,將課程ID相同的數據划分到和課程信息相同的一個Mysql服務中。
      Mycat借鑒了NewSQL領域的新秀Foundation DB的設計思路,Foundation DB創新性的提
    出了Table Group的概念,其將子表的存儲位置依賴於主表,並且物理上緊鄰存放,因此徹底解決了
    JION的效率和性能問題,根據這一思路,提出了基於E-R關系的數據分片策略,子表的記錄與所關聯的父表記錄存放在同一個數據分片上。
  • 配置分表
      修改Mycat的schema.xml文件,增加課程表t_schedule的子表t_schedule_detail
<?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="t_student" dataNode="dn2"></table>
        <table name="t_schedule" dataNode="dn1,dn2" rule="student_id_mod_rule">
            <childTable name="t_schedule_detail" primaryKey="id" joinKey="schedule_id" parentKey="id" />
        </table>
    </schema>
    <dataNode name="dn1" dataHost="host1" database="education" />
    <dataNode name="dn2" dataHost="host2" database="education" />
    <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM1" url="192.168.133.131:3306" user="root" password="3edc#EDC"></writeHost>
    </dataHost>
    <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM2" url="192.168.133.130:3306" user="root" password="3edc#EDC"></writeHost>
    </dataHost>
</mycat:schema>
  • 在另一台主機上創建課程詳情表
CREATE TABLE `t_schedule_detail` (
  `id` int NOT NULL AUTO_INCREMENT,
  `class_time` datetime DEFAULT NULL COMMENT '上課時間',
  `schedule_id` int DEFAULT NULL COMMENT '課程ID',
  PRIMARY KEY (`id`) USING BTREE
) COMMENT='課程明細表';
  • 啟動Mycat
# 進入Mycat的bin目錄
./mycat console
  • 插入數據
      在服務器連接Mycat或者使用Navicat等工具連接。
insert into t_schedule_detail(id, class_time, schedule_id) values (1, now(), 1);
insert into t_schedule_detail(id, class_time, schedule_id) values (2, now(), 2);
insert into t_schedule_detail(id, class_time, schedule_id) values (3, now(), 3);
insert into t_schedule_detail(id, class_time, schedule_id) values (4, now(), 4);
insert into t_schedule_detail(id, class_time, schedule_id) values (5, now(), 5);
insert into t_schedule_detail(id, class_time, schedule_id) values (6, now(), 6);
  • 測試
# 使用Mycat查詢,6條數據
select a.*, b.class_time, b.schedule_id from t_schedule a right join t_schedule_detail b on a.id = b.schedule_id order by id;

# 使用Mysql-1查詢,3條數據,student_id均為2
select a.*, b.class_time, b.schedule_id from t_schedule a right join t_schedule_detail b on a.id = b.schedule_id order by id;

# 使用Mysql-2查詢,3條數據,student_id均為1
select a.*, b.class_time, b.schedule_id from t_schedule a right join t_schedule_detail b on a.id = b.schedule_id order by id;
  • 配置全局表
      根據業務將業務表進行拆分后,數據被划分到不同的數據分片中,但是與業務相關聯的數據字典表的關聯問題也需要解決。
      考慮到數據字典表等特征表具有以下特點:(1)數據量小;(2)數據變化不頻繁等特點,因此可以采用數據冗余的方式,將此類型的表拆分到每一個數據片中。當插入數據時,對所有節點進行插入操作,確保數據的一致性;當單表查詢時,僅從一個數據片中查詢;當與其他表關聯時,與業務表相同的數據片中的表進行關聯。
  • 配置分表
      修改Mycat的schema.xml文件,增加課程字典表t_subject_dict為全局表:
<?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="t_student" dataNode="dn2"></table>
        <table name="t_schedule" dataNode="dn1,dn2" rule="student_id_mod_rule">
            <childTable name="t_schedule_detail" primaryKey="id" joinKey="schedule_id" parentKey="id" />
        </table>
        <table name="t_subject_dict" dataNode="dn1,dn2" type="global" ></table>
    </schema>
    <dataNode name="dn1" dataHost="host1" database="education" />
    <dataNode name="dn2" dataHost="host2" database="education" />
    <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM1" url="192.168.133.131:3306" user="root" password="3edc#EDC"></writeHost>
    </dataHost>
    <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM2" url="192.168.133.130:3306" user="root" password="3edc#EDC"></writeHost>
    </dataHost>
</mycat:schema>
  • 在另一台主機上創建課程字典表
CREATE TABLE `t_subject_dict` (
  `id` int NOT NULL AUTO_INCREMENT,
  `subject_code` varchar(20) DEFAULT NULL COMMENT '課程編碼',
  `subject_name` varchar(50) DEFAULT NULL COMMENT '課程名稱',
  PRIMARY KEY (`id`) USING BTREE
) COMMENT='課程字典表';
  • 啟動Mycat
# 進入Mycat的bin目錄
./mycat console
  • 插入數據
      在服務器連接Mycat或者使用Navicat等工具連接。
insert into t_subject_dict(id, subject_code, subject_name) values(1, 'YW', '語文');
insert into t_subject_dict(id, subject_code, subject_name) values(2, 'SX', '數學');
insert into t_subject_dict(id, subject_code, subject_name) values(3, 'YY', '英語');
  • 測試
# 使用Mycat查詢,3條數據
select * from t_subject_dict;

# 使用Mysql-1查詢,3條數據
select * from t_subject_dict;

# 使用Mysql-2查詢,3條數據
select * from t_subject_dict;

5. 常用分片規則

  • 取模
      上述對課程表的分表規則即為取模。
  • 分片枚舉
      枚舉盡可能的規則ID,使得數據在插入時按照枚舉的規則划分到對應的數據片中。這類表具有數據固定且數據量小等特點。例如:區域表,全國區域固定,按照區域編碼進行枚舉,將特定的區域已經相關聯的區域業務數據划分到同一個數據片中。
      修改Mycat的schema.xml文件,增加區域表t_area並配置規則sharding_by_area_code(名稱自定義):
<?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="t_student" dataNode="dn2"></table>
        <table name="t_schedule" dataNode="dn1,dn2" rule="student_id_mod_rule">
            <childTable name="t_schedule_detail" primaryKey="id" joinKey="schedule_id" parentKey="id" />
        </table>
        <table name="t_subject_dict" dataNode="dn1,dn2" type="global" ></table>
        <table name="t_area" dataNode="dn1,dn2" rule="sharding_by_area_code" ></table>
    </schema>
    <dataNode name="dn1" dataHost="host1" database="education" />
    <dataNode name="dn2" dataHost="host2" database="education" />
    <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM1" url="192.168.133.131:3306" user="root" password="3edc#EDC"></writeHost>
    </dataHost>
    <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM2" url="192.168.133.130:3306" user="root" password="3edc#EDC"></writeHost>
    </dataHost>
</mycat:schema>

  修改Mycat的rule.xml,配置規則:

# 新增規則
<tableRule name="sharding_by_area_code">
	<rule>
		<columns>area_code</columns>
		<algorithm>hash-int</algorithm>
	</rule>
</tableRule>

# 修改算法hash-int
# mapFile => 標識配置文件名稱
# type => 0為int類型,非0為String類型
# defaultNode => 小於0則為不配置默認節點,大於等於0標識配置對應的數據節點。當匹配不到對應的數據節點時,則使用默認的數據節點,若不配置默認數據節點,則報錯
<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
	<property name="mapFile">partition-hash-int.txt</property>
    <property name="type">1</property>
    <property name="defaultNode">0</property>
</function>

# 修改partition-hash-int.txt,配置枚舉
029=0
0913=1

# 啟動Mycat
# 進入Mycat的bin目錄
./mycat console

# 使用Mycat創建區域表
CREATE TABLE `t_area` (
  `id` int NOT NULL AUTO_INCREMENT,
  `area_code` varchar(20) DEFAULT NULL COMMENT '區域編碼',
  `area_name` varchar(50) DEFAULT NULL COMMENT '區域名稱',
  PRIMARY KEY (`id`) USING BTREE
) COMMENT='區域信息表';

# 插入數據
insert into t_area(id, area_code, area_name) values(1, '010', '北京');
insert into t_area(id, area_code, area_name) values(2, '029', '西安');
insert into t_area(id, area_code, area_name) values(3, '0913', '渭南');

# 測試,查詢數據
# 使用Mycat查詢,3條數據
select * from t_area;

# 使用Mysql-1查詢,2條數據,area_code為010、029
select * from t_area;

# 使用Mysql-2查詢,1條數據,area_code為0913
select * from t_area;
  • 范圍約定
      限定某些范圍的數據被划分到指定的數據片中。例如:學生成績表,根據成績區間可以划分到不同的數據片中。
      修改Mycat的schema.xml文件,增加成績表t_score並配置規則sharding_by_score(名稱自定義):
<?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="t_student" dataNode="dn2"></table>
        <table name="t_schedule" dataNode="dn1,dn2" rule="student_id_mod_rule">
            <childTable name="t_schedule_detail" primaryKey="id" joinKey="schedule_id" parentKey="id" />
        </table>
        <table name="t_subject_dict" dataNode="dn1,dn2" type="global" ></table>
        <table name="t_area" dataNode="dn1,dn2" rule="sharding_by_area_code" ></table>
        <table name="t_score" dataNode="dn1,dn2" rule="sharding_by_score" ></table>
    </schema>
    <dataNode name="dn1" dataHost="host1" database="education" />
    <dataNode name="dn2" dataHost="host2" database="education" />
    <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM1" url="192.168.133.131:3306" user="root" password="3edc#EDC"></writeHost>
    </dataHost>
    <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM2" url="192.168.133.130:3306" user="root" password="3edc#EDC"></writeHost>
    </dataHost>
</mycat:schema>

  修改Mycat的rule.xml,配置規則:

# 新增規則
<tableRule name="sharding_by_score">
	<rule>
		<columns>score</columns>
		<algorithm>rang-long</algorithm>
	</rule>
</tableRule>

# 修改算法rang-long
# mapFile => 標識配置文件名稱
# defaultNode => 小於0則為不配置默認節點,大於等於0標識配置對應的數據節點。當匹配不到對應的數據節點時,則使用默認的數據節點,若不配置默認數據節點,則報錯
<function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
	<property name="mapFile">autopartition-long.txt</property>
    <property name="defaultNode">0</property>
</function>

# 修改autopartition-long.txt,約定范圍
0-60=0
61-100=1

# 啟動Mycat
# 進入Mycat的bin目錄
./mycat console

# 使用Mycat創建成績表
CREATE TABLE `t_score` (
  `id` int NOT NULL AUTO_INCREMENT,
  `score` int DEFAULT 0 COMMENT '總成績',
  `student_id` int DEFAULT NULL COMMENT '區域名稱',
  PRIMARY KEY (`id`) USING BTREE
) COMMENT='成績信息表';

# 插入數據
insert into t_score(id, score, student_id) values(1, 54, 1);
insert into t_score(id, score, student_id) values(2, 98, 2);

# 測試,查詢數據
# 使用Mycat查詢,2條數據
select * from t_score;

# 使用Mysql-1查詢,1條數據,成績<60
select * from t_score;

# 使用Mysql-2查詢,1條數據,成績>=60
select * from t_score;
  • 按照日期分片
      按照日期(例如:天)將數據划分到不同的數據片中。例如:日志表,可以按照天將日志划分到不同的數據分區,便於查詢和刪除歷史過期日志。
      修改Mycat的schema.xml文件,增加成績表t_log並配置規則sharding_by_date(名稱自定義):
<?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="t_student" dataNode="dn2"></table>
        <table name="t_schedule" dataNode="dn1,dn2" rule="student_id_mod_rule">
            <childTable name="t_schedule_detail" primaryKey="id" joinKey="schedule_id" parentKey="id" />
        </table>
        <table name="t_subject_dict" dataNode="dn1,dn2" type="global" ></table>
        <table name="t_area" dataNode="dn1,dn2" rule="sharding_by_area_code" ></table>
        <table name="t_score" dataNode="dn1,dn2" rule="sharding_by_score" ></table>
        <table name="t_log" dataNode="dn1,dn2" rule="sharding_by_date" ></table>
    </schema>
    <dataNode name="dn1" dataHost="host1" database="education" />
    <dataNode name="dn2" dataHost="host2" database="education" />
    <dataHost name="host1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM1" url="192.168.133.131:3306" user="root" password="3edc#EDC"></writeHost>
    </dataHost>
    <dataHost name="host2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM2" url="192.168.133.130:3306" user="root" password="3edc#EDC"></writeHost>
    </dataHost>
</mycat:schema>

  修改Mycat的rule.xml,配置規則:

# 新增規則
<tableRule name="sharding_by_date">
	<rule>
		<columns>log_date</columns>
		<algorithm>sharding-by-date</algorithm>
	</rule>
</tableRule>

# 新增算法sharding-by-data
#dateFormat => 日期格式
#sBeginDate => 開始日期
#sEndDate => 結束日期,當日期到達結束時間后,從開始分片插入
#sPartionDay :分區天數,即默認從開始日期算起,分隔2天一個分區
<function name="sharding-by-date" class="io.mycat.route.function.PartitionByDate">
    <property name="dateFormat">yyyy-MM-dd</property>
    <property name="sBeginDate">2020-10-10</property>
    <property name="sEndDate">2020-10-13</property>
    <property name="sPartionDay">2</property>
  </function>

# 啟動Mycat
# 進入Mycat的bin目錄
./mycat console

# 使用Mycat創建日志表
CREATE TABLE `t_log` (
  `id` int NOT NULL AUTO_INCREMENT,
  `log_title` varchar(50) NULL DEFAULT NULL COMMENT '日志標題',
  `log_date` date NULL DEFAULT NULL COMMENT '日志時間',
  PRIMARY KEY (`id`) USING BTREE
) COMMENT='日志信息表';

# 插入數據
insert into t_log(id, log_title, log_date) values(1, '測試1', '2020-10-10');
insert into t_log(id, log_title, log_date) values(2, '測試2', '2020-10-11');
insert into t_log(id, log_title, log_date) values(3, '測試3', '2020-10-12');
insert into t_log(id, log_title, log_date) values(4, '測試4', '2020-10-13');
insert into t_log(id, log_title, log_date) values(5, '測試5', '2020-10-14');
insert into t_log(id, log_title, log_date) values(6, '測試6', '2020-10-15');

# 測試,查詢數據
# 使用Mycat查詢,6條數據
select * from t_log order by id;

# 使用Mysql-1查詢,4條數據,日志日期為10、11、14、15
select * from t_log order by id;

# 使用Mysql-2查詢,2條數據,日志日期為12、13
select * from t_log order by id;

6. 全局序列

  在實現數據庫分庫分表后,數據庫自增主鍵如何保證唯一性是需要解決的必要問題。Mycat提供了sequence,使用本地配置或數據庫配置等多種方式保證自增主鍵的唯一性。

  • 本地文件方式(不建議使用)
      Mycat將sequence值配置到sequence_conf.properties配置文件中,當使用sequence后,更新配置文件中sequence的值。
      此方式優點是加載速度快,缺點是抗風險能力差,Mycat宕機后,無法從本地配置文件讀取sequence值。
  • 數據庫方式(推薦)
      在數據庫上創建一張表來作為主鍵計數,如果采用每次使用時再查詢效率不高,因此采用匹配查詢的方式,即每次Mycat會預加載一部分數據(例如100個),當使用完后,再次取下一部分數據(再取100個)。
      此方式效率高,但是當Mycat宕機后,加載到Mycat內存中的數據就會丟失,因此每次當時重啟后,Mycat舍棄之前取的數據,而是直接從數據庫獲取下一部分數據。
      創建序列腳本:
# 在Mysql-1上創建全局序列表
CREATE TABLE mycat_sequence ( 
	name VARCHAR(50) NOT NULL, 
	current_value INT NOT NULL, 
	increment INT NOT NULL DEFAULT 100, 
	PRIMARY KEY (name)
) COMMENT 'Mycat全局序列表';

# 設置全局序列需要的函數

DELIMITER $
CREATE FUNCTION mycat_seq_currval (
	seq_name VARCHAR(50)
) RETURNS VARCHAR(64) 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;

DELIMITER $
CREATE FUNCTION mycat_seq_setval (
	seq_name VARCHAR(50),
	VALUE INTEGER 
) RETURNS VARCHAR(64) DETERMINISTIC BEGIN
	UPDATE MYCAT_SEQUENCE 
	SET current_value = VALUE
	WHERE
		NAME = seq_name;
	RETURN mycat_seq_currval (seq_name);
END $
DELIMITER;

DELIMITER $
CREATE FUNCTION mycat_seq_nextval (
	seq_name VARCHAR(50)
) RETURNS VARCHAR(64) DETERMINISTIC BEGIN
	UPDATE MYCAT_SEQUENCE 
	SET current_value = current_value + increment 
	WHERE
		NAME = seq_name;
	RETURN mycat_seq_currval (seq_name);
END $
DELIMITER;

# 初始化全局序列表
insert into mycat_sequence(name, current_value, increment) values ('SCHEDULE', 10000, 100);

  修改Mycat配置,在配置文件 sequence_db_conf.properties添加課程序列(SCHEDULE)在Mysql-1上:

# 進入Mycat的bin目錄
vi sequence_db_conf.properties

# 添加配置
SCHEDULE=dn1

  修改server.xml,知道全局序列類型:

# 進入Mycat的bin目錄
vi server.xml

# 修改sequnceHandlerType=1
# sequnceHandlerType => 0為本地文件方式,1位數據庫方式,2位時間戳方式
<property name="sequnceHandlerType">1</property>

  啟動Mycat

# 進入Mycat的bin目錄
./mycat console

  測試:

# 連接Mycat,插入數據(可執行多次)
insert into t_schedule(id, subject_code, student_id) values(next value for MYCATSEQ_SCHEDULE, 'WL', 1);

# 查詢課程表(id從10100開始)
select * from t_schedule order by id desc;

# 重啟Mycat,再次插入(可執行多次)
insert into t_schedule(id, subject_code, student_id) values(next value for MYCATSEQ_SCHEDULE, 'HX', 2);

# 查詢課程表(id從10200開始)
select * from t_schedule order by id desc;
  • 時間戳方式
      全局序列ID=64位二進制 (42(毫秒)+5(機器 ID)+5(業務編碼)+12(重復累加)換算成十進制為 18位數的long類型,每毫秒可以並發12位二進制的累加。
      此方式優點是配置簡單,缺點是ID為18,位數太長。
  • 自定義方式(推薦)
      通過Redis生成序列,或者通過第三方插件生成自增ID,具體根據業務自由選擇。


免責聲明!

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



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