分片策略
垂直分片
将同一个功能模块的表切分到不同的数据库中,查询的时候比较方便,分片也比较简单。适用场景:表比较多,但是每张表的数据量不多。
水平分片
将每张表的内容水平分开,根据相应地策略分到不同的数据库中(比如按照id取余),这样在查询的需要借助数据库中间件来联合查询。但是当你获得到根ID后,可以按照id的规则计算出这个根数据所存储的数据库,再到相应地数据库查询详细信息。这样分片比较复杂,而且查询也比较麻烦。适用场景:表比较少,但是每张表的数据量比较大。
垂直分片+水平分片
这种联合分片规则是最常用的,因为复杂的系统往往即有非常多的表,也有某些表的数据量超大。这样就需要我们先对数据库按照功能模块进行垂直分片,再对需要水平分片的表进行水平分片。
主键
分片后的数据要求主键唯一性,就不能依赖数据库的主键自增长了,需要我们维护一套主键系统。
- 可以适用uuid来保证唯一性,优点是:生成非常方便。缺点:uuid非常长,对于数据量比较大得表,非常占资源,也占索引。
- 可以在每台服务器上面创建一张Sequence表记录每张分片表的最后插入ID。然后根据数据库的集群个数,给每个数据库设置一个编号,在insert的时候,随机从所有集群数据库中获取这张表中对应的ID然后加上数据库的编号,即为要插入的id,同时更新Sequence表中分片表的id为下次insert做准备(要保证事务原子性)。
- 也可以利用缓存:Redis、Memcached来将每张表的主键缓存起来,每次insert的时候+1.
MYCAT示例
去mycat官方下载1.6RELEASE版本,并解压。
server配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<system>
<!--分布式事务开关,0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但是记录分布式事务日志-->
<property name="handleDistributedTransactions">0</property>
<property name="serverPort">8066</property>
</system>
<user name="root">
<property name="password"></property>
<property name="schemas">test</property>
</user>
</mycat:server>
schema配置
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="test" checkSQLschema="true" sqlMaxLimit="100">
<table name="User" primaryKey="id" dataNode="dn1,dn2,dn3" rule="mod-long" />
</schema>
<dataNode name="dn1" dataHost="localhost1" database="test"/>
<dataNode name="dn2" dataHost="localhost1" database="or_test"/>
<dataNode name="dn3" dataHost="localhost1" database="bdkcf"/>
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select 1</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="localhost:3306" user="root"
password="">
<!-- can have multi read hosts -->
<readHost host="hostS2" url="localhost:3306" user="root" password="" />
</writeHost>
</dataHost>
</mycat:schema>
这里采用取摸分片。
启动
进入mycat bin目录下启动mycat:./mycat console 前台运行。
分片规则
- mod-long 对id进行取摸运算。优点:数据分布均匀。缺点:进行缩容扩容的时候需要对所有数据进行迁移。
- sharding-by-murmur 一致性hash运算。优点:mycat原生支持数据迁移。且不需要对所有数据进行迁移,只需要迁移某一个库的数据。缺点:数据分布相对不太均匀。
数据库连接
spring:
datasource:
name: test
url: jdbc:mysql://127.0.0.1:8066/test
username: root
password:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
主键生成
配合redis使用,每次启动服务的时候,去数据库查询要分片的表最后一条ID,存入redis中。table:xx:id
-> id。每次新增的时候从redis中获取该表的id,然后+1返回并重置redis的value。这是一种比较简单的方法,当然也可以采用主键生成框架来做这件事。