数据库之分库分表架构设计(一)

1、什么是分库分表

        数据拆分是对数据进行分而治之的通用概念

 垂直拆分:根据业务维度,将原本一个库(表)拆分为多个库(表),每个库(表)与原有的结构不同。例如将用户表和订单表分别存于两个不同的数据库中,或者将用户表中的一些信息拆分存于不同的表中。

   优点:

  • 拆分后业务清晰,拆分规则明确
  • 系统之间进行整合或扩展容易
  • 按照成本、应用等级、应用的类型等将表放到不同的机器上,便于管理
  • 便于实现动静分离、冷热分离的数据库表设计模式。(冷数据查询多,适合MyISAM引擎,热数据更新频繁,适合InnoDB)
  • 数据维护简单

    缺点 :

  • 部分业务表无法关联(join),只能通过接口方式解决,提高系统的复杂度
  • 受每种业务的不同限制,存在单库性能瓶颈,不易进行数据扩展和提升性能
  • 事务处理复杂

水平拆分:根据分片(sharding)算法,将一个库(表)拆分为多个库(表),每个库(表)保留原有的结构。例如将用户表id为0-1000的数据存于数据库A中,1001-2000的数据存于数据库B中。又或者是id为0-1000的存于数据库A中的table1,1001-2000的存于table2中。

    方法:1、按照哈希切片  2、按照时间切片

    优点:

  • 单库单表的数据保持在一定量级,有助于性能 提高
  • 切分的表结构相同,应用层改造较少,只需要增加路由规则即可(路由:针对输入的请求,通过分库分表规则找到对应的表和库的过程)
  • 提高了系统稳定性和负载能力

    缺点:

  • 切分后数据是分散的,很难利用数据库的join操作,跨库的join性能差
  • 拆分规则难以抽象
  • 分片事物的一致性难以解决
  • 数据扩容难度和维护量极大

1.1、使用阶段:单表单库、单库多表、多库多表

2、什么情况下需要分库分表

  • 2.1、如果数据库中表的数据量达到一定的量级,则需要进行分表,分解单表的大量数据量对索引查询带来的压力,并方便对索引和表结构的变更
  • 2.2、数据库的吞吐量达到了瓶颈,就需要增加数据库实例。
  • 2.3、希望再扩容时对应用层的配置改变最少,就需要再每个数据库实例中预留足够的数据库数量

3、分库分表解决方案

在应用层直接实现:直接在应用层读取并解析分片规则,根据分片规则实现切分的路由逻辑,从应用层直接决定每次操作应该使用那个数据库实例、数据库及哪个数据库的表。

数据库之分库分表架构设计(一)_第1张图片

通过定制JDBC协议实现:针对业务逻辑层提供与JDBC一致的接口,分库分表在JDBC内部实现,对业务层保持透明。(Sharding JDBC采用此方案)

数据库之分库分表架构设计(一)_第2张图片

通过定制ORM框架实现:把分片规则实现到ORM框架中或者通过ORM框架支持的扩展机制来完成分库分表的逻辑。如在MyBatis配置文件SQL中增加表索引的参数来实现分片。

数据库之分库分表架构设计(一)_第3张图片

代理分片:在应用层和数据库层增加一层代理层,把分片的路由规则配置在代理层,代理层对外提供与JDBC兼容的接口给应用层。(Cobar和MyCat等)

数据库之分库分表架构设计(一)_第4张图片

4、分片后的事务处理机制

4.1、分布式事务

       解决方法:

  • 两阶段提交协议:将分布式事务分为两个阶段,一个是准备阶段,一个是提交阶段,两个阶段都是由事务管理器发起
  • 最大努力保证模式:在更新多个资源的时候,将多个资源的提交尽量延后到最后一刻处理,这样的话如果过程出现问题,则所有的资源更新都可以回滚
  • 事务补偿机制:对于跨库的多个操作,可通过补偿和重试,使其在一定的时间窗口内完成操作,这样就可以实现事务最终一致性

4.2、事务路由

  • 自动提交事务路由:依赖JDBC数据源的自动提交事务特性,对任何数据库进行更新操作后会自动提交事务
  • 可编程事务路由:在分库分表中,在需要开启事务的方法中,需要动态的确定开启哪个数据库实例的事务。
  • 声明式事务:在实现的服务方法上直接声明事务的处理注解

5、读写分离

  • 当读操作压力很大时,可以考虑添加从库机器来分解大量读操作带来的压力,但是当从库机器达到一定的数量时,就需要考虑分库来缓解压力

  • 当写操作压力很大时,就必须进行分库操作了

  • 当由于服务器性能不一时,可以通过程序控制每台机器读写的比重来达到负载均衡,这需要更加复杂的读写分离的路由规则

6、分库分表引起的问题

6.1、扩容与迁移

解决方法:

  1. 按照新旧分片规则,对新旧数据库进行双写
  2. 将双写前按照旧分片规则写入的历史数据,根据新分片规则迁移写入新的数据库
  3. 将按照旧分片规则的查询改为新分片规则查询
  4. 将双写数据库逻辑从代码中下线,只按照新的分片规则写入数据
  5. 删除按照旧分片规则写入的历史数据

6.2、分库分表维度导致查询问题

解决方法:

  1. 在多个分片表查询后合并数据集,这种方式的效率低
  2. 记录两份数据,一份按照买家维度分表,一份按照商品维度分表(电商系统涉及的查询)
  3. 通过搜索引擎解决,但是如果实时性要求很高,就需要实现实时搜索

6.3、跨库事务难以实现

     尽量避免在一个事务中同时修改db0和db1的表

6.4、同组数据跨库问题

     尽量把同一组数据放到同一台服务器上,不但在某些场景下可以利用本地事务的强一致性,还可以使这组数据自治。

 

参考:《可伸缩服务架构:框架与中间件》

你可能感兴趣的:(读书笔记,DB,分库分表)