Mycat分库分表
当线上某张表随着时间推移 数据越来越多时 对mysql的性能和服务器磁盘产生巨大压力
读:old+new
写:new(不写历史库 是因为在partition-range-mod.txt配置中 id区间问题)
JAVA端代码不需要任何改动 只需要搭建新的mysql服务 在使用mycat指向即可
将system_user表进行分库分表的配置demo
schema.xml
使用规则:auto-sharding-rang-mod(见下文 rule.xml)
范围求模分片
先进行范围分片计算出分片组,组内再求模
优点可以避免扩容时的数据迁移,又可以一定程度上避免范围分片的热点问题
综合了范围分片和求模分片的优点,分片组内使用求模可以保证组内数据比较均匀,分片组之间是范围分片
可以兼顾范围查询。
最好事先规划好分片的数量,数据扩容时按分片组扩容,则原有分片组的数据不需要迁移。由于分片组内数
据比较均匀,所以分片组内可以避免热点数据问题
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="BAIDU" checkSQLschema="false" sqlMaxLimit="100000" dataNode="dnHistory">
<table name="system_user" dataNode="dnHistory,dn$1-2"
primaryKey="id" autoIncrement="true" rule="auto-sharding-rang-mod">
</table>
</schema>
<dataNode name="dnHistory" dataHost="datahostHistory" database="mycat" />
<dataNode name="dn1" dataHost="datahost1" database="g1" />
<dataNode name="dn2" dataHost="datahost1" database="g2" />
<dataHost name="datahostHistory" maxCon="10" minCon="2" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="127.0.0.1:3306" user="root" password="19981101">
</writeHost>
</dataHost>
<dataHost name="datahost1" maxCon="10" minCon="2" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="101.101.0.1:3306" user="root"
password="19981101">
</writeHost>
</dataHost>
</mycat:schema>
参照博客:https://www.cnblogs.com/icebutterfly/p/9505624.html
schema标签各属性含义
1. name属性
配置逻辑库的名字(即数据库实例名);
2. dataNode属性
用于配置该逻辑库默认的分片。没有通过table标签配置的表,就会走到默认的分片上。这里注意没有配置在table标签的表,用工具查看是无法显示的,但是可以正常使用。
如果没有配置dataNode属性,则没有配置在table标签的表,是无法使用的。注意,dual表在mycat中,也被视为一个表。
通过mycat建表,而该表并没有提前配置table标签,则mycat会找到默认的dataNode,并把表建在默认的dataNode上。如果没有配置默认dataNode,则mycat报错。
3. checkSQLschema属性
boolean类型。
当执行【select *from BAIDU.system_user;】时(表名前指定了mycat逻辑库名),两种取值:
true:mycat会把语句转换为【select * from system_user;】
false:会报错
4. sqlMaxLimit属性
相当于sql的结果集中,加上【limit N】。如果sql本身已经指定limit,则以sql指定的为准。
table标签各属性含义
1. name属性
逻辑表的表名,同一个schema表名必须唯一。
2. dataNode属性
定义这个逻辑表所属的 dataNode,用英文逗号间隔
3. rule属性
该属性用于指定逻辑表要使用的规则名字,规则名字在 rule.xml 中定义,必须与 tableRule 标签中 name 属性属性值一一对应。
sever.xml
sequnceHandlerType=2 : 本地时间戳方式(配合下文sequence_time_conf.properties文件配置)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<system>
<property name="nonePasswordLogin">0</property>
<property name="useHandshakeV10">1</property>
<property name="useSqlStat">0</property> <!-- 1为开启实时统计、0为关闭 -->
<property name="useGlobleTableCheck">0</property> <!-- 1为开启全加班一致性检测、0为关闭 -->
<property name="sequnceHandlerType">2</property>
<property name="subqueryRelationshipCheck">false</property>
<property name="processorBufferPoolType">0</property>
<property name="handleDistributedTransactions">0</property>
<property name="serverPort">8002</property>
<property name="useOffHeapForMerge">1</property>
<property name="memoryPageSize">64k</property>
<property name="spillsFileBufferSize">1k</property>
<property name="useStreamOutput">0</property>
<property name="systemReserveMemorySize">384m</property>
<property name="useZKSwitch">false</property>
<property name="strictTxIsolation">false</property>
<property name="useZKSwitch">true</property>
</system>
<user name="root" defaultAccount="true">
<property name="password">19981101</property>
<property name="schemas">BAIDU</property>
</user>
<user name="user">
<property name="password">user</property>
<property name="schemas">BAIDU</property>
<property name="readOnly">true</property>
</user>
</mycat:server>
rule.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="rule1">
<rule>
<columns>id</columns>
<algorithm>func1</algorithm>
</rule>
</tableRule>
<tableRule name="rule2">
<rule>
<columns>user_id</columns>
<algorithm>func1</algorithm>
</rule>
</tableRule>
<tableRule name="sharding-by-intfile">
<rule>
<columns>sharding_id</columns>
<algorithm>hash-int</algorithm>
</rule>
</tableRule>
<tableRule name="auto-sharding-long">
<rule>
<columns>id</columns>
<algorithm>rang-long</algorithm>
</rule>
</tableRule>
<tableRule name="mod-long">
<rule>
<columns>id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<tableRule name="sharding-by-murmur">
<rule>
<columns>id</columns>
<algorithm>murmur</algorithm>
</rule>
</tableRule>
<tableRule name="crc32slot">
<rule>
<columns>id</columns>
<algorithm>crc32slot</algorithm>
</rule>
</tableRule>
<tableRule name="sharding-by-month">
<rule>
<columns>create_time</columns>
<algorithm>partbymonth</algorithm>
</rule>
</tableRule>
<tableRule name="latest-month-calldate">
<rule>
<columns>calldate</columns>
<algorithm>latestMonth</algorithm>
</rule>
</tableRule>
<!-- 这里的mod-long对应的就是上面schema.xml的表配置中rule属性所使用的规则名称,其columns节点
指定了当前规则所对应的字段名,也就是id,algorithm节点则指定了当前规则所使用的算法,具体的
算法对应于下面的function节点所指定的实现类-->
<tableRule name="auto-sharding-rang-mod">
<rule>
<columns>id</columns>
<algorithm>rang-mod</algorithm>
</rule>
</tableRule>
<tableRule name="jch">
<rule>
<columns>id</columns>
<algorithm>jump-consistent-hash</algorithm>
</rule>
</tableRule>
<function name="murmur"
class="io.mycat.route.function.PartitionByMurmurHash">
<property name="seed">0</property><!-- 默认是0 -->
<property name="count">2</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
<property name="virtualBucketTimes">160</property>
</function>
<function name="crc32slot"
class="io.mycat.route.function.PartitionByCRC32PreSlot">
</function>
<function name="hash-int"
class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-int.txt</property>
</function>
<function name="rang-long"
class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txt</property>
</function>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">3</property>
</function>
<function name="func1" class="io.mycat.route.function.PartitionByLong">
<property name="partitionCount">8</property>
<property name="partitionLength">128</property>
</function>
<function name="latestMonth"
class="io.mycat.route.function.LatestMonthPartion">
<property name="splitOneDay">24</property>
</function>
<function name="partbymonth"
class="io.mycat.route.function.PartitionByMonth">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2015-01-01</property>
</function>
<function name="rang-mod" class="io.mycat.route.function.PartitionByRangeMod">
<property name="mapFile">partition-range-mod.txt</property>
</function>
<function name="jump-consistent-hash" class="io.mycat.route.function.PartitionByJumpConsistentHash">
<property name="totalBuckets">3</property>
</function>
</mycat:rule>
partition-range-mod.txt
每一行在等号前指定了一个范围,这个范围表示的就是目标分区字段的值将会落在哪个范围内;
等号后面有一个数字,这个数字并不是指数据库节点id,而是当前范围将会占用的数据库节点数目,比如这里的范围0-50384340167内的数据将会被分配到1个数据库节点上(指向老的库dnHistory),而范围50384340167-9223372036854775807内的数据将会被分配到2个数据库节点上(指向两个新库dn1、dn2);
等号后面指定了当前范围所需要使用的分片数,而该范围的数据在这几个数据库节点的分布方式是通过取模的方式来实现的,也就是说,在大的方向上,整体数据被切分为多个范围,然后在每个范围内,数据根据取模的方式分配到不同的数据节点上。
# range start-end ,data node group size
0-50384340167=1
50384340167-9223372036854775807=2
sequence_time_conf.properties
线上采用的是mycat集群+haproxy集群+Keepalived实现高可用
使用mycat集群时,确保每个节点下面的不同
#sequence depend on TIME
WORKID=02
DATAACENTERID=02