跨库 join

全局表

系统中基本都会存在数据字典信息,如数据分类信息、项目的配置信息等。这些字典数据最大的特点就是数据量不大并且很少会被改变。同时绝大多数的业务场景都会涉及到字典表的操作。 因此为了避免频繁的跨库 join 操作,结合冗余数据思想,可以考虑把这些字典信息在每一个分库中都存在一份。

mycat 在进行 join 操作时,当业务表与全局表进行聚合会优先选择相同分片的全局表,从而避免跨库 join 操作。在进行数据插入时,会把数据同时插入到所有分片的全局表中。

修改schema.xml

1
<table name="tb_global" dataNode="dn142,dn145" primaryKey="global_id" type="global"/>

ER 表

ER 表也是一种为了避免跨库 join 的手段,在业务开发时,经常会使用到主从表关系的查询,如商品表与商品详情表。

ER 表的出现就是为了让有关系的表数据存储于同一个分片中,从而避免跨库 join 的出现。

  1. 修改 schema.xml
1
2
3
<table name="tb_goods" dataNode="dn129,dn130" primaryKey="goods_id" rule="sharding-by-murmur-goods">
<childTable name="tb_goods_detail" primaryKey="goods_detail_id" joinKey="goods_id" parentKey="goods_id"></childTable>
</table>
  1. 再次添加 goods 数据的时候,有关系的表数据存储于同一个分片中

读写分离

一个数据库的容量毕竟是有限制的,如果数据量非常大,分表已经满足不了的话,就会进行分库操作。分库架构如下:

现在存在两个主库,并且各自都有从节点。 当插入数据时,根据 id 取模放入不同的库中。同时主从间在进行写时复制的同时,还要完成主从读写分离的配置。

  1. 修改 schema.xml。配置多 datenode 与 datahost。同时配置主从读写分离。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

<schema name="userDB" checkSQLschema="true" dataNode="dn129" sqlMaxLimit="500">
<table name="t_user" dataNode="dn129,dn130" primaryKey="id" rule="mod-long"/>
</schema>


<dataNode name="dn129" dataHost="dh129" database="user"/>
<dataNode name="dn130" dataHost="dh130" database="user"/>

<dataHost name="dh129" balance="1" maxCon="100" minCon="10" dbType="mysql" dbDriver="jdbc" writeType="0" switchType="1" slaveThreshold="1000">
<!--查询心跳-->
<heartbeat>select user()</heartbeat>
<!--配置写节点实际物理数据库信息-->
<writeHost url="jdbc:mysql://192.168.200.129:3306" host="host1" user="root" password="123456">
<!--配置读节点实际物理数据库信息-->
<readHost host="host2" url="jdbc:mysql://192.168.200.130:3306" user="root" password="123456" ></readHost>
</writeHost>
</dataHost>

<dataHost name="dh130" balance="1" maxCon="100" minCon="10" dbType="mysql" dbDriver="jdbc" writeType="0" switchType="1" slaveThreshold="1000">
<!--查询心跳-->
<heartbeat>select user()</heartbeat>
<!--配置写节点实际物理数据库信息-->
<writeHost url="jdbc:mysql://192.168.200.129:3306" host="host1" user="root" password="123456">
<!--配置读节点实际物理数据库信息-->
<readHost host="host2" url="jdbc:mysql://192.168.200.130:3306" user="root" password="123456" ></readHost>
</writeHost>
</dataHost>
</mycat:schema>
  1. 修改 rule.xml。配置取模时的模数
1
2
3
4
5
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<!-- 根据datanode数量进行取模分片,也就是要模几。 -->
<property name="count">2</property>
</function>
  1. 读写分离验证

​ 设置 log4j2.xml 的日志级别为 DEBUG

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
........
<asyncRoot level="DEBUG" includeLocation="true">
........
</asyncRoot>
</Loggers>
</Configuration>

基于 mysql 服务进行数据查看,观察控制台信息,可以看到对于 read 请求的数据源,分别使用的是配置文件的配置

主从切换

基于 Mycat 主从复制方案,当前存在一个主节点和一个从节点,主节点负责写操作,从节点负责读操作。当在一个 dataHost 中配置了两个或多个 writeHost,如果第一个 writeHost 宕机,则 Mycat 会在默认 3 次心跳检查失败后,自动切换到下一个可用的 writeHost 执行 DML 语句,并在conf/dnindex.properties文件里记录当前所用的 writeHost 的 index。

在 Mycat 主从切换中,可以将从节点也配置为是一个写节点(相当于从节点同时负责读写)。当原有的 master 写节点宕机后,从节点会被提升为主节点,同时负责读写操作。当写节点恢复后,会被作为从节点使用,保持现有状态不变,跟随新的主节点。

简单点说就是:原来的主变成从,原来的从一直为主。

schema.xml 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

<schema name="userDB" checkSQLschema="true" dataNode="dn142" sqlMaxLimit="500">
<table name="tb_user" dataNode="dn142" primaryKey="user_id" />
</schema>


<dataNode name="dn142" dataHost="dh142" database="user"/>

<!--
writeType:0 所有的写操作都发送到writeHost上
balance:1 所有读操作都发送到readHost上
switchType:2 基于mysql主从同步的状态决定是否切换
-->
<dataHost name="dh142" writeType="0" balance="1" switchType="2" maxCon="100" minCon="10" dbType="mysql" dbDriver="jdbc" slaveThreshold="1000">
<!--查询心跳-->
<heartbeat>show slave status</heartbeat>
<!--配置写节点实际物理数据库信息-->
<writeHost url="jdbc:mysql://192.168.200.142:3309" host="host1" user="root" password="123456">
<!--配置读节点实际物理数据库信息-->
<readHost host="host2" url="jdbc:mysql://192.168.200.145:3309" user="root" password="123456" ></readHost>
</writeHost>

<!--配置从节点也会作为写节点使用-->
<writeHost url="jdbc:mysql://192.168.200.145:3309" host="host2" user="root" password="123456"></writeHost>
</dataHost>
</mycat:schema>

测试:

  • 开启 host1 和 host2

    结论: 新增数据,全部新增到了 host1 中

  • 关闭 host1

    结论: 新增数据,全部新增到了 host2 中

  • 再次开启 host1

    结论: 新增数据,依然新增到 host2 中