文章目录
1. 分布式全局id概述及引发的问题
- 在创建表的时候我们对主键id都是使用自增,通过这个来唯一区分数据
- 在分库分表的场景中自增id就出现无法解决重复的问题了
- 两条不同的业务数据由于id重复,就会导致查询出错或关联数据有问题
2. 通过UUID实现全局id
- UUID通用唯一识别码
- 缺点:只是一个单纯的id,没有实际意义,长度32位,太长没有顺序对MySQL innoDB引擎的索引组织表及不友好
- MyCat不支持UUID的方式的,Sharding-Jdbc支持UUID的方式
2.1. 在sharding-jdbc中使用UUID进行主键数据的分库
- 创建表
CREATE TABLE `order_content_1` (
`id` varchar(32) NOT NULL,
`order_amount` decimal(10,2) DEFAULT NULL,
`order_status` int(255) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- 配置properties将UUID的列作为数据库的划分方式
我们就需要将inline的规则改成standard的规则,并自己实现standard的分片规则类
# 分库的规则
spring.shardingsphere.sharding.tables.order_content.database-strategy.standard.sharding-column=id
spring.shardingsphere.sharding.tables.order_content.database-strategy.standard.precise-algorithm-class-name=com.icodingedu.config.MyShardingRule
# 分表的规则
spring.shardingsphere.sharding.tables.order_content.table-strategy.standard.sharding-column=id
spring.shardingsphere.sharding.tables.order_content.table-strategy.standard.precise-algorithm-class-name=com.icodingedu.config.MyShardingRule
指定id的生成规则由sharding-jdbc提供
# 指定id的生成规则为UUID,由sharding-jdbc提供
# 如果生命值的写入就会使用写入的而不是UUID
spring.shardingsphere.sharding.tables.order_content.key-generator.column=id
spring.shardingsphere.sharding.tables.order_content.key-generator.type=UUID
分库的自定义类
package com.icodingedu.config;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.util.Collection;
public class MyShardingRule implements PreciseShardingAlgorithm<String> {
@Override
public String doSharding(Collection<String> collection, PreciseShardingValue<String> preciseShardingValue) {
String id = preciseShardingValue.getValue();
int mode = id.hashCode()%collection.size();
mode = Math.abs(mode);
Object [] nodes = collection.toArray();
return nodes[mode].toString();
}
}
3. 通过雪花算法实现全局id
-
SnowFlack是由Twitter提出的分布式ID算法
-
是一个64bit的long型数字
-
引入了时间戳的概念,保持自增
-
SnowFlack数据结构
- 第一位是0固定不变的,表示一个正数,如果是1就是负数了
- 41位的时间戳:当前时间减去你设置的开始时间的毫秒数,开始时间在雪花算法生成里可以设置,最长的时间范围是69年
- 5位的机房id
- 5位的机器id:5位机房和5位机器唯一标识机器的序列,可以配置2的10次方,也就是1024个机器在并发的情况下可以不重复
- 12位的序号:同一时间同一机器并发可以生成2的12次方个序列,也就是说有4096个不同
- 说明雪花支持毫秒级的并发是4096个
-
时间回调会引起重复
你在一开始上线的时候和实际的时间不一致,比实际早,发现后将时间修改就有一定可能导致时间重叠出现重复,重复的几率比较低
-
MyCat和sharding-jdbc都支持雪花算法
-
Sharding-jdbc可以设置最大容忍回调时间,如果超过之后再通过snowflack生成id会抛出异常
3.1. MyCat如何使用雪花生成id
# 0.首先要将id由int修改为bigint
# 1.修改server.xml的配置,修改为2将自动生成的id变更为雪花算法方式
<property name="sequnceHandlerType">2</property>
# 2.设置机房id和机器id
conf下的sequence_time_conf.properties
WORKID=03 #机器id
DATAACENTERID=03 #机房id
# 3.配置表生成的id规则
<table name="order_info" dataNode="dn213,dn214" rule="mod-long" autoIncrement="true" primaryKey="id">
<childTable name="order_item" joinKey="order_id" parentKey="id"/>
</table>
# autoIncrement
# primaryKey
3.2. Sharding-Jdbc实现雪花
# 给两个数据源命名
spring.shardingsphere.datasource.names=ds0,ds1
# 数据源链接ds0要和命名一致
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbcUrl=jdbc:mysql://39.103.163.215:3306/shard_order
spring.shardingsphere.datasource.ds0.username=gavin
spring.shardingsphere.datasource.ds0.password=123456
# 数据源链接ds1要和命名一致
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbcUrl=jdbc:mysql://39.101.221.95:3306/shard_order
spring.shardingsphere.datasource.ds1.username=gavin
spring.shardingsphere.datasource.ds1.password=123456
# 具体的分片规则,基于数据节点
spring.shardingsphere.sharding.tables.order_info.actual-data-nodes=ds$->{0..1}.order_info_$->{1..2}
# 分库的规则
spring.shardingsphere.sharding.tables.order_info.database-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.order_info.database-strategy.inline.algorithm-expression=ds$->{id % 2}
# 分表的规则
spring.shardingsphere.sharding.tables.order_info.table-strategy.inline.sharding-column=user_id
spring.shardingsphere.sharding.tables.order_info.table-strategy.inline.algorithm-expression=order_info_$->{user_id % 2 + 1}
# 设定雪花id
spring.shardingsphere.sharding.tables.order_info.key-generator.column=id
spring.shardingsphere.sharding.tables.order_info.key-generator.type=snowflake
# 这里也需要设置机房id和机器id,两者合并了,是10位,所以不要超过1024
spring.shardingsphere.sharding.tables.order_info.key-generator.props.worker.id=1000
# 最大的时间容忍间隔
spring.shardingsphere.sharding.tables.order_info.key-generator.props.max.tolerate.time.difference.milliseconds=60000