数据拆分
一个大型系统里各个环节中最容易出性能和可用性问题的往往是数据库,因此分布式设计与开发的一个重要领域就是如何让数据层具有可扩展性,数据库的扩展分为Scale Up 和Scale Out,而Scale Up说白了是通过升级服务器配置来完成,因此不在分布式设计的考虑之内。Scale Out是通过增加机器的方式来提升处理能力,一般需要考虑以下两个问题:
- 数据拆分
- 数据库高可用架构
数据拆分是最先会被想到的,原理很简单,当一个表的数据达到无法处理的时候,就需要把它拆成多个表,说起来简单,真正在项目里运用的时候有很多点是需要深入研究的,一般分为:
- 切分策略
- 与应用程序端的整合策略
切分策略
切分策略一般分为垂直切分、横向切分和两者的混搭。
1)垂直切分
垂直切分就是要把表按模块划分到不同数据库中,这种拆分在大型网站的演变过程中是很常见的。当一个网站还在很小的时候,只有小量的人来开发和维护,各模块和表都在一起,当网站不断丰富和壮大的时候,也会变成多个子系统来支撑,这时就有按模块和功能把表划分出来的需求。如下图所示:
其实,相对于垂直切分更进一步的是服务化改造,说得简单就是要把原来强耦合的系统拆分成多个弱耦合的服务,通过服务间的调用来满足业务需求看,因此表拆出来后要通过服务的形式暴露出去,而不是直接调用不同模块的表,淘宝在架构不断演变过程,最重要的一环就是服务化改造,把用户、交易、店铺、宝贝这些核心的概念抽取成独立的服务,也非常有利于进行局部的优化和治理,保障核心模块的稳定性。这样一种拆分方式也是有代价的:
- 表关联无法在数据库层面做
- 单表大数据量依然存在性能瓶颈
- 事务保证比较复杂
- 应用端的复杂性增加
上面这些问题是显而易见的,处理这些的关键在于如何解除不同模块间的耦合性,这说是技术问题,其实更是业务的设计问题,只有在业务上是松耦合的,才可能在技术设计上隔离开来。没有耦合性,也就不存在表关联和事务的需求。另外,大数据瓶颈问题可以参见下面要将的水平切分。
2)水平切分
上面谈到垂直切分只是把表按模块划分到不同数据库,但没有解决单表大数据量的问题,而水平切分就是要把一个表按照某种规则把数据划分到不同表或数据库里。例如像计费系统,通过按时间来划分表就比较合适,因为系统都是处理某一时间段的数据。而像SaaS应用,通过按用户维度来划分数据比较合适,因为用户与用户之间的隔离的,一般不存在处理多个用户数据的情况,下面是一个比较简单的按user_id来水平切分的例子:
水平切分没有破坏表之间的联系,完全可以把有关系的表放在一个库里,这样就不影响应用端的业务需求,并且这样的切分能从根本上解决大数据量的问题。它的问题也是很明显的:
- 当切分规则复杂时,增加了应用端调用的难度
- 数据维护难度比较大,当拆分规则有变化时,需要对数据进行迁移
对于第一个问题,可以参考后面要讲的如何整合应用端和数据库端。对于第二个问题可以参考一致性hash的算法,通过某些映射策略来降低数据维护的成本
3)垂直与水平联合切分
由上面可知垂直切分能更清晰化模块划分,区分治理,水平切分能解决大数据量性能瓶颈问题,因此常常就会把两者结合使用,这在大型网站里是种常见的策略,这可以结合两者的优点,当然缺点就是比较复杂,成本较高,不太适合小型网站,下面是结合前面两个例子的情况:
与应用程序端的整合策略
数据切出来还只是第一步,关键在于应用端如何方便地存取数据,不能因为数据拆分导致应用端存取数据错误或者异常复杂。按照从前往后一般说来有以下三种策略:
- 应用端做数据库路由
- 在应用端和服务器端加一个代理服务器做路由
- 数据库端自行做路由
1) 应用端做数据库路由
应用端做数据库路由实现起来比较简单,也就是在数据库调用的点通过工具包的处理,给每次调用数据库加上路由信息,也就是分析每次调用,路由到正确的库。这种方式多多少少没有对应用端透明,如果路由策略有更改还需要修改应用端,并且这种更改很难做到动态更改。最关键的是应用端的连接池设计会比较复杂,池里的连接就不是无状态了,不利于管理和扩展。
2)在应用端和服务器端加一个代理服务器做路由
通过代理服务器来做服务器做路由可以对客户端屏蔽后端数据库拆分细节,增强了拆分规则的可维护性,一般而言proxy需要提供以下features:
- 对客户端和数据库服务端的连接管理和安全认证
- 数据库请求路由可配置性
- 对调用命令和SQL的解析
- 调用结果的过滤和合并
现在有些开源框架提供了类似功能,比如ameoba
3)数据库端自行做路由
例如MySQL就提供了MySQL Proxy的代理产品可以在数据库端做路由,结构如下所示:
这种方式的最大问题就是拆分规则配置的灵活性不好,不一定能满足应用端的多种划分需求。