2. 分库分表一些概念&基础设置
本文章大部分内容来自官网https://shardingsphere.apache.org/document/current/cn/features/sharding/
垂直分片
按照业务拆分的方式称为垂直分片,又称为纵向拆分,它的核心理念是专库专用。 在拆分之前,一个数据库由多个数据表构成,每个表对应着不同的业务。而拆分之后,则是按照业务将表进行归类,分布到不同的数据库中,从而将压力分散至不同的数据库。 下图展示了根据业务需要,将用户表和订单表垂直分片到不同的数据库的方案。

垂直分片往往需要对架构和设计进行调整。通常来讲,是来不及应对互联网业务需求快速变化的;而且,它也并无法真正的解决单点瓶颈。 垂直拆分可以缓解数据量和访问量带来的问题,但无法根治。如果垂直拆分之后,表中的数据量依然超过单节点所能承载的阈值,则需要水平分片来进一步处理。
水平分片
水平分片又称为横向拆分。 相对于垂直分片,它不再将数据根据业务逻辑分类,而是通过某个字段(或某几个字段),根据某种规则将数据分散至多个库或表中,每个分片仅包含数据的一部分。 例如:根据主键分片,偶数主键的记录放入0库(或表),奇数主键的记录放入1库(或表),如下图所示。

水平分片从理论上突破了单机数据量处理的瓶颈,并且扩展相对自由,是分库分表的标准解决方案。
挑战
虽然数据分片解决了性能、可用性以及单点备份恢复等问题,但分布式的架构在获得了收益的同时,也引入了新的问题。
面对如此散乱的分库分表之后的数据,应用开发工程师和数据库管理员对数据库的操作变得异常繁重就是其中的重要挑战之一。他们需要知道数据需要从哪个具体的数据库的分表中获取。
另一个挑战则是,能够正确的运行在单节点数据库中的SQL,在分片之后的数据库中并不一定能够正确运行。例如,分表导致表名称的修改,或者分页、排序、聚合分组等操作的不正确处理。
跨库事务也是分布式的数据库集群要面对的棘手事情。 合理采用分表,可以在降低单表数据量的情况下,尽量使用本地事务,善于使用同库不同表可有效避免分布式事务带来的麻烦。 在不能避免跨库事务的场景,有些业务仍然需要保持事务的一致性。 而基于XA的分布式事务由于在并发度高的场景中性能无法满足需要,并未被互联网巨头大规模使用,他们大多采用最终一致性的柔性事务代替强一致事务。
涉及到的技术,版本
Sharding-jdbc最好和我的保持一致,其他的可以不一样。
技术 | 版本 |
---|---|
Sharding-jdbc | 4.0.0-RC1 |
mybatis-plus | 3.3.1.tmp |
HikariCP | 3.4.2 |
SpringBoot | 2.2.7 |
easy | 0.0.1-SNAPSHOT |
其中easy是自己在日常开发中总结的一个工具包,一个注解处理java8LocalDateTime格式化问题,SpringMVC统一异常处理,参数校验配置等等工具类项目地址:https://github.com/xiao-ren-wu/easy
约定
逻辑库&逻辑表
Sharding-jdbc提供了逻辑表和逻辑库的概念,供开发人员使用,如图

该示例中,将数据库进行水平拆分,分为db0和db1,又分别对表进行了水平拆分,分别是db0里面的table0,table1和db1里面的table0和table1,他们对应的逻辑库为db,对应的逻辑表为table,逻辑库和逻辑表是抽象出来的,不是真实存在的,逻辑表的结构和物理表的结构一致,这样,开发人员只需要关心具体的业务逻辑,而不需要关系复杂的分库分表。
配置方式
sharing-jdbc给我们提供了四种配置分库分表的形式,分别是硬编码形式,SpringXML配置,yaml配置文件形式,和springboot配置文件形式。
参照官网:https://shardingsphere.apache.org/document/current/cn/manual/sharding-jdbc/configuration/
我比较喜欢使用yaml配置文件的形式,因为我认为这样不会给spingboot 配置文件造成”污染“,还能达到‘专人专用“的效果,缺点也很明显,就是不能使用springboot提供的配置提示功能,不过没关系。
为了方便配置文件的使用,我这做了一个简单的约定,并编写了一个简答的工具类
约定
Yaml文件约定存放位置及其路径

resource资源目录下的sharding文件夹,名字为dataSource-${spring.profile.active}.yml
读取配置文件类
@Component
public class ShardingDataSourceYamlConfig {
private static final String SHARDING_FILE_NAME = "sharding/dataSource";
private static final String SUFFIX = ".yml";
private static final String WORD_SPLIT = "-";
@Resource
private ConfigurableEnvironment configurableEnvironment;
/**
* 根据spring-profile-active找到合适的sharding-jdbc配置文件
*
* @return sharding-jdbc config File
* @throws FileNotFoundException FileNotFoundException
* @throws FileAlreadyExistsException FileAlreadyExistsException
*/
public File getShardingFileByProfileActive() throws FileNotFoundException, FileAlreadyExistsException {
// 获取classpath
String classPath = Objects.requireNonNull(ClassLoader.getSystemClassLoader().getResource("")).getPath();
// 获取所有环境
String[] profiles = configurableEnvironment.getActiveProfiles();
if (profiles.length == 0) {
// default profile
String shardingConfigFileName = String.format("%s%s%s", classPath, SHARDING_FILE_NAME, SUFFIX);
File defaultShardingFile = new File(shardingConfigFileName);
if (!defaultShardingFile.exists()) {
throw new FileNotFoundException(shardingConfigFileName);
}
return defaultShardingFile;
} else {
// 如果存在多个符合的配置文件,因为他没有上下级的关系,所以无法进行归并,这里采用报错的形式返回
File profileShardingFile = null;
for (String profile : profiles) {
// 构建文件地址
String shardingConfigFileName = String.format("%s%s%s%s%s", classPath, SHARDING_FILE_NAME, WORD_SPLIT, profile, SUFFIX);
File file = new File(shardingConfigFileName);
if (file.exists()) {
if (Objects.isNull(profileShardingFile)) {
profileShardingFile = file;
} else {
// 出现多个符合条件的配置文件,抛异常
throw new FileAlreadyExistsException("Sharding-jdbc配置文件找到多个");
}
}
}
if (Objects.isNull(profileShardingFile)) {
throw new FileNotFoundException("没有找到Sharding-jdbc配置文件");
}
return profileShardingFile;
}
}
}
准备好这些,我们就可以进行整合了。