分库分表-mycat进阶

目标:

1、掌握不同数据分片策略的配置方式与特点

2、Mycat扩缩容与数据导入导出

3、理解Mycat注解的作用于应用场景

1. 分片策略详解

1.1 Mycat分片策略详解

总体上分为连续分片和离散分片,还有一种是连续分片和离散分片的结合,例如先范围后取模。比如范围分片(id 或者时间)就是典型的连续分片,单个分区的数量和边 界是确定的。离散分片的分区总数量和边界是确定的,例如对 key 进行哈希运算,或者再取模。

1.1.1 连续分片

缺点:会出现冷热数据,热数据分布在同一个节点,分库没有起到分摊数据访问压力的作用。

示例1:按自然月分片
1
2
3
CREATE TABLE `sharding_by_month` (
`create_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, `db_nm` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

mycat配置:

1
<table name="sharding_by_month" dataNode="72-imall,74-imall,76-imall" rule="pd-sharding-by-month" />

分片规则:

1
2
3
4
5
6
<tableRule name="pd-sharding-by-month"> 
<rule>
<columns>create_time</columns>
<algorithm>pd-partbymonth</algorithm>
</rule>
</tableRule>

分片算法:

1
2
3
4
5
<function name="pd-partbymonth" class="io.mycat.route.function.PartitionByMonth"> 
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2025-10-01</property>
<property name="sEndDate">2025-12-31</property>
</function>

columns 标识将要分片的表字段,字符串类型,与 dateFormat 格式一致。

algorithm 为分片函数。

dateFormat 为日期字符串格式

sBeginDate 为开始日期。

sEndDate 为结束日期

注意:节点个数要大于月份的个数

测试语句:

1
2
3
4
5
6
7
truncate table sharding_by_month;
INSERT INTO sharding_by_month (create_time,db_nm) VALUES ('2024-10-16', database());
INSERT INTO sharding_by_month (create_time,db_nm) VALUES ('2025-10-27', database());
INSERT INTO sharding_by_month (create_time,db_nm) VALUES ('2026-11-04', database());
INSERT INTO sharding_by_month (create_time,db_nm) VALUES ('2027-11-11', database());
INSERT INTO sharding_by_month (create_time,db_nm) VALUES ('2029-12-25', database());
INSERT INTO sharding_by_month (create_time,db_nm) VALUES ('2030-12-31', database());

注意:以上跟年度没有关系,只跟月度有关。

问题:不在 10 月和 12 月之间的数据,路由到哪个节点?结果不一定。可以在本地 调试一下。

另外还有按天分片(可以指定多少天一个分片)、按小时分片

1.1.2 离散分片

特点:分布很均匀,但是节点扩容需要迁移已分片的数据

示例1:十进制取模分片

根据分片键进行十进制求模运算。sharding_by_mod 表。

1
2
3
4
5
6
<tableRule name="mod-long"> 
<rule>
<columns>id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
1
2
3
4
<function name="mod-long" class="io.mycat.route.function.PartitionByMod"> 
<!-- how many data nodes -->
<property name="count">3</property>
</function>

测试数据:

1
2
3
4
5
6
7
truncate table sharing_by_mod;
INSERT INTO `sharding_by_mod` (`id`, `db_nm`) VALUES (1, '1');
INSERT INTO `sharding_by_mod` (`id`, `db_nm`) VALUES (2, '2');
INSERT INTO `sharding_by_mod` (`id`, `db_nm`) VALUES (3, '3');
INSERT INTO `sharding_by_mod` (`id`, `db_nm`) VALUES (4, '4');
INSERT INTO `sharding_by_mod` (`id`, `db_nm`) VALUES (5, '5');
INSERT INTO `sharding_by_mod` (`id`, `db_nm`) VALUES (6, '6');
示例2:枚举分片,根据年龄

将所有可能出现的值列举出来,指定分片。例如:全国 34 个省,要将不同的省的数 据存放在不同的节点,可用枚举的方式。

三个节点 imall 库创建 sharding_by_intfile 表

1
2
3
4
CREATE TABLE `sharding_by_intfile` (
`age` int(11) NOT NULL,
`db_nm` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

逻辑表:

1
<table name="sharding_by_intfile" dataNode="72-imall,74-imall,76-imall" rule="pd-sharding-by-intfile" />

分片规则:

1
2
3
4
5
6
<tableRule name="pd-sharding-by-intfile"> 
<rule>
<columns>age</columns>
<algorithm>hash-int</algorithm>
</rule>
</tableRule>

分片算法:

1
2
3
4
5
<function name="hash-int" class="org.opencloudb.route.function.PartitionByFileMap"> 
<property name="mapFile">partition-hash-int.txt</property>
<property name="type">0</property>
<property name="defaultNode">0</property>
</function>

type:默认值为 0,0 表示 Integer,非零表示 String。

PartitionByFileMap.java,通过 map 来实现。

策略文件:partition-hash-int.txt

1
2
3
16=0
17=1
18=2

插入数据测试

1
2
3
4
truncate table sharding_by_intfile;
INSERT INTO `sharding_by_intfile` (age,db_nm) VALUES (16, database());
INSERT INTO `sharding_by_intfile` (age,db_nm) VALUES (17, database());
INSERT INTO `sharding_by_intfile` (age,db_nm) VALUES (18, database());

特点:适用于枚举值固定的场景。

示例3:一致性哈希分片

一致性 hash 有效解决了分布式数据的扩容问题,可以一定程度减少数据的迁移。

建表语句:

分片规则

1
2
3
4
CREATE TABLE `sharding_by_murmur` (
`id` int(10) DEFAULT NULL,
`db_nm` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1
<table name="sharding_by_murmurhash" primaryKey="id" dataNode="72-imall,74-imall,76-imall" rule="sharding-by-murmur" />

分片规则:

1
2
3
4
5
6
<tableRule name="pd-sharding-by-murmur"> 
<rule>
<columns>id</columns>
<algorithm>pd-murmur</algorithm>
</rule>
</tableRule>

分片算法

1
2
3
4
5
<function name="pd-murmur" class="io.mycat.route.function.PartitionByMurmurHash"> 
<property name="seed">0</property>
<property name="count">3</property>
<property name="virtualBucketTimes">160</property>
</function>

测试语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
truncate table sharding_by_murmur;
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (1, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (2, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (3, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (4, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (5, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (6, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (7, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (8, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (9, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (10, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (11, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (12, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (13, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (14, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (15, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (16, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (17, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (18, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (19, database());
INSERT INTO `sharding_by_murmur` (id,db_nm) VALUES (20, database());
示例4:固定分片哈希

这是先求模得到逻辑分片号,再根据逻辑分片号直接映射到物理分片的一种散列算法。

特点:在一定范围内 id 是连续分布的。

建表语句:

1
2
3
4
CREATE TABLE `sharding_by_long` ( 
`id` int(10) DEFAULT NULL,
`db_nm` varchar(20) DEFAULT NULL
);

逻辑表

1
<table name="sharding_by_long" dataNode="72-imall,74-imall,76-imall" rule="pd-sharding-by-long" />

分片规则:

1
2
3
4
5
6
<tableRule name="pd-sharding-by-long">
<rule>
<columns>id</columns>
<algorithm>pd-sharding-by-long</algorithm>
</rule>
</tableRule>

分片算法:平均分成 8片(%1024 的余数,1024=128*8)

1
2
3
4
<function name="pd-sharding-by-long" class="io.mycat.route.function.PartitionByLong"> 
<property name="partitionCount">8</property>
<property name="partitionLength">128</property>
</function>

partitionCount 为指定分片个数列表。

partitionLength 为分片范围列表。

如果要不均匀的分布到不同节点,那就如下:

1
2
3
4
<function name="pd-sharding-by-long" class="io.mycat.route.function.PartitionByLong"> 
<property name="partitionCount">2,1</property>
<property name="partitionLength">256,512</property>
</function>

参数表示前2个节点分片长度256,第三个节点分片长度512

测试语句:

1
2
truncate table sharding_by_long;
INSERT INTO `sharding_by_long` (id,db_nm) VALUES (222, database()); INSERT INTO `sharding_by_long` (id,db_nm) VALUES (333, database()); INSERT INTO `sharding_by_long` (id,db_nm) VALUES (666, database());
示例5:取模范围分片

先对键取模,然后按照结果所在范围进行分片

特点:可以调整节点的数据分布,适合存储能力不同的节点组成的集群

节点扩容需迁移数据

建表:

1
2
3
4
CREATE TABLE `sharding_by_pattern` ( 
`id` varchar(20) DEFAULT NULL,
`db_nm` varchar(20) DEFAULT NULL
);

逻辑表:

1
<table name="sharding_by_pattern" primaryKey="id" dataNode="72-imall,74-imall,76-imall" rule="sharding-by-pattern" />

分片规则:

1
2
3
4
5
6
<tableRule name="sharding-by-pattern"> 
<rule>
<columns>id</columns>
<algorithm>sharding-by-pattern</algorithm>
</rule>
</tableRule>

分片算法:

1
2
3
4
5
<function name="sharding-by-pattern" class=" io.mycat.route.function.PartitionByPattern"> 
<property name="patternValue">100</property>
<property name="defaultNode">0</property>
<property name="mapFile">partition-pattern.txt</property>
</function>

patternValue 取模基数,这里设置成 100

partition-pattern.txt,一共 3 个节点

1
2
3
id=19%100=19,在 dn1; 
id=222%100=22,dn2;
id=371%100=71,dn3

测试语句:

1
2
truncate table sharding_by_pattern;
INSERT INTO `sharding_by_pattern` (id,db_nm) VALUES (19, database()); INSERT INTO `sharding_by_pattern` (id,db_nm) VALUES (222, database()); INSERT INTO `sharding_by_pattern` (id,db_nm) VALUES (371, database());
示例6:范围取模分片

先范围后取模

特点:扩容的时候旧数据无需迁移

建表:

1
2
3
4
CREATE TABLE `sharding_by_rang_mod` ( 
`id` bigint(20) DEFAULT NULL,
`db_nm` varchar(20) DEFAULT NULL
);

逻辑表配置:

1
<table name="sharding_by_rang_mod" dataNode="72-imall,74-imall,76-imall" rule="pd-sharding-by-rang-mod" />

分片规则:

1
2
3
4
5
6
<tableRule name="pd-sharding-by-rang-mod"> 
<rule>
<columns>id</columns>
<algorithm>pd-rang-mod</algorithm>
</rule>
</tableRule>

分片算法:

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

partition-range-mod.txt

1
2
3
# range start-end ,data node group size
0-20000=1
20001-40000=2

Id 在 20000 以内的,全部分布到 dn1。Id 在 20001-40000 的,%2 分布到 dn2,dn3。

测试语句:

1
2
3
truncate table sharding_by_rang_mod;
INSERT INTO `sharding_by_rang_mod` (id,db_nm) VALUES (666, database()); INSERT INTO `sharding_by_rang_mod` (id,db_nm) VALUES (6667, database()); INSERT INTO `sharding_by_rang_mod` (id,db_nm) VALUES (16666, database()); INSERT INTO `sharding_by_rang_mod` (id,db_nm) VALUES (21111, database()); INSERT INTO `sharding_by_rang_mod` (id,db_nm) VALUES (22222, database());
INSERT INTO `sharding_by_rang_mod` (id,db_nm) VALUES (23333, database()); INSERT INTO `sharding_by_rang_mod` (id,db_nm) VALUES (24444, database());
其他分片规则
  • 应用指定分片 PartitionDirectBySubString
  • 日期范围哈希 PartitionByRangeDateHash
  • 冷热数据分片 PartitionByHotDate
  • 也可以自定义分片规则:
1
extends AbstractPartitionAlgorithm implements RuleAlgorithm。
1.1.3 连续和离散的特点

连续分片优点:

  1. 范围查询消耗资源少,不需要汇总数据
  2. 扩容无需迁移数据

连续分片缺点:

​ 存在热点数据导致并发访问能力受限于单一或少量节点

离散分片优点:

  1. 并发访问能力强
  2. 范围条件查询性能提升(并行计算)

离散分片缺点:

  1. 数据扩容涉及数据迁移问题
  2. 数据库连接消耗大
1.1.4 切分规则的选择

步骤:

  1. 找到需要切分的大表和关联的表
  2. 确定分片字段(尽量使用主键),一般用最频繁使用的查询条件
  3. 考虑单个分片的存储容量和请求、数据增长、扩容和数据迁移问题

问题:

​ 按照上面递增?序号还是日期?主键是否有业务意义?

举例:
3.7 亿的数据怎么分表?我是不是分成 3 台服务器?

1、一年内到达多少?两年内到达多少?(数据的增长速度)?

答:一台设备每秒钟往 3 张表各写入一条数据,一共 4 台设备。每张表一天86400*4=345600 条。每张表一个月 10368000 条。

分析:增长速度均匀,可以用日期切分,每个月分一张表。

2、什么业务?所有的数据都会访问,还是访问新数据为主?

答:访问新数据为主,但是所有的数据都可能会访问到

3、表结构和表数据是什么样的?一个月消耗多少空间?

答:字段不多,算过了,三年数据量有 3.7 亿,30G。

分析:30G 没必要分库,浪费磁盘空间。

4、访问量怎么样?并发压力大么?

答:并发有一点吧

分析:如果并发量不大,不用分库,只需要在单库分表。不用引入 Mycat 中间件了。如果要自动路由的话可以用 Sharding-JDBC,否则就是自己拼装表名。

5、3 张表有没有关联查询之类的操作?

答:没有。

分析:还是拼装表名简单一点。

如果从单库变成分库分表,或者节点数的增加和减少,都会涉及到数据迁移的问题。数据迁移有两种,一种是在线不停机的迁移,还有一种是停机的。

2. Mycat扩缩容

2.1 在线扩缩容思路

流程:

  1. 把历史数据通过中间件迁移到新库
  2. 新的写请求,发送到消息队列,不消费
  3. 数据迁移完毕,迁移程序下线
  4. 消费信息,将增量数据写入新库
  5. 数据一致性验证
  6. 旧数据下线,切换到新库,重启应用。

不下线数据迁移

2.2 mysqldump方式

系统第一次上线,把单张表迁移到 Mycat,可以用 mysqldump。

MySQL 导出命令

1
mysqldump -uroot -p123456 -h127.0.0.1 -P3306 -c -t --skip-extended-insert imall > mysql-1107.sql

-c 代表带列名

-t 代表只要数据,不要建表语句

–skip-extended-insert 代表生成多行 insert(mycat childtable 不支持多行插入 ChildTable multi insert not provided)

Mycat 导入命令

1
mysql -uroot -p123456 -h127.0.0.1 -P8066 imall < mysql-1107.sql

2.3 Mycat自带的离线扩缩容工具

如果是已有分片表,可以用mycat自带的工具,实际上是对mysqldump进行了包装。

2.3.1 准备工作
  1. mycat所在环境安装mysql客户端程序
  2. mycat的lib目录下添加mysql的jdbc驱动包
  3. 对扩容表的所有节点数据进行备份,以便前以失败后的数据恢复。
2.3.2 步骤

以取模分片表 sharding-by-mod 缩容为例。

时间 数据
迁移前数据 72-imall 3, 6 74-imall 1,4 76-imall 2,5
迁移后数据 72-imall 2,4,6 74-imall 1,3,5

1、复制 schema.xml、rule.xml 并重命名为 newSchema.xml、newRule.xml 放 于 conf 目录下。

2、修改 newSchema.xml 和 newRule.xml 配置文件为扩容缩容后的 mycat 配 置参数(表的节点数、数据源、路由规则)。

注意:

只有节点变化的表才会进行迁移。仅分片配置变化不会迁移。

newSchema.xml

1
<table name="sharding_by_mod" dataNode="72-imall,74-imall,76-imall" rule="pd-sharding-by-mod" />

改成:

1
<table name="sharding_by_mod" dataNode="72-imall,74-imall" rule="pd-sharding-by-mod" />

newRule.xml 修改 count 个数

1
2
3
<function name="pd-sharding-by-mod-long" class="io.mycat.route.function.PartitionByMod"> 
<property name="count">2</property>
</function>

3、修改 conf 目录下的 migrateTables.properties 配置文件,告诉工具哪些表需 要进行扩容或缩容,没有出现在此配置文件的 schema 表不会进行数据迁移,格式:

1
imall=sharding-by-mod

注意

1)不迁移的表,不要修改 dn 个数,否则会报错。

2)ER 表,因为只有主表有分片规则,子表不会迁移。

4、dataMigrate.sh 中这个必须要配置

通 过 命 令 “find / -name mysqldump” 查 找 mysqldump 路 径 为 “/usr/bin/mysqldump”,指定#mysql bin 路径为”/usr/bin/“

1
2
#mysql bin 路径
RUN_CMD="$RUN_CMD -mysqlBin= /usr/bin/"

5、停止 mycat 服务

6、执行执行 bin/dataMigrate.sh 脚本,注意:必须要配置 Java 环境变量,不能用 openjdk

7、脚本执行完成,如果最后的数据迁移验证通过,就可以将之前的 newSchema.xml 和 newRule.xml 替换之前的 schema.xml 和 rule.xml 文件,并重启 mycat 即可。

2.3.3 注意事项
  1. 保证分片表迁移数据前后路由规则一致(取模——取模)。
  2. 保证分片表迁移数据前后分片字段一致。
  3. 全局表将被忽略。
  4. 不要将非分片表配置到 migrateTables.properties 文件中。
  5. 暂时只支持分片表使用 MySQL 作为数据源的扩容缩容。

migrate 限制比较多,还可以使用 mysqldump。

总结:离线或者在线,主要看数据量,和对于业务的影响程度决定。

3. Mysql 主从复制

用 mycat 实现了 MySQL 数据的分片存储,第一个可以实现负载 均衡,不同的读写发生在不同的节点上。第二可以实现横向扩展,如果数据持续增加, 加机器就 OK 了。

当然,一个分片只有一台机器还不够。为了防止节点宕机或者节点损坏,都要用副本机制来实现。MySQL 数据库同样可以集群部署,有了多个节点之后,节点之间数据又是个大问题。

3.1 主从复制的含义

在 MySQL 多服务器的架构中,主节点,也就是产生数据的节点叫 master 节点。其 他的副本,向主节点同步数据的节点,叫做 slave(默认是异步的,客户端的数据在 master 刷盘就返回)。一个集群里面至少要有一个 master。slave 可以有多个。

3.2 主从复制的用途

数据备份:把数据复制到不同的机器上,以免单台服务器发生故障时数据丢失。

负载均衡:结合负载的机制,均摊所有的应用访问请求,降低单机 IO。

高可用 HA:当节点故障时,自动转移到其他节点,提高可用性。

主从复制的架构可以有多种

3.3 主从复制的形式

  • 一主一从/一主多从
  • 双主复制(互为主从)
  • 级联复制

不过在,MySQL 自身并没有自动选举和故障转移的功能,需要依赖其他的中间件或架构实现,比如 MMM,MHA,percona,mycat。

主从复制是怎么实现的呢?

3.4 binlog

客户端对 MySQL 数据库进行操作的时候,包括 DDL 和 DML 语句,服务端会在日 志文件中用事件的形式记录所有的操作记录,这个文件就是 binlog 文件(属于逻辑日志, 跟 Redis 的 AOF 文件类似)。Binary log,二进制日志。

基于 binlog,我们可以实现主从复制和数据恢复。

binlog 默认是不开启的,需要在服务端手动配置。注意有一定的性能损耗。

3.4.1 binlog配置

编辑 /etc/my.cnf

1
2
log-bin=/var/lib/mysql/mysql-bin 
server-id=1

重启 MySQL 服务

1
2
3
4
5
service mysqld stop 
service mysqld start
## 如果出错查看日志
vi /var/log/mysqld.log
cd /var/lib/mysql

是否开启 binlog

1
show variables like 'log_bin%';
3.4.2 binlog 格式

STATEMENT:记录每一条修改数据的 SQL 语句(减少日志量,节约 IO)。

ROW:记录哪条数据被修改了,修改成什么样子了(5.7 以后默认)。

MIXED:结合两种方式,一般的语句用 STATEMENT,函数之类的用 ROW。

查看 binlog 格式:

1
show global variables like '%binlog_format%';

Binlog 文件超过一定大小就会产生一个新的,查看 binlog 列表:

1
show binary logs;

大小:

1
show binlog events in 'mysql-bin.000001';

用 mysqlbinlog 工具,基于时间查看 binlog (注意这个是 Linux 命令, 不是 SQL)

1
/usr/bin/mysqlbinlog --start-datetime='2025-08-22 13:30:00' --stop-datetime='2025-08-22 14:01:01' -d gupao /var/lib/mysql/mysql-bin.000001

3.5 主从复制的原理

3.5.1 主从复制配置
  1. 主库开启binlog,设置server-id

  2. 在主库创建具有复制权限的用户,允许从库连接

    1
    2
    GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl'@'10.0.12.77' IDENTIFIED BY '123456';
    FLUSH PRIVILEGES;
  3. 从库配置/etc/my.cnf ,并重启数据库

    1
    2
    3
    4
    5
    server-id=2 
    log-bin=mysql-bin
    relay-log=mysql-relay-bin
    read-only=1
    log-slave-updates=1

    开启log-slave-updates参数后,从库从主库复制的数据会写入从库的log-bin日志文件里,这样可以实现互为主备或者级联复制

  4. 在从库执行

    1
    2
    3
    stop slave;
    change master to master_host='10.0.12.78',master_user='repl',master_password='123456',master_log_file='mysql-bin.00000 1', master_log_pos=4;
    start slave;

5、查看同步状态

1
SHOW SLAVE STATUS \G

Slave_IO_Running 和 Slave SQL Running 都为 yes 为正常。

3.5.2 主从复制原理

这里面涉及到几个线程:

主从复制原理

1、slave 服务器执行 start slave,开启主从复制开关, slave 服务器的 IO 线程请 求从 master 服务器读取 binlog(如果该线程追赶上了主库,会进入睡眠状态)。

2、master 服务器创建 Log Dump 线程,把 binlog 发送给 slave 服务器。slave 服 务器把读取到的 binlog 日志内容写入中继日志 relay log(会记录位置信息,以便下次继 续读取)。

3、slave 服务器的 SQL 线程会实时检测 relay log 中新增的日志内容,把 relay log 解析成 SQL 语句,并执行。

为什么需要 relay log?为什么不把接收到的 binlog 数据直接写入从库?

同步转异步,Relay log 相当于一个中转站,也记录了 master 和 slave 的同步信息。

3.5.3 mycat 读写分离配置

添加:

1
2
3
4
5
6
7
8
<dataHost name="host122" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="10.0.12.72:3306" user="root"
password="123456">
<readHost host="hostS1" url="10.0.12.78:3306" user="root" password="123456" />
</writeHost>
</dataHost>