数据库系列(三) 垂直拆分 水平拆分

当我们使用读写分离、缓存后,数据库的压力还是很大的时候,这就需要使用到数据库拆分了。

数据库拆分简单来说,就是指通过某种特定的条件,按照某个维度,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面以达到分散单库(主机)负载的效果。

切分模式: 垂直(纵向)拆分、水平拆分。

 

垂直拆分

专库专用

一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,分布到不同的数据库上面,这样也就将数据或者说压力分担到不同的库上面,如下图:

img

优点:

1. 拆分后业务清晰,拆分规则明确。

2. 系统之间整合或扩展容易。

3. 数据维护简单。

缺点:

1. 部分业务表无法join,只能通过接口方式解决,提高了系统复杂度。

2. 受每种业务不同的限制存在单库性能瓶颈,不易数据扩展跟性能提高。

3. 事务处理复杂。

 

水平拆分

垂直拆分后遇到单机瓶颈,可以使用水平拆分。相对于垂直拆分的区别是:垂直拆分是把不同的表拆到不同的数据库中,而水平拆分是把同一个表拆到不同的数据库中。

相对于垂直拆分,水平拆分不是将表的数据做分类,而是按照某个字段的某种规则来分散到多个库之中,每个表中包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中 的某些行切分到一个数据库,而另外的某些行又切分到其他的数据库中,主要有分表,分库两种模式,如图:

img

 

img

优点:

\1. 不存在单库大数据,高并发的性能瓶颈。

\2. 对应用透明,应用端改造较少。

\3. 按照合理拆分规则拆分,join操作基本避免跨库。

\4. 提高了系统的稳定性跟负载能力。

缺点:

\1. 拆分规则难以抽象。

\2. 分片事务一致性难以解决。

\3. 数据多次扩展难度跟维护量极大。

\4. 跨库join性能较差。

 

拆分的处理难点

两种方式共同缺点

1. 引入分布式事务的问题。

2. 跨节点Join 的问题。

3.跨节点合并排序分页问题。

 

针对数据源管理,目前主要有两种思路:

A. 客户端模式,在每个应用程序模块中配置管理自己需要的一个(或者多个)数据源,直接访问各个 数据库,在模块内完成数据的整合。

优点:相对简单,无性能损耗。

缺点:不够通用,数据库连接的处理复杂,对业务不够透明,处理复杂。

 

B. 通过中间代理层来统一管理所有的数据源,后端数据库集群对前端应用程序透明;

优点:通用,对应用透明,改造少。

缺点:实现难度大,有二次转发性能损失。

 

拆分原则

1. 尽量不拆分,架构是进化而来,不是一蹴而就。(SOA)

2. 最大可能的找到最合适的切分维度。

3. 由于数据库中间件对数据Join 实现的优劣难以把握,而且实现高性能难度极大,业务读取 尽量少使用多表Join -尽量通过数据冗余,分组避免数据垮库多表join。

4. 尽量避免分布式事务。

5. 单表拆分到数据1000万以内。

 

切分方案

范围、枚举、时间、取模、哈希、指定等

 

案例分析

场景一

建立一个历史his系统,将公司的一些历史个人游戏数据保存到这个his系统中,主要是写入,还有部分查询,读写比约为1:4;由于是所有数据的历史存取,所以并发要求比较高;

分析:

历史数据

写多读少

越近日期查询越频繁?

什么业务数据?用户游戏数据

有没有大规模分析查询?

数据量多大?

保留多久?

机器资源有多少?

 

方案1:按照日期每月一个分片

带来的问题:1.数据热点问题(压力不均匀)

 

方案2:按照用户取模, --by Jerome 就这个比较合适了

带来的问题:后续扩容困难

 

方案3:按用户ID范围分片(1-1000万=分片1,xxx)

带来的问题:用户活跃度无法掌握,可能存在热点问题

 

场景二

建立一个商城订单系统,保存用户订单信息。

 

分析:

电商系统

一号店或京东类?淘宝或天猫?

实时性要求高

存在瞬时压力

基本不存在大规模分析

数据规模?

机器资源有多少?

维度?商品?用户?商户?

 

方案1:按照用户取模,

带来的问题:后续扩容困难

 

方案2:按用户ID范围分片(1-1000万=分片1,xxx)

带来的问题:用户活跃度无法掌握,可能存在热点问题

 

方案3:按省份地区或者商户取模

数据分配不一定均匀

 

场景三

上海公积金,养老金,社保系统

 

分析:

社保系统

实时性要求不高

不存在瞬时压力

大规模分析?

数据规模大

数据重要不可丢失

偏于查询?

 

方案1:按照用户取模,

带来的问题:后续扩容困难

 

方案2:按用户ID范围分片(1-1000万=分片1,xxx)

带来的问题:用户活跃度无法掌握,可能存在热点问题

 

方案3:按省份区县地区枚举

数据分配不一定均匀

 

拆分应用

前面所讲的读写分离、分布式存储、数据垂直拆分和数据水平拆分都是在解决数据方面的问题。下面我们来看看应用方面的变化。

之前解决了应用服务器从单机到多机的扩展,应用就可以在一定范围内水平扩展了。随着业务的发展,应用的功能会越来越多,应用也会越来越大。我们需要考虑如何不让应用持续变大,这就需要把应用拆开,从一个应用变为两个甚至多个应用。我们来看两种方式。

第一种方式,根据业务的特性把应用拆开。在我们的例子中,主要的业务功能分为三大部分:交易、商品和用户。我们可以把原来的一个应用拆成分别以交易和商品为主的两个应用,对于交易和商品都会有涉及用户的地方,我们让这两个系统自己完成涉及用户的工作,而类似用户注册、登录等基础的用户工作,可以暂时交给两系统之一来完成(注意,我们在这里主要是通过例子说明拆分的做法),如图2-22 所示,这样的拆分可以使大的应用变小。

 

img

 

我们还可以按照用户注册、用户登录、用户信息维护等再拆分,使之变成三个系统。不过,这样拆分后在不同系统中会有一些相似的代码,例如用户相关的代码。如何能够保证这部分代码的一致以及如何对其复用是需要解决的问题。此外,按这样的方式拆分出来的新系统之间一般没有直接的相互调用。而且,新拆出来的应用可能会连接同样的数据库。

来看一个具体的例子,如图2-23 所示。

我们根据业务的不同功能拆分了几个业务应用,而且这些业务应用之间不存在直接的调用,它们都依赖底层的数据库、缓存、文件系统、搜索等。这样的应用拆分确实能够解决当下的一些问题,不过也有一些缺点。

img

 

 

走服务化的路

我们再来看一下服务化的做法。图2-24 是一个示意图。从中可以看到我们把应用分为了三层,处于最上端的是Web 系统,用于完成不同的业务功能;处于中间的是一些服务中心,不同的服务中心提供不同的业务服务;处于下层的则是业务的数据库。当然,我们在这个图中省去了缓存等基础的系统,因此可以说是服务化系统结构的一个简图。

 

img

 

图2-24 与之前的图相比有几个很重要的变化。首先,业务功能之间的访问不仅是单机内部的方法调用了,还引入了远程的服务调用。其次,共享的代码不再是散落在不同的应用中了,这些实现被放在了各个服务中心。第三,数据库的连接也发生了一些变化,我们把与数据库的交互工作放到了服务中心,让前端的Web 应用更加注重与浏览器交互的工作,而不必过多关注业务逻辑的事情。连接数据库的任务交给相应的业务服务中心了,这样可以降低数据库的连接数。而服务中心不仅把一些可以共用的之前散落在各个业务的代码集中了起来,并且能够使这些代码得到更好的维护。第四,通过服务化,无论是前端Web 应用还是服务中心,都可以是由固定小团队来维护的系统,这样能够更好地保持稳定性,并能更好地控制系统本身的发展,况且稳定的服务中心日常发布的次数也远小于前端Web 应用,因此这个方式也减小了不稳定的风险。

要做到服务化还需要一些基础组件的支撑,在后面服务框架的章节我们会具体介绍。

拆分实现

通过某种特定的条件,将存放在同一个数据库中的数据分散存放到多个数据库上,实现分布存储,通过路由规则路由访问特定的数据库,这样一来每次访问面对的就不是单台服务器了,而是N台服务器,这样就可以降低单台机器的负载压力。提示:sqlserver 2005版本之后,可以友好的支持“表分区”。

  垂直(纵向)拆分:是指按功能模块拆分,比如分为订单库、商品库、用户库...这种方式多个数据库之间的表结构不同。

  水平(横向)拆分:将同一个表的数据进行分块保存到不同的数据库中,这些数据库中的表结构完全相同。

SQL Server:数据库/数据表 拆分 ▲(纵向拆分)

SQL Server:数据库/数据表 拆分 ▲(横向拆分)

  1,实现原理:使用垂直拆分,主要要看应用类型是否合适这种拆分方式,如系统可以分为,订单系统,商品管理系统,用户管理系统业务系统比较明的,垂直拆分能很好的起到分散数据库压力的作用。业务模块不明晰,耦合(表关联)度比较高的系统不适合使用这种拆分方式。但是垂直拆分方式并不能彻底解决所有压力问题,例如 有一个5000w的订单表,操作起来订单库的压力仍然很大,如我们需要在这个表中增加(insert)一条新的数据,insert完毕后,数据库会针对这张表重新建立索引,5000w行数据建立索引的系统开销还是不容忽视的,反过来,假如我们将这个表分成100个table呢,从table_001一直到table_100,5000w行数据平均下来,每个子表里边就只有50万行数据,这时候我们向一张只有50w行数据的table中insert数据后建立索引的时间就会呈数量级的下降,极大了提高了DB的运行时效率,提高了DB的并发量,这种拆分就是横向拆分

  2,实现方法:垂直拆分,拆分方式实现起来比较简单,根据表名访问不同的数据库就可以了。横向拆分的规则很多,这里总结前人的几点,

  (1)顺序拆分:如可以按订单的日前按年份才分,2003年的放在db1中,2004年的db2,以此类推。当然也可以按主键标准拆分。

  优点:可部分迁移

  缺点:数据分布不均,可能2003年的订单有100W,2008年的有500W。

  (2)hash取模分: 对user_id进行hash(或者如果user_id是数值型的话直接使用user_id的值也可),然后用一个特定的数字,比如应用中需要将一个数据库切分成4个数据库的话,我们就用4这个数字对user_id的hash值进行取模运算,也就是user_id%4,这样的话每次运算就有四种可能:结果为1的时候对应DB1;结果为2的时候对应DB2;结果为3的时候对应DB3;结果为0的时候对应DB4,这样一来就非常均匀的将数据分配到4个DB中。

  优点:数据分布均匀

  缺点:数据迁移的时候麻烦;不能按照机器性能分摊数据 。

  (3)在认证库中保存数据库配置

  就是建立一个DB,这个DB单独保存user_id到DB的映射关系,每次访问数据库的时候都要先查询一次这个数据库,以得到具体的DB信息,然后才能进行我们需要的查询操作。

  优点:灵活性强,一对一关系

  缺点:每次查询之前都要多一次查询,会造成一定的性能损失。

posted @ 2020-03-20 11:24  明志德道  阅读(339)  评论(0)    收藏  举报