“分库分表” ?选型和流程要慎重,否则会失控

数据库中间件之分库分表

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

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

切入层次

以下,范围界定在JAVA和MySQL中。我们首先来看一下分库分表切入的层次。

1、编码层

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

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

如果项目裂变,此类代码大多不能共用,大多通过拷贝共享。长此以往,码将不码。

2、框架层

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

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

很多情况要修改框架源码,不推荐。

3、驱动层

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

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

请求流向一般是这样的:

4、代理层

代理层的数据库中间件,将自己伪装成一个数据库,接受业务端的链接。然后负载业务端的请求,解析或者转发到真正的数据库中。像MySQL Router、MyCat等,都是在此层切入。

请求流向一般是这样的:

5、实现层

SQL特殊版本支持,如Mysql cluster本身就支持各种特性,mariadb galera cluster支持对等双主,Greenplum支持分片等。需要换存储,一般是解决方案,就不在讨论之列了。

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

驱动层和代理层对比

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

1、驱动层特点

仅支持JAVA,支持丰富的DB

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

占用较多的数据库连接

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

数据聚合在业务实例执行

数据聚合,比如count sum等,是通过多次查询,然后在业务实例的内存中进行聚合。路由表存在于业务方实例内存中,通过轮询或者被动通知的途径更新路由表即可。

集中式管理

所有集群的配置管理都集中在一个地方,运维负担小,DBA即可完成相关操作。

典型实现

2、代理层特点

异构支持,DB支持有限

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

运维负担大

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

典型实现

共同点

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

使用限制

确保数据均衡 拆分数据库的数据尽量均匀,比如按省份分user库不均匀,按userid取模会比较均匀
不用深分页 不带切分键的深分页,会取出所有库所取页数之前的所有数据在内存排序计算。容易造成内存溢出。

减少子查询 子查询会造成SQL解析紊乱,解析错误的情况,尽量减少SQL的子查询。
事务最小原则 尽量缩小单机事务涉及的库范围,即尽可能减少夸库操作,将同类操作的库/表分在一起

数据均衡原则 拆分数据库的数据尽量均匀,比如按省份分user库不均匀,按userid取模会比较均匀
特殊函数 distinct、having、union、in、or等,一般不被支持。或者被支持,使用之后会增加风险,需要改造。

产品

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

以下列表,排名不分先后,有几个是只有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、几乎每个大厂都有自己的数据库中间件(还发现了几个喜欢拿开源组件加公司前缀作为产品的),只不过不给咱用罢了。

流程解决方案

无论是采用哪个层面切入进行分库分表,都面临以下工作过程。

信息收集

1、统计影响的业务和项目

项目范围越大,分库难度越高。有时候,一句复杂的SQL能够涉及四五个业务方,这种SQL都是需要重点关注的。确定分库分表的规模,是只分其中的几张表,还是全部涉及。分的越多,工作量越大,几乎是线性的。

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

2、确定参与人员

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

3、确定分库分表策略

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

4、前期准备

数据规整

库表结构不满足需求,需要提前规整。比如,切分键的字段名称不同或者类型各异。在实施分库分表策略时,这些个性会造成策略过大不好维护。

扫描所有SQL

将项目中所有的SQL扫描出来,逐个判断是否能够按照切分键正常运行。在判断过程中肯定会有大量不合规的SQL,则都需要给出改造方案,这是主要的工作量之一。

验证工具支持

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

技术准备

建议以下提到的各个点,都找一个例子体验一下,然后根据自己的团队预估难度。

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

5、实施阶段

数据迁移

分库分表会重新影响数据的分布,无论是全量还是增量,都会涉及到数据迁移,所以Databus是必要的。一种理想的状态是所有的增删改都是消息,可以通过订阅MQ进行双写。

但一般情况下,仍然需要去模拟这个状态,比如使用Canal组件。

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

充足的测试

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

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

SQL复验

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

演练

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

制定新的SQL规范

分库分表以后,项目中的SQL就加了枷锁,不能够随意书写了。很多平常支持的操作,在拆分环境下就可能运行不了了。所以在上线前,涉及的SQL都应该有一个确认过程,即使已经经过了充足的测试。

6、题外话

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

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

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

本文转载自小姐姐味道。

Image placeholder
fireqong
未设置
  79人点赞

没有讨论,发表一下自己的看法吧

推荐文章
数据库分库分表解决方案汇总

一.数据切分关系型数据库本身比较容易成为系统瓶颈,单机存储容量、连接数、处理能力都有限。当单表的数据量达到1000W或100G以后,由于查询维度较多,即使添加从库、优化索引,做很多操作时性能仍下降严重

分库分表就能无限扩容吗,解释得太好了!

像我这样的菜鸟,总会有各种疑问,刚开始是对JDKAPI的疑问,对NIO的疑问,对JVM的疑问,当工作几年后,对服务的可用性,可扩展性也有了新的疑问,什么疑问呢?其实是老生常谈的话题:服务的扩容问题。正

JavaScript的运算符和流程控制笔记

"usestrict""usestrict""usestrict"严格模式

三个月5位老员工离职!苹果健康团队被曝内部分歧严重,员工扎堆儿离开

大数据文摘编辑部出品一年一度的秋季发布会召开前夕,苹果健康团队忽然被曝,大批老员工高调离职。据外媒CNBC报道,最近几个月,苹果的医疗保健团队紧张氛围愈加严重,这种氛围据内部人士称已经持续了一段时间,

炸!业界难题,跨库分页的几种常见方案

为什么需要研究跨库分页?互联网很多业务都有分页拉取数据的需求,例如:(1)微信消息过多时,拉取第N页消息;(2)京东下单过多时,拉取第N页订单;(3)浏览58同城,查看第N页帖子;这些业务场景对应的消

千万不要和女程序员做同事!否则你会爱上她

如果说,每个程序员都是格子衫的化身,那么,每个女程序员,早已不需要格子衫作为职业铠甲。随身带电脑是必修课,手机装VPN是安全感,写Bug时要风轻云淡,打断点就要像打粉底。我,一枚长期浸淫在IT圈、敲代

JS 中一定要了解的数据类型和数据转换

数据类型 前言 Js中的类型只有6种,其中基本数据类型有5种分别为string,number,boolen,null,undefined,引用类型有一种,就是object,object是一个大的综合

JS 中一定要了解的数据类型和数据转换

Js数据类型 前言 Js中的类型只有6种,其中基本数据类型有5种分别为string,number,boolen,null,undefined,引用类型有一种,就是object,object是一个大的

关于企业数字化转型和AI应用的5个建议

波士顿咨询公司(BostonConsultingGroup)表示,企业对数字化转型和人工智能抱有很高的期望,但也面临着一些挑战。许多企业正在迎来第一波数字化转型浪潮,在扩大覆盖面和定制化、改进流程、提

小米办公Wi-Fi选型最看重什么?

以“体验智能边缘,尽享无限商机”为主题的Aruba中国第一届合作伙伴大会暨InstantOn新品发布会在京举行。会上,Aruba分享了最新的技术和产品信息,以及行业解决方案。小米作为Aruba成功案例

企业备份软件选型指南:这三点是必关注项

企业备份软件,简单来说可以将数据和应用程序从主存储平台转移到二级存储。过去,磁带和磁盘常被用作二级存储媒介。如今,越来越多的供应商也把支持公有云存储作为一项长期战略。在现代IT实践中,备份工具已经从仅

多场景数据库如何选型?五位大咖这样说!

2019年5月9日,第十届中国数据库技术大会(DTCC2019)作为国内顶级的数据领域技术盛会,在第二天主会场上迎来了五位大咖,他们分别从开源数据库、数据仓库架构、数据库一体机、电商数据库架构、Ora

中国联通容器化之路及选型标准

“容器”的概念灵感来源于集装箱,有了集装箱,货物不会杂乱无章地堆放在一起,易于管理,也方便运输。容器技术也被称为轻量化虚拟化技术,与集装箱的作用相似。相比前网红虚拟机,容器技术凭借其轻量化、快速部署以

爱奇艺的数据库选型大法,实用不纠结!

来源:rrd.me/fgGsG我们进行数据库选型的时候要考虑哪些问题?有哪些需求?待选用的数据库是否和需求对得上?是不是直接可以拿来用?需不需要一些额外的开发?这些都会在本文的分享中提及。一、数据库技

sharding sphere 4.0.0-RC1版本 按年分表实战

1.shardingsphere4.0.0-RC1版本按年分表实战1.1.需求需要对日志表进行按时间划分表,由于用于后台系统,日志量预估不会太大,因此按年划分表经过我不断的查阅shardingsphe

百亿级数据分表后怎么分页查询?

推荐课程:PHP开发工程师--学习猿地精品课程 当业务规模达到一定规模之后,像淘宝日订单量在5000万单以上,美团3000万单以上。数据库面对海量的数据压力,分库分表就是必须进行的操作了。而分库分表之

玩转 GitHub Actions,简化 npm 发布流程

Github最近添加了一项名为GithubActions的新功能,为我们带来了一套强大的工作流系统,可以处理各种各样的任务。我们在发布Node.js包时可以使用Actions自动运行测试,然后自动将

02.3. 流程和函数

这小节我们要介绍Go里面的流程控制以及函数操作。 流程控制 流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的流程描述来表达很复杂的逻辑。Go中流程控制分三大类:条件判断,循环控制和

Python入门教程_4. 深入 Python 流程控制

除了刚刚介绍的while语句,Python还有一些在其他语言中常见的控制流语句,并做了一些改动。 4.1.if语句 也许最著名的语句是if语句了。 例如: >>>x=int(input("Please

从0到1,马蜂窝大交通团队如何构建高效研发流程体系?

“旅游之前,先上马蜂窝”已经成为许多人习惯性的选择。2019年5月,马蜂窝完成了新一轮融资,金额达2.5亿美元。这也标志着通过集内容、社区、交易为一体的消费决策场景构建,从攻略社区起家的马蜂窝开始迈入

老焦专栏 | 用 RACI 模式梳理业务流程,提高业务发布的效率

转载本文需注明出处:微信公众号EAWorld,违者必究。最近经常在不同场合说,技术发展已经进入深水区。IT技术发展已经越来越成熟了,尤其在金融行业,以前是解决从无到有的问题,现在该有的系统都有了,是解

为什么说IPA智能流程自动化是企业IT的下一波浪潮?

提到IPA,可能很多人会立刻想到RPA。RPA,即机器人流程自动化,是企业IT过去两年最热门的技术之一。仅在2018年,就有三家公司拿到了总额超过十亿美金的风投,包括AnywhereAutomatio

流程控制 if

流程控制:对计算机执行代码的管控。分类:顺序、分支、循环循序结构是系统默认自发从上而下执行。分支结构:单项分支(if...)当条件表达式为真,则执行代码组中的内容,为假则跳过。双向分支(if...el

流程控制 for、while

循环结构while循环执行结束后会回到while的位置,如果没有设定结束条件,会一直循环到资源耗尽。【死循环】为while循环设定一个结束条件使之变为带有计数格式的循环,当条件达到跳出循环。 for循