相关文章:

  • 自己动手写一个分库分表中间件(一)
  • 排查项目中读写分离失效原因

分库分表最核心的功能是数据源路由。首先要确定怎么样算是一个数据源。

数据源定义

选择自研就是为了更适配我们的业务,在上一篇文章《自己动手写一个分库分表中间件(一)》中介绍了我们业务特有的数据源定义:

业务1(master+slave+report)/业务2(master+slave+report)/业务3(master+slave+report)

在这里 master、slave、report 从 DataSource 的角度是不同的数据源,从 MySQL 的角度,master 就是主库,slave 和 report 都是从库;业务目前是根据订单号按照年份划分的。

在分库分表之前我们一般是这么使用:我们会为 master、slave、report 配置三套数据源配置(包括 DataSourceSqlSessionFactoryMapperTransactionManager 等),开发人员根据当前的业务场景一般查询走从库、更新和对数据实时性要求高的场景走主库、报表功能走 report 库)去选择使用对应的 Mapper 操作即可。

所以在分库分表的设计中,数据源由三部分构成:

business(业务)+model(数据库类型,固定 master/slave/report)+分表

物理上的数据源数量= business 数量 * model 数量(固定 3),但是逻辑上的数据源数量= business 数量 * model 数量(固定 3)* 分表数量。

实际开发的时候研发同学需要关心 business 和 model:

  1. 根据业务场景设置当前数据路由的 model
  2. 如果当前 SQL 带有路由标识(目前仅支持订单号),那么指定该字段为路由标识后框架底层会根据开发人员实现的规则自动匹配 business 和表路由
  3. 真正跟路由相关的是 business 和分表,model 是我们的业务读写分离场景

缺省数据源

这里再谈谈数据源的缺省值问题。

缺省分表

其实分表没有必要缺省,分表路由强依赖路由字段。

如果指定了路由字段,那么可以根据路由字段直接精准定位出 business 和分表;如果没有路由字段,是不支持绕开 business 直接指定分表的。因为物理上 business+model 才是一个数据源,物理上的表是要落在一个具体的库上的,绕开库直接指定表,这个就会显得很奇怪。

缺省 business

在上一篇文章《自己动手写一个分库分表中间件(一)》中谈到底层中间件主要要为业务服务,而且我们的业务大多数场景其实都是在操作特定的某个业务,所以这个业务就作为缺省数据源即可,由于缺省数据源这个配置很简单,多一个配置无伤大雅,所以中间件可以提供一个缺省的数据源配置项

缺省 model

在上文中提到我们的系统目前已经为 master、slave、report 提供了不同的 Mapper, 所以分库分表环境中研发人员也需要指定 model。

最开始我设想的是在事务环境下缺省 master,非事务环境下 slave,但是这个设想很快就否决了,因为这里的“事务环境”其实指的是 Spring 的 @Transactional 包裹的环境,如果历史代码中有单个的 update 操作没有加 @Transactional(也没必要),此时“事务环境”的判断就会失效,就会造成 update 操作跑到 slave 库去了,这个是肯定不行的,所以缺省 model 是 master 没毛病。

还有一个点是,我们期望的肯定是常规业务读都到 slave,写都到 mater。历史代码啥都没加那不是会造成压力都到 master 库了嘛,接下来就谈谈在本次分库分表中间件中的数据分片代理层。

静态数据分片代理层

先解释一下分片代理层在项目开发中的分层位置,之前我们项目开发都是:

Controller->Service->Mapper

但是这次改造后会变成:

Controller->Service->MapperProxy->Mapper

所以中间件会提供一个配置 Proxy 层 package 的配置,当然也支持直接配置到 mapper 的 package,但是我们是建议增加一个 Proxy 层的,虽然 Proxy 层的存在可能会增加一点点的代码量。

这里再谈一下为什么会有一个 Proxy 层。

事务聚合

这个其实跟分库分表关系不大。平时我们经常会有一个更新操作要同时更新多个表的场景,此时同时更新多个表这个操作肯定要放在一个事务中,比如这样:

@Service
public UserService{@ResourceUserMapper userMapper;@ResourceAddressMapper addressMapper;public int saveUser(User user){userMapper.select(..)addressMapper.select(..)userMapper.insert(..);addressMapper.insert(..);}}

这里两个 insert 肯定要放在一个事务中,但是事务加在 saveUser 方法上是不太合适的,这样会让事务粒度过大,此时两个 insert 操作就可以合并成一个事务方法放在 Proxy 层。

读写分离

在 Sharding-JDBC 的读写分离中设计的是写操作就是主库,读操作默认从库。这样设计对研发人员来说的确是更方便。但是也会造成研发人员过于忽视了“什么场景该读主,什么场景下该读从”,我们就曾出现过并发场景下由于查询的从库造成分布式锁失效,从而引发线上问题的场景。

当然上面这个观点属于仁者见仁。这里 Proxy 层还有一个作用是适配之前项目的使用习惯,之前我们系统读写分离是这么用的:

  1. master 一套 Mapper,slave 一套 Mapper,想用哪个就用对应的 Mapper 即可,缺陷就是数据源配置麻烦点(SqlSessionFactoryTransactionManager 都要配置多套),部分 master 和 slave Mapper 都要用的 SQL 要写两遍;
  2. 基于注解的方式,Mapper 和数据源配置都只有一套,对外提供两个方法,比如 selectFromMasterselectFromSlave,其实两个方法内部都是调用的同一个 Mapper 的同一个方法,只是加的注解不一样;

这里的 Proxy 层也是这个作用。

定义数据路由

Proxy 层最主要的作用就是在这一层去指定数据路由。

在上一篇文章《自己动手写一个分库分表中间件(一)》中介绍过我们系统其实大部分操作都在“某个业务”中,我们更需要的是“写+从读+报表读”的数据应用分离的场景,此时我们更多的场景是手动指定数据路由(或者根据路由键),这里跟 Sharding-JDBC 中的数据分片是有略微差异的,也就是说我们可能手动的场景比较多(虽然有缺省机制,手动非必要)。

既然有手动的场景那肯定是希望所有对数据路由的指定都统一放在这一层来做(虽然中间件提供的大部分路由能力并没有严格限制只能在 Proxy 层生效),避免混用,或者指定路由粒度过大等场景。

抛开分库分表,中间件能力混用和粒度控制问题其实在平时开发中很常见,最经典的比如 Spring 中 this 调用事务失效的问题,还有比如之前分享的《排查项目中读写分离失效原因》,就是因为读写分离注解和事务注解的粒度控制问题导致的。

最后

已经到《自己动手写一个分库分表中间件》系列的第二篇的结尾了,却还没有提到任何代码,还是在“空谈”设计,感觉有点小小的尴尬。其实我个人也非常讨厌 talk 一堆,but not any code,但的确这就是个人在 coding 中的一些感想和感悟。其实分库分表写起来真的不难,关键是怎么让使用者 0 学习成本,更容易理解,真正做到只用关注业务逻辑,这里面就需要一些相应的思考。

下一篇会开始展示代码,介绍分库分表中间件最主要(但不是最麻烦)的功能:数据路由的具体实现。

欢迎关注公众号:

自己动手写一个分库分表中间件(二)数据源定义和分片代理层设计相关推荐

  1. 自己动手写一个分库分表中间件(三)数据源路由实现

    相关文章: 自己动手写一个分库分表中间件(一)思考 自己动手写一个分库分表中间件(二)数据源定义和分片代理层设计 排查项目中读写分离失效原因 小议 Java 内省机制 注:本文内容暂不涉及事务相关的问 ...

  2. 分享下去年底写的分库分表中间件heisenberg

    好久没有写博了,去年年底的时候写了一个分库分表中间件服务器,当时正在看绝命毒师,觉得heisenberg这个名字很叼,然后就以这个命名了,炼毒也要精益求精啊... 公司在java分布式这块的基础设施很 ...

  3. 去年底写的mysql分库分表中间件heisenberg

    好久没有写博了,去年年底的时候写了一个分库分表中间件服务器,当时正在看绝命毒师,觉得heisenberg这个名字很叼,然后就以这个命名了,炼毒也要精益求精啊... 公司在java分布式这块的基础设施很 ...

  4. 【数据库与事务系列】分库分表中间件

    前面讲了利用mybatis插件进行多数据源切换和分表的方案,但是对业务侵入性较强,当然给予mybatis-plus的对业务侵入性还好,但是支持的策略有限.场景有限. 所以业界诞生了很多分库分表中间件来 ...

  5. 一文快速入门分库分表中间件 Sharding-JDBC (必修课)

    书接上文 <一文快速入门分库分表(必修课)>,这篇拖了好长的时间,本来计划在一周前就该写完的,结果家庭内部突然人事调整,领导层进行权利交接,随之宣布我正式当爹,紧接着家庭地位滑落至第三名, ...

  6. 一文快速入门分库分表中间件 Sharding-JDBC

    一.Sharding-JDBC 简介 Sharding-JDBC 最早是当当网内部使用的一款分库分表框架,到2017年的时候才开始对外开源,这几年在大量社区贡献者的不断迭代下,功能也逐渐完善,现已更名 ...

  7. 【Sharding-JDBC系列二】一文快速入门分库分表中间件 Sharding-JDBC (必修课)

    作为Sharding-JDBC 分库分表实战系列的开篇文章,我们在前文中回顾了一下分库分表的基础知识,对分库分表的拆分方式有了一定的了解,下边我们介绍一下 Sharding-JDBC框架和快速的搭建一 ...

  8. 关系型数据库分库分表中间件之选型

    写在前面 本文主要介绍关系型数据库分库分表的中间件,主要包含中间件介绍.选项及其对比.虽然市面上很多分库分表中间件,但是大多数都是不友好或者社区活跃度不高的项目,当然还是有很多淘汰的中间件.目前,在实 ...

  9. 数据库分库分表中间件对比(很全)

    数据库(分库分表)中间件对比 分区:对业务透明,分区只不过把存放数据的文件分成了许多小块,例如mysql中的一张表对应三个文件.MYD,MYI,frm. 根据一定的规则把数据文件(MYD)和索引文件( ...

  10. 支付宝分库分表中间件--zdal简介

    中间件, 如果仅仅作为一名用户的话, 主要关注一下如何使用即可, 大多数情况下也就是配置. 下面简单的介绍一下支付宝的分库分表中间件--->zdal在web项目中的配置. 1, 在网上查阅相关资 ...

最新文章

  1. 关于Access数据库执行Update语句后,不报错,但影响行数总是返回0的问题
  2. 使用 Bundle在Activity间传递数据
  3. python web为什么不火-Python这么火,为何有人说Python不好找工作?
  4. 使用 Servlet 读取表单数据
  5. android 请求权限失败怎么办,java – Android HTTP POST请求错误 – 套接字失败EACCES(权限被拒绝)...
  6. yolo_model to output理解
  7. arm-linux 交叉编译后程序,ARM交叉编译下,应用程序实践
  8. 网易云首届渠道大会:多媒体通信助力互联网+
  9. MyEclipse中消除frame引起的“the file XXX can not be found.Please check the location and try again.”的错误...
  10. 全面解析resultType和resultMap的区别
  11. Scrum指南更新:Ken Schwaber、Jeff Sutherland访谈
  12. Unity打开的文件是杂项文件的处理方法
  13. Android.mk入门(一)
  14. 分享一些C语言的学习资料
  15. 文本编辑器Typora软件免费版本下载及其用法
  16. AtCoder Beginner Contest 175 A Rainy Season 字符串+5种情况
  17. PS不能拖入图片进去
  18. 网络安全工程师的入门学习的路径
  19. 深度学习上采样下采样概念以及实现
  20. 华视100UC 身份证阅读器 Java

热门文章

  1. 华为云UGO正式亮相DTCC 2021,去“O”从此再无后顾之忧
  2. 14、CSS渲染:CSS是如何绘制颜色的?
  3. python绘制单线图_教你快速利用CAD绘制管道单线图.pdf
  4. cartographer基于3d地图的纯定位模式
  5. Exp2_固件程序设计 20165226_20165310_20165315
  6. linux查看字体并安装字体
  7. mysql输出九九乘法表_SQL 打印九九乘法表
  8. 华为U9508一键root
  9. (转)JS事件循环和宏任务和微任务
  10. 使用adb安装apk报错:INSTALL_FAILED_INVALID_URI