`

分库分表适用场景(转)

    博客分类:
  • JAVA
 
阅读更多

分库分表适用场景

分库分表用于应对当前互联网常见的两个场景——大数据量和高并发。通常分为垂直拆分和水平拆分两种。

垂直拆分是根据业务将一个库(表)拆分为多个库(表)。如:将经常和不常访问的字段拆分至不同的库或表中。由于与业务关系密切,目前的分库分表产品均使用水平拆分方式。

水平拆分则是根据分片算法将一个库(表)拆分为多个库(表)。如:按照ID的最后一位以3取余,尾数是1的放入第1个库(表),尾数是2的放入第2个库(表)等。

关系型数据库在大于一定数据量的情况下检索性能会急剧下降。在面对互联网海量数据情况时,所有数据都存于一张表,显然会轻易超过数据库表可承受的数据量阀值。这个单表可承受的数据量阀值,需根据数据库和并发量的差异,通过实际测试获得。

单纯的分表虽然可以解决数据量过大导致检索变慢的问题,但无法解决过多并发请求访问同一个库,导致数据库响应变慢的问题。所以通常水平拆分都至少要采用分库的方式,用于一并解决大数据量和高并发的问题。这也是部分开源的分片数据库中间件只支持分库的原因。

但分表也有不可替代的适用场景。最常见的分表需求是事务问题。同在一个库则不需考虑分布式事务,善于使用同库不同表可有效避免分布式事务带来的麻烦。目前强一致性的分布式事务由于性能问题,导致使用起来并不一定比不分库分表快。目前采用最终一致性的柔性事务居多。分表的另一个存在的理由是,过多的数据库实例不利于运维管理。综上所述,最佳实践是合理地配合使用分库+分表。

Sharding-JDBC简介

Sharding-JDBC是当当应用框架ddframe中,从关系型数据库模块dd-rdb中分离出来的数据库水平分片框架,实现透明化数据库分库分表访问。Sharding-JDBC是继dubbox和elastic-job之后,ddframe系列开源的第3个项目。

Sharding-JDBC直接封装JDBC API,可以理解为增强版的JDBC驱动,旧代码迁移成本几乎为零:

  • 可适用于任何基于Java的ORM框架,如JPA、Hibernate、Mybatis、Spring JDBC Template或直接使用JDBC。
  • 可基于任何第三方的数据库连接池,如DBCP、C3P0、 BoneCP、Druid等。
  • 理论上可支持任意实现JDBC规范的数据库。虽然目前仅支持MySQL,但已有支持Oracle、SQLServer等数据库的计划。

Sharding-JDBC定位为轻量Java框架,使用客户端直连数据库,以jar包形式提供服务,无proxy代理层,无需额外部署,无其他依赖,DBA也无需改变原有的运维方式。

Sharding-JDBC分片策略灵活,可支持等号、between、in等多维度分片,也可支持多分片键。

SQL解析功能完善,支持聚合、分组、排序、limit、or等查询,并支持Binding Table以及笛卡尔积表查询。

与常见开源产品对比

为了对其他开源项目表示尊重,我们无意评论目前仍在更新中的项目。这里仅列出目前停止更新,但仍然在数据库分片领域非常有影响力的几个项目,请参见表1。

图片描述

表1 数据库分片工具对比

 

通过以上表格可以看出,Cobar属于中间层方案,在应用程序和MySQL之间搭建一层Proxy。中间层介于应用程序与数据库间,需要做一次转发,而基于JDBC协议并无额外转发,直接由应用程序连接数据库,性能上有些许优势。这里并非说明中间层一定不如客户端直连,除了性能,需要考虑的因素还有很多,中间层更便于实现监控、数据迁移、连接管理等功能。

Cobar-Client、TDDL和Sharding-JDBC均属于客户端直连方案。此方案的优势在于轻便、兼容性、性能以及对DBA影响小。其中Cobar-Client的实现方式基于ORM(Mybatis)框架,其兼容性与扩展性不如基于JDBC协议的后两者。

实现原理

前文已介绍了Sharding-JDBC是实现了JDBC协议的jar文件。基于JDBC协议的实现与基于MySQL等数据库协议实现的中间层略有差别。

无论使用哪种架构,核心逻辑均极为相似,除了协议实现层不同(JDBC或数据库协议),都会分为分片规则配置、SQL解析、SQL改写、SQL路由、SQL执行以及结果归并等模块。

Sharding-JDBC的整体架构图参见图1。

图片描述

图1 Sharding-JDBC的整体架构图

 

分片规则配置

Sharding-JDBC的分片逻辑非常灵活,支持分片策略自定义、复数分片键、多运算符分片等功能。

如:根据用户ID分库,根据订单ID分表这种分库分表结合的分片策略;或根据年分库,月份+用户区域ID分表这样的多片键分片。

Sharding-JDBC除了支持等号运算符进行分片,还支持in/between运算符分片,提供了更加强大的分片功能。

Sharding-JDBC提供了spring命名空间用于简化配置,以及规则引擎用于简化策略编写。由于目前刚开源分片核心逻辑,这两个模块暂未开源,待核心稳定后将会开源其他模块。

JDBC规范重写

Sharding-JDBC对JDBC规范的重写思路是针对DataSource、Connection、Statement、PreparedStatement和ResultSet五个核心接口封装,将多个真实JDBC实现类集合(如:MySQL JDBC实现/DBCP JDBC实现等)纳入Sharding-JDBC实现类管理。

Sharding-JDBC尽量最大化实现JDBC协议,包括addBatch这种在JPA中会使用的批量更新功能。但分片JDBC毕竟与原生JDBC不同,所以目前仍有未实现的接口,包括Connection游标,存储过程和savePoint相关、ResultSet向前遍历和修改等不太常用的功能。此外,为了保证兼容性,并未实现JDBC 4.1及其后发布的接口(如:DBCP 1.x版本不支持JDBC 4.1)。

SQL解析

SQL解析作为分库分表类产品的核心,性能和兼容性是最重要的衡量指标。目前常见的SQL解析器主要有fdb/jsqlparser和Druid。Sharding-JDBC使用Druid作为SQL解析器,经实际测试,Druid解析速度是另外两个解析器的几十倍。

目前Sharding-JDBC支持join、aggregation(包括avg)、order by、 group by、limit、甚至or查询等复杂SQL的解析。目前不支持union、部分子查询、函数内分片等不太应在分片场景中出现的SQL解析。

SQL改写

SQL改写分为两部分,一部分是将分表的逻辑表名称替换为真实表名称。另一部分是根据SQL解析结果替换一些在分片环境中不正确的功能。这里具两个例子:

第1个例子是avg计算。在分片的环境中,以avg1 +avg2+avg3/3计算平均值并不正确,需要改写为(sum1+sum2+sum3)/(count1+count2+ count3)。这就需要将包含avg的SQL改写为sum和count,然后再结果归并时重新计算平均值。

第2个例子是分页。假设每10条数据为一页,取第2页数据。在分片环境下获取limit 10, 10,归并之后再根据排序条件取出前10条数据是不正确的结果。正确的做法是将分条件改写为limit 0, 20,取出所有前2页数据,再结合排序条件算出正确的数据。可以看到越是靠后的Limit分页效率就会越低,也越浪费内存。有很多方法可避免使用limit进行分页,比如构建记录行记录数和行偏移量的二级索引,或使用上次分页数据结尾ID作为下次查询条件的分页方式。

SQL路由

SQL路由是根据分片规则配置,将SQL定位至真正的数据源。主要分为单表路由、Binding表路由和笛卡尔积路由。

单表路由最为简单,但路由结果不一定落入唯一库(表),因为支持根据between和in这样的操作符进行分片,所以最终结果仍然可能落入多个库(表)。

Binding表可理解为分库分表规则完全一致的主从表。举例说明:订单表和订单详情表都根据订单ID作为分片键,任意时刻分片逻辑均相同。这样的关联查询和单表查询难度和性能相当。

笛卡尔积查询最为复杂,因为无法根据Binding关系定位分片规则的一致性,所以非Binding表的关联查询需要拆解为笛卡尔积组合执行。查询性能较低,而且数据库连接数较高,需谨慎使用。

SQL执行

路由至真实数据源后,Sharding-JDBC将采用多线程并发执行SQL,并完成对addBatch等批量方法的处理。

结果归并

结果归并包括4类:普通遍历类、排序类、聚合类和分组类。每种类型都会先根据分页结果跳过不需要的数据。

普通遍历类最为简单,只需按顺序遍历ResultSet的集合即可。

排序类结果将结果先排序再输出,因为各分片结果均按照各自条件完成排序,所以采用归并排序算法整合最终结果。

聚合类分为3种类型,比较型、累加型和平均值型。比较型包括max和min,只返回最大(小)结果。累加型包括sum和count,需要将结果累加后返回。平均值则是通过SQL改写的sum和count计算,相关内容已在SQL改写涵盖,不再赘述。

分组类最为复杂,需要将所有的ResultSet结果放入内存,使用map-reduce算法分组,最后根据排序和聚合条件做相关处理。最消耗内存,最损失性能的部分即是此,可以考虑使用limit合理的限制分组数据大小。

结果归并部分目前并未采用管道解析的方式,之后会针对这里做更多改进。

性能

路由结果在单库单表的性能测试报告:

查询操作:Sharding-JDBC的TPS为JDBC的TPS的99.8%; 
插入操作:Sharding-JDBC的TPS为JDBC的TPS的90.2%; 
更新操作:Sharding-JDBC的TPS为JDBC的TPS的93.1%; 
可以看到,Sharding-JDBC性能损失非常低。

路由结果在多库多表的性能测试报告:

查询操作:TPS双库比单库可以增加大约94%的性能; 
插入操作:TPS双库比单库可以增加大约60%的性能; 
更新操作:TPS双库比单库可以增加大约89%的性能; 
结果表明,Sharding-JDBC可有效利用多线程与分布式资源大幅度提升性能; 
更多详细情况可查看Sharding-JDBC的性能测试报告。

Roadmap

目前Sharding-JDBC集中于分库分表核心逻辑开发,在功能稳定之后将会按照如下线路持续更新:

  • 读写分离;
  • 柔性分布式事务;
  • 分布式主键生成策略;
  • SQL重写优化,进一步提升性能;
  • SQL Hint,可指定某SQL在某具体库表执行,基于业务规则而非SQL解析路由; 
    小表广播;
  • HA相关;
  • 流量控制;
  • 数据库建表工具;
  • 数据迁移;
  • 复杂SQL解析支持,如子查询、存储过程等;
  • Oracle, SQLServer支持;
  • 配置中心;

开源理念

目前国内很多开源产品都在公司内部经受过时间的考验,然后剥离业务逻辑和敏感代码,再开源贡献给社区。这样做的优点是开源的产品相对成熟。但缺点也不可避免,主要有:

  1. 后续支持匮乏。产品已经满足了该公司的业务场景需求,缺乏后续提升的动力。文档、支持也会相对较少,甚至出现文档和代码不同步的状况。
  2. 与该公司业务场景耦合较为严重。大部分框架产品都是为了解决特定的问题。比如:有的公司可能并不需要分表;有的公司只需支持几种分片策略就好。
  3. 开源不完整。和公司业务耦合紧密的部分不会开源。
  4. 缺乏粘度。较为成型的项目由于功能繁多、代码结构复杂,社区志愿者难于扩展或修改核心逻辑。如果测试覆盖率不够,难以保证修改后的代码质量。以上一系列问题会导致项目对社区的粘度不高,难于找寻可合作开发的志愿者。
  5. 分支众多难于维护。由于开源之后公司缺乏持续提升的动力,和本公司关系不大的需求功能得不到重视,导致各公司都开发自己的分支。开源项目虽然一开始给社区注入了新鲜思想,但最终并没有吸取社区精华。如:Dubbo一出现即引起了相当多的关注,而各公司都有自己的版本,如当当的DubboX,但最终Dubbo并未能持续发展。

我们考虑全新的开源策略,在Sharding-JDBC刚完成初版的时候,即向社区和当当内部同时推广。这样做的好处有:

  • 后续支持完善。Sharding-JDBC与当当内部落地绑定,将会在当当内部和社区同时提供支持。虽然无法提供社区需求的优先级高于当当内部的承诺,但我们会综合考虑社区与内部的需求,以更高的视角,尽量整合与优化升级路线。
  • 完整开源。代码的snapshot版本都会首先出现在GitHub上。
  • 共同发展。Sharding-JDBC目前代码较为简单。使社区开源爱好者能更加轻松地理解代码核心,为以后的持续发展奠定基础。并且Sharding-JDBC也会吸纳社区精华,让更多地爱好者参与代码贡献。

最后需要澄清,未经时间考证的Sharding-JDBC并非Bug成堆,完全不可用的项目。目前测试覆盖率超过90%,详细功能以及不支持项都明确地罗列在GitHub的文档中,希望让使用者心中有数。

分享到:
评论

相关推荐

    数据分库分表之二叉树分库分表

    ### 数据分库分表之二叉树分库分表 #### 一、引言与背景 随着互联网技术的快速发展及用户需求的激增,单一数据库系统已难以应对日益增长的数据处理需求。为了提高系统的可扩展性和性能,数据分库分表成为了一种...

    Python+MySQL分表分库实战

    这种做法可以有效减轻单个数据库的压力,提高数据处理的吞吐量和查询效率,尤其是在涉及到海量数据处理和高并发访问的场景下,分库分表就显得尤为关键。 了解基础知识后,我们将探讨创建新表结构的步骤。在Python...

    集成sharding-jdbc实现分库分表.zip

    在IT行业中,数据库扩展是解决高并发、大数据量问题的关键技术之一。Sharding-JDBC作为阿里巴巴开源的一款轻量级...在实际操作中,我们需要结合业务场景和数据库特性,合理地设计分片策略,以实现最佳的分库分表效果。

    shardingsphere 分库分表中文帮助文档

    - 数据库横向扩展场景:当单个数据库无法承载大量数据时,可以使用 Shardingsphere-JDBC 进行分库分表操作。 - 复杂查询优化:通过路由规则配置,可以优化跨库、跨表的复杂 SQL 查询。 ##### 1.1.2 ...

    SpringBoot + ShardingSphere分库分表实战(附完整代码)

    【SpringBoot + ShardingSphere分库分表实战】 在应对大数据量的系统中,分库分表是一种常见的解决策略,可以有效地分散数据库压力,提高系统的处理能力。在Java开发领域,ShardingSphere是一个广泛使用的开源...

    分库分表案例.rar

    本案例“分库分表案例.rar”提供了一个基于MySQL数据库实现的分库分表和读写分离的示例,采用IDEA开发环境,包含完整的数据库结构和源代码,为开发者提供了实际操作的参考。 首先,我们来看分库分表的概念。分库...

    sharding-jdbc分库分表

    它作为JDBC的一个增强工具,可以在现有的Java应用中透明地添加分布式数据库处理能力,实现了数据的分库分表以及读写分离。 1. **分库分表原理**: 分库分表是解决大数据量下数据库性能瓶颈的有效手段。Sharding-...

    50_一个关键的问题!分库分表之后全局id咋生成?.zip

    在IT行业中,数据库设计是至关重要的,特别是在大型系统中,分库分表是解决高并发、大数据量场景下的常见策略。然而,随着数据的分散,如何生成全局唯一ID(Global Unique Identifier)成为一个关键问题。本话题将...

    Java分库分表实战案例程序

    本资源适用于Java开发者、数据库管理员以及对分库分表技术感兴趣的人群。具备一定的Java编程和数据库知识会更有利于理解和应用该案例。 使用场景及目标: 1. 高并发系统:对于需要处理大量请求的系统,分库分表可以...

    java mysql 分库分表详解

    在进行分库分表时,需要评估业务场景,选择合适的分片策略,如哈希取模、范围分片等,确保数据均匀分布。此外,还要关注分布式事务的处理,如2PC(两阶段提交)、TCC(尝试-确认-补偿)等方案,以及如何设计和优化跨...

    分库分表代码实现和讲解

    在大数据量的场景下,传统的单数据库架构可能会面临性能瓶颈,这时就需要采用分库分表策略来提升系统处理能力。本教程将详细讲解如何使用PHP实现MySQL的分库分表,帮助你理解并掌握这一核心技能。 首先,我们来探讨...

    mysql分库分表分区1

    MySQL 数据库在处理大数据量时,为了提高查询性能和管理效率,通常会采用分库分表的技术。这里的“mysql分库分表分区1”主要讨论的是 MySQL 中的表分区技术,这是一种将大表物理分割为多个更小、更易管理的部分的...

    分库分表面试题- pdf

    分库分表是一种重要的数据库优化技术,尤其适用于处理大规模数据和高并发访问的场景。通过对数据进行合理拆分,不仅可以显著提升系统的性能和可用性,还能有效降低运维成本。然而,实施分库分表也需要解决一系列技术...

    ShardingSphere分库分表教程.pdf

    为了应对大数据量带来的挑战,数据库中间件ShardingSphere应运而生,它通过分库分表技术,将数据分布到多个数据库实例中,有效提高了系统的性能和扩展性。本文将详细探讨ShardingSphere中分库分表的核心概念、实现...

    Mysql分库分表11111111111

    ### MySQL分库分表策略详解 #### 一、场景与系统分析 在互联网技术日新月异的今天,数据量的快速增长对数据库系统的性能提出了更高要求。为了应对这些挑战,许多企业选择实施分库分表策略。分库分表是指将原来单一...

    mysql大数据分库和分表 php解决方案

    在这种背景下,单一数据库往往难以承受巨大的数据处理压力,因此,采用分库分表技术成为了提高数据库性能的有效手段之一。本文主要探讨MySQL大数据分库和分表的PHP解决方案,并通过具体的案例分析来加深理解。 ####...

    高性能数据库集群分库分表方案.docx

    高性能数据库集群分库分表方案 本文主要介绍高性能数据库集群分库分表相关理论、基本架构、涉及的复杂度问题以及常见解决方案。 1. 分库分表概述 分库分表是数据库性能优化的重要手段之一,通过将数据库读写操作...

    分库分表入门级-lzg

    分库分表是应对大数据量、高并发场景下的数据库优化策略,旨在解决单表数据量过大、并发处理能力不足等问题。本文将深入探讨分库分表的基本概念、关键问题及其解决方案,并介绍相关开源工具和实际应用案例。 **一、...

    第六节课交易分库分表详解二1

    分库分表是为了应对高并发、大数据量场景下的性能瓶颈,但是它带来了如分布式事务、分布式主键、跨库查询以及数据迁移等问题。 分布式事务是其中的一大难点,因为它涉及到多个数据库间的协调与一致性保证。解决这个...

    Mysql分库分表实例.zip

    为了解决这一问题,"Mysql分库分表实例" 提供了一种解决方案——数据分片技术,即通过分库分表来提升数据库的读写效率。 分库分表是数据库水平扩展的一种策略,它的核心思想是将一个大的数据库拆分成多个小的数据库...

Global site tag (gtag.js) - Google Analytics