一、何为分库分表

  1. Sharding的基本思想就要把一个数据库切分成多个部分放到不同的数据库(server)上,从而缓解单一数据库的性能问题。不太严格的讲,对于海量数据的数据库,如果是因为表多而数据多,这时候适合使用垂直切分,即把关系紧密(比如同一模块)的表切分出来放在一个server上。如果表并不多,但每张表的数据非常多,这时候适合水平切分,即把表的数据按某种规则(比如按ID散列)切分到多个数据库(server)上。当然,现实中更多是这两种情况混杂在一起,这时候需要根据实际情况做出选择,也可能会综合使用垂直与水平切分,从而将原有数据库切分成类似矩阵一样可以无限扩充的数据库(server)阵列。

二、分库分表需要解决的问题

  1. 事务问题
    1. 解决事务问题目前有两种可行的方案:分布式事务和通过应用程序与数据库共同控制实现事务下面对两套方案进行一个简单的对比。
      1. 方案一:使用分布式事务
        1. 优点:交由数据库管理,简单有效
        2. 缺点:性能代价高,特别是shard越来越多时
      2. 方案二:由应用程序和数据库共同控制
        1. 原理:将一个跨多个数据库的分布式事务分拆成多个仅处 于单个数据库上面的小事务,并通过应用程序来总控 各个小事务。
        2. 优点:性能上有优势
        3. 缺点:需要应用程序在事务控制上做灵活设计。如果使用 了spring的事务管理,改动起来会面临一定的困难。
  2. 跨数据库查询
    1. join:只要是进行切分,跨节点Join的问题是不可避免的。但是良好的设计和切分却可以减少此类情况的发生。解决这一问题的普遍做法是分两次查询实现。在第一次查询的结果集中找出关联数据的id,根据这些id发起第二次请求得到关联数据。
    2. 排序:
    3. 聚合count,order by,group by:这些是一类问题,因为它们都需要基于全部数据集合进行计算。多数的代理都不会自动处理合并工作。解决方案:与解决跨节点join问题的类似,分别在各个节点上得到结果后在应用程序端进行合并。和join不同的是每个结点的查询可以并行执行,因此很多时候它的速度要比单一大表快很多。但如果结果集很大,对应用程序内存的消耗是一个问题
  3. 全局序列号
    1. uuid:是一种最简单的实现,但是缺点明显,由于uuid非常长,占用空间大,并且索引的创建和基于索引的查询都会有一定的性能问题。
    2. 使用数据库的表,专门生成id:创建一张表,专门用来获取id ,但是这种方案性能瓶颈明显,所有的插入操作都需要访问这张表,很容易就成为系统性能瓶颈,并且存在单点问题,即使使用主从模式,也只能解决单点问题。
    3. 使用数据库表,批量获取id,可以解决频繁访问数据库问题,将批量获取的id在内存中进行分配消耗,不会保证数据插入id的绝对自增顺序。
    4. 雪花算法:由毫秒级时间41位 机器ID 10位 毫秒内序列12位组成,实现简单。整体按照时间自增排序,不会产生id碰撞,效率极高。但是存在时钟回拨的id碰撞风险
    5. redis自增:这个就是依赖redis的单线程特性,使用自增integer来保证全局唯一,性能也很好。
  4. 分库策略
    1. 根据数值范围:比如订单id为1-9999分到第一个库,10000-20000分到第二个库,以此类推。
    2. 根据数值取模:比如订单id mod n,按照余数放到对应编号的库中。实践中,为了处理简单,选择mod分库比较多,但是数据是否平均分布依赖于拆分键是否均匀分布,比如按照order_id分布就比较平均,如果按照seller_id,就会分布不平均,因为有些大卖家记录会比较多,会出现热点问题,可以尽量采用异步处理来减少热点的影响。
  5. 分库数量
    1. 对mysql来说,单表保持在500万以下性能最好,但是分多少库,每个实例创建多少分库,这个需要综合考虑。实例越多、分库越多,对于硬件投入就越大,单库数据量少,但是当需要跨库访问时,就需要消耗宝贵的线程资源,增加数据库负担。一般一个实例创建4-8个库就可以了。
  6. 路由透明

    1. 分库后,DB schema改变了,但是应该对应用代码透明,应用不需要关心数据具体在哪个分库的哪个表上面,这个事情要交给分库分表组件来完成,对于跨库查询也应该由分库分表组件来完成。

      需要多维度拆分的情况,可以针对对实时性要求,优先记录实时性要求最高的维度,然后异步再将其他维度数据落库。比如订单需要按照用户维度、卖家维度以及管理端三个维度去分,但是用户维度对实时性要求是最高的,可以先按照用户维度落库,然后通过异步消息去同步另外两个维度数据。

      三、框架对比

      1、当当 sharding-jdbc

      1. 定位为轻量级Java框架,在JavaJDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。<br /> 这种是在jdbc级别的框架,跟tddl是一个设计思路,通过侵入业务代码(依赖相关jar包),修改sql的方式达到路由的目的,这种的无需数据库端任何的支持,只需要在数据库中创建好对应的数据库和表即可,然后配置对应的路由规则,sharding-jdbc就会在执行sql时根据配置的规则,自动改写sql,达到访问对应的数据库中的对应表<br /> 目前使用上还有很多限制,一些复杂sql不支持,详细信息参见:[https://shardingsphere.apache.org/document/5.1.1/cn/features/db-compatibility/sql-parser/mysql/](https://shardingsphere.apache.org/document/5.1.1/cn/features/db-compatibility/sql-parser/mysql/)<br /> 支持XA事务、BASE(柔性事务)详细信息参见:[https://shardingsphere.apache.org/document/5.1.1/cn/features/transaction/concept/xa/](https://shardingsphere.apache.org/document/5.1.1/cn/features/transaction/concept/xa/)

      2、mycat

      什么是mycat

  • 一个彻底开源的,面向企业应用开发的大数据库集群
  • 支持事务、ACID、可以替代MySQL的加强版数据库
  • 一个可以视为MySQL集群的企业级数据库,用来替代昂贵的Oracle集群
  • 一个融合内存缓存技术、NoSQL技术、HDFS大数据的新型SQL Server
  • 结合传统数据库和新型分布式数据仓库的新一代企业级数据库产品
  • 一个新颖的数据库中间件产品

mycat是一个数据库的代理

优势

  1. 基于阿里开源的Cobar产品而研发,Cobar的稳定性、可靠性、优秀的架构和性能以及众多成熟的使用案例使得MYCAT一开始就拥有一个很好的起点,站在巨人的肩膀上,我们能看到更远。业界优秀的开源项目和创新思路被广泛融入到MYCAT的基因中,使得MYCAT在很多方面都领先于目前其他一些同类的开源项目,甚至超越某些商业产品。<br />MYCAT背后有一支强大的技术团队,其参与者都是5年以上软件工程师、架构师、DBA等,优秀的技术团队保证了MYCAT的产品质量。<br />MYCAT并不依托于任何一个商业公司,因此不像某些开源项目,将一些重要的特性封闭在其商业产品中,使得开源项目成了一个摆设。

3、DRDS

  1. DRDS 是一款基于 MySQL 存储、采用分库分表技术进行水平扩展的分布式 OLTP 数据库服务产品,支持 RDS for MySQL 以及 POLARDB for MySQL,产品目标旨在提升**数据存储容量、并发吞吐、复杂计算效率**三个方面的扩展性需求。<br />DRDS 核心能力采用标准关系型数据库技术实现,构建与公共云( cloud native ),配合完善的管控运维及产品化能力,使其具备稳定可靠、高度可扩展、持续可运维、类传统单机 MySQL 数据库体验的特点。<br />DRDS 于公共云和专有云环境沉淀打磨多年,历经各界天猫双十一核心交易业务及各行业阿里云客户业务的考验。承载大量用户核心在线业务,横跨互联网、金融&支付、教育、通信、公共事业等多行业,是阿里巴巴集团内部所有在线核心业务及众多阿里云客户业务接入分布式数据库的事实标准。

4、框架对比

框架/特性 sharding-jdbc mycat DRDS
框架/特性 sharding-jdbc mycat DRDS
支持的数据库 任意 mysql、mongodb、oracle、sqlserver 、hive 、db2 、 postgresql mysql
支持的语言 仅java 任意 任意
使用限制 只支持java,JDBC一些操作不支持 只支持mysql
分布式事务 支持XA、BASE事务 支持弱XA 支持,默认开启XA分布式事务
跨数据库查询 支持 支持 支持
全局序列号 支持(雪花算法,强依赖时间,存在风险) 支持,提供多种获取方式通过select last_insert_id() 获取 支持隐式获取,id获取跟单库获取方式一样
分库配置 通过应用程序配置来实现,数据库层面无感知 mycat管理,应该无感知 drds管理,应用无感知
实现方式 通过对jdbc增强,修改sql 代理 代理
路由透明
稳定性 较高(依赖数据库),对于发现的问题可以自己通过扩展去解决 较高,社区活跃, 高,由阿里云维护,解决问题比较快
扩展性 提供SPI扩展方式,用户可以通过SPI来自定义实现一些功能 只能通过修改源码来扩展功能 功能方面不能自己扩展,但是性能方面提供平滑扩容功能
运维难度 简单 复杂 相对简单,阿里云提供一系列的工具帮助运维,完善的运维体系,完善的生命周期管理、容量管理、安全与审计、容灾管理、监控告警