“分库分表" ?选型和流程要慎重,不然会失控

更多文章关注微信公众号《小姐姐味道》 mp.weixin.qq.com/s?__biz=MzA…java

数据库中间件之分库分表

恭喜你,贵公司终于成长到必定规模,须要考虑高可用,甚至分库分表了。但你是否知道分库分表须要哪些要素?拆分过程是复杂的,提早计划,不要等真正开工,各类意外的工做接踵而至,以致失控。mysql

本文意图打开数据库中间件的广度,而不考虑实现深度,至于库表垂直和水平分的概念和原因,不作过多解释。因此此文面向的是有必定研发经验,正在寻找选型和拆分流程的专业人士。sql

切入层次

如下,范围界定在JAVAMySQL中。咱们首先来看一下分库分表切入的层次。 数据库

① 编码层

在同一个项目中建立多个数据源,采用if else的方式,直接根据条件在代码中路由。Spring中有动态切换数据源的抽象类,具体参见 AbstractRoutingDataSource编程

若是项目不是很庞大,使用这种方式可以快速的进行分库。但缺点也是显而易见的,须要编写大量的代码,照顾到每一个分支。当涉及跨库查询、聚合,须要循环计算结果并合并的场景,工做量巨大。后端

若是项目裂变,此类代码大多不能共用,大多经过拷贝共享。久而久之,码将不码。安全

② 框架层

这种状况适合公司ORM框架统一的状况,但在不少状况下不太现实。主要是修改或加强现有ORM框架的功能,在SQL中增长一些自定义原语或者hint来实现。微信

经过实现一些拦截器(好比MybatisInterceptor接口),增长一些自定义解析来控制数据的流向,效果虽然较好,但会改变一些现有的编程经验。架构

不少状况要修改框架源码,不推荐。框架

③ 驱动层

基于在编码层和框架层切入的各类缺点,真正的数据库中间件起码要从驱动层开始。什么意思呢?其实就是从新编写了一个JDBC的驱动,在内存中维护一个路由列表,而后将请求转发到真正的数据库链接中。

TDDLShardingJDBC等,都是在此层切入。

包括Mysql Connector/J的Failover协议 (具体指“load balancing”、“replication”、“farbic”等), 也是直接在驱动上进行修改。

请求流向通常是这样的:

④ 代理层

代理层的数据库中间件,将本身假装成一个数据库,接受业务端的连接。而后负载业务端的请求,解析或者转发到真正的数据库中。

MySQL RouterMyCat等,都是在此层切入。

请求流向通常是这样的:

⑤ 实现层

SQL特殊版本支持,如Mysql cluster自己就支持各类特性,mariadb galera cluster支持对等双主,Greenplum支持分片等。

须要换存储,通常是解决方案,就不在讨论之列了。

技术最终都会趋于一致,选择任何一种、都是可行的。但最终选型,受开发人员熟悉度、社区活跃度、公司切合度、官方维护度、扩展性,以及公司现有的数据库产品等多方位因素影响。选择或开发一款合适的,小伙伴们会幸福不少。

驱动层和代理层对比

经过以上层次描述,很明显,咱们选择或开发中间件,就集中在驱动层和代理层。在这两层,可以对数据库链接和路由进行更强的控制和更细致的管理。但它们的区别也是明显的。

驱动层特色

仅支持JAVA,支持丰富的DB

驱动层中间件仅支持Java一种开发语言,但支持全部后端关系型数据库。若是你的开发语言固定,后端数据源类型丰富,推荐使用此方案。

占用较多的数据库链接

驱动层中间件要维护不少数据库链接。好比一个分了10个 的表,每一个java中的Connection要维护10个数据库链接。若是项目过多,则会出现链接爆炸(咱们算一下,若是每一个项目6个实例,链接池中minIdle等于5,3个项目的链接总数是 10*6*5*3 = 900 个)。像Postgres这种每一个链接对应一个进程的数据库,压力会很大。

数据聚合在业务实例执行

数据聚合,好比count sum等,是经过屡次查询,而后在业务实例的内存中进行聚合。

路由表存在于业务方实例内存中,经过轮询或者被动通知的途径更新路由表便可。

集中式管理

全部集群的配置管理都集中在一个地方,运维负担小,DBA便可完成相关操做。

典型实现

代理层特色

异构支持,DB支持有限

代理层中间件正好相反。仅支持一种后端关系型数据库,但支持多种开发语言。若是你的系统是异构的,而且都有一样的SLA要求,则推荐使用此方案。

运维负担大

代理层须要维护数据库链接数量有限(MySQL Router那种粘性链接除外)。但做为一个独立的服务,既要考虑单独部署,又要考虑高可用,会增长不少额外节点,更别提用了影子节点的公司了。 另外,代理层是请求惟一的入口,稳定性要求极高,一旦有高耗内存的聚合查询把节点搞崩溃了,都是灾难性的事故。

典型实现

共同点

篇幅有限,不作过多讨论。访问各中间件宣传页面,可以看到长长的Feature列表,也就是白名单;也能看到长长的限制列表,也就是黑名单。限定了你怎么玩,在加强了分布式能力后,分库分表自己就是一个阉割的数据库。

使用限制

确保数据均衡 拆分数据库的数据尽可能均匀,好比按省份分user库不均匀,按userid取模会比较均匀 不用深分页 不带切分键的深分页,会取出全部库所取页数以前的全部数据在内存排序计算。容易形成内存溢出。 减小子查询 子查询会形成SQL解析紊乱,解析错误的状况,尽可能减小SQL的子查询。 事务最小原则 尽可能缩小单机事务涉及的库范围,即尽量减小夸库操做,将同类操做的库/表分在一块儿 数据均衡原则 拆分数据库的数据尽可能均匀,好比按省份分user库不均匀,按userid取模会比较均匀 特殊函数 distinct、having、union、in、or等,通常不被支持。或者被支持,使用以后会增长风险,须要改造。

产品

建议聚焦在MyCatShardingJDBC上。另外,还有大量其余的中间件,不熟悉建议不要妄动。 数据库中间件很差维护,你会发现大量半死不活的项目。

如下列表,排名不分前后,有几个是只有HA功能,没有拆分功能的:

Atlas、Kingshard、DBProxy、mysql router、MaxScale、58 Oceanus、ArkProxy、Ctrip DAL、Tsharding、Youtube vitess、网易DDB、Heisenberg、proxysql、Mango、DDAL、Datahekr、MTAtlas、MTDDL、Zebra、Cobar、Cobar

汗、几乎每一个大厂都有本身的数据库中间件(还发现了几个喜欢拿开源组件加公司前缀做为产品的),只不过不给咱用罢了。

流程解决方案

不管是采用哪一个层面切入进行分库分表,都面临如下工做过程。

信息收集

统计影响的业务和项目

项目范围越大,分库难度越高。有时候,一句复杂的SQL可以涉及四五个业务方,这种SQL都是须要重点关注的。

肯定分库分表的规模,是只分其中的几张表,仍是所有涉及。分的越多,工做量越大,几乎是线性的。

还有一些项目是牵一发动全身的。举个例子,下面这个过程,影响的链路就不只是分库这么简单了。

肯定参与人员

除了分库分表组件的技术支持人员,最应该参与的是对系统、对现有代码最熟悉的几我的。只有他们可以肯定哪些SQL该废弃掉、SQL的影响面等。

肯定分库分表策略

肯定分库分表的维度和切分键。切分键(就是路由数据的column)一旦肯定,是不容许修改的,因此在前期架构设计上,应该首先将其确立下来,才能进行后续的工做;数据维度多意味着有不一样的切分键,达到不一样条件查询的效果。这涉及到数据的冗余(多写、数据同步),会更加复杂。

前期准备

数据规整

库表结构不知足需求,须要提早规整。好比,切分键的字段名称不一样或者类型各异。在实施分库分表策略时,这些个性会形成策略过大很差维护。

扫描全部SQL

将项目中全部的SQL扫描出来,逐个判断是否可以按照切分键正常运行。 在判断过程当中确定会有大量不合规的SQL,则都须要给出改造方案,这是主要的工做量之一。

验证工具支持

直接在原有项目上进行改动和验证是可行的,但会遇到诸多问题,主要是效率过低。我倾向于首先设计一些验证工具,输入要验证的SQL或者列表,而后打印路由信息和结果进行判断。

技术准备

建议如下提到的各个点,都找一个例子体验一下,而后根据本身的团队预估难度。

如下: 中间件全部不支持的SQL类型 整理容易形成崩溃的注意事项 不支持的SQL给出处理方式 考虑一个通用的主键生成器 考虑没有切分键的SQL如何处理 考虑定时任务等扫全库的如何进行遍历 考虑跨库跨表查询如何改造 准备一些工具集

实施阶段

数据迁移

分库分表会从新影响数据的分布,不管是全量仍是增量,都会涉及到数据迁移,因此Databus是必要的。

一种理想的状态是全部的增删改都是消息,能够经过订阅MQ进行双写。

但通常状况下,仍然须要去模拟这个状态,好比使用Canal组件。

怎么保证数据安全的切换,咱们分其余章节进行讨论。

充足的测试

分库分表必须通过充足的测试,每一句SQL都要通过严格的验证。若是有单元测试或者自动化测试工具,彻底的覆盖是必要的。一旦有数据进行了错误的路由,尤为是增删改,将会创造大量的麻烦。

在测试阶段,将验证过程输出到单独的日志文件,充足测试后review日志文件是否有错误的数据流向。

SQL复验

强烈建议统一进行一次SQL复验。主要是根据功能描述,肯定SQL的正确性,也就是一般说的review。

演练

在非线上环境屡次对方案进行演练,确保万无一失。

制定新的SQL规范

分库分表之后,项目中的SQL就加了枷锁,不可以随意书写了。不少日常支持的操做,在拆分环境下就可能运行不了了。因此在上线前,涉及的SQL都应该有一个确认过程,即便已经通过了充足的测试。

题外话

没有支持的活别接,干不成。

分库分表是战略性的技术方案,不少状况没法回退或者回退方案复杂。若是要拆分的库表涉及多个业务方,公司技术人员复杂,CTO要亲自挂帅进行协调,并有专业仔细的架构师进行监督。没有受权的协调人员会陷入尴尬的境地,致使流程失控项目难产。

真正经历过的人,会知道它的痛!

相关文章
相关标签/搜索