知乎头条。纯干货:深度认识 Sharding-JDBC,mybatis 连接数据库原理
Q:请问 Sharding-JDBC 自研的 SQL 解析器开源否?性能能否有大的提升?另外,现在当当的业务中,数据库的分库分表迁移可否自动化?
Sharding-JDBC 自研的 parser 是开源的,目前在 parser 这个分支,但是还未做完,仍然在快速的迭代中。
SQL 解析原理和 Druid 基本相同,但是简化了一些流程。Duird 的初衷是对 SQL 进行监控、分析以及规范化,因此它的 SQL 解析场景需要对 SQL 进行完全的理解。采用 Druid 的作为基础解析器的 Sharding-JDBC 解析流程为:(Lexer -> Parser -> AST -> Vistor) -> SharidingContext,其中括号内是 Duird 框架的流程,无法修改。而 Sharding-JDBC 仅需理解与 Sharding 相关的关键字,无关内容则采取跳过的方式,因此将直接生成分片上下文,无需再通过抽象语法树的访问器再获取。
New Parser 的解析流程简化为:Lexer -> Parser ->?SharidingContext。因此在性能以及实现复杂度上都有所突破。具体的性能测试报告目前还未做,会随着 New Parser 分支完全一起发布。
关于分库分表自动迁移的事,当当还没有做到自动化。由于数据迁移更加贴近于数据库运维工具,和 JDBC 关系不大,因此 Shariding-JDBC 也暂时未将数据迁移纳入范围。
关于 Sharding-JDBC 未来的规划,张亮老师也和我们分享了很多干货
Q:Sharding-JDBC 下一步规划是什么?
Sharding-JDBC 目前正在进行 SQL Parser 部分的重写。之前的 Sharding-JDBC 使用 Duird 作为 SQL 解析的基础工具,但基于各方面的考虑,我们决定采用自研的方式解析 SQL,能进一步的提升性能和 Sharding 的准确性以及兼容性。
New SQL Parser 完成之后,我们会着重处理之前没有完成的柔性事务 TCC 部分,更多类型 SQL 的支持以及配置动态化。
这些做完之后会考虑将 Sharding-JDBC 分为 Sharding-Driver 以及 Sharding-JDBC-Server 两个版本,用于满足不同用户的需要。Sharding-JDBC-Driver 会更加轻量级,而 Sharding-JDBC-Server 会以 Proxy 的形式提供服务,能更好的处理数据迁移,事务以及 OLAP 等需求。
Shariding-JDBC 的核心应该就是 JDBC 驱动的增强,以 jar 形式提供轻量级的服务。大体上看,Sharding-JDBC 的生态应该大致分为 3 个环路:
一环是 JDBC 相关的核心功能,包括分库分表、读写分离、分布式主键等。这个是小而美的核心部分。
二环是和数据库相关,但不属于 JDBC 范畴的,将以插件的形式提供,包括柔性事务、数据库的 HA、数据库 Metadata 管理、配置动态化等。
三环是业务或使用友好度相关的,包括多租户、账户安全、Spring 自定义命名空间、Yaml 配置等。
有很多朋友提到关于对其他语言的支持,因为 Shariding-JDBC 是基于 Java 提供的 JDBC 规范的接口所开发,因此目前暂时不支持 Python、Node.js 等。
但其核心的解析、路由、结果归并等功能模块和基于 Proxy 版本开发几乎是一致的。因此,未来我们有打算提供 Shariding-JDBC-Server 版本,将会支持全语言。
有朋友看到我们在考虑开发 Sharding-JDBC-Server,以为目前的 Sharding-JDBC 模式遇到了某些不可解决的问题。其实 Shariding-JDBC 以当前的定位来说,没有遇到不可解决的问题,但如果想做的更多(前面提到的数据迁移,分布式事务,元数据管理等),则需要向 Proxy 的方式靠拢。Shariding-JDBC 想提供两种不同的使用方式,给使用者更自由的选择。
还有就是对 SQL 语句的支持。由于时间和精力有限,目前无法做到全 SQL 的兼容。我们现阶段的目标是尽量支持 OLTP 最常用的 80% 的 SQL。目前支持聚合、分组、排序等查询。暂时不支持 distinct,对 or 的支持也不是特别完善,但是 distinct 和 group by 可以互换,or 也可以用 in 代替。因此绝大部分 SQL 经过修改是可以使用的。
有朋友提到,既然 distinct 和 group by 可以互换,or 可以用 in 代替,那么是不是可以考虑直接在 SQL 解析的时候自动切换?
对于这个问题,虽然这样做在技术上是可行的,但是设计上来说还有待商榷。
如果已经做了 distinct 和 or 的解析,其实完全没有必要改写 SQL,直接支持就可以了。而改写 SQL,对于 DBA 的调试就比较痛苦,因此我们希望做到尽量不修改 SQL,仅修改必要的部分,如:分表的名称、avg 转化为 count 和 sum、limit 的 offset 和 rowCount。
对于过于复杂的 SQL,如子查询等,不一定适合在大数据量的分片数据库中使用,也许需要重新梳理。
未来我们也会对 SQL 兼容性这块持续进行提升。
目前 Sharding-JDBC 仅支持 MySQL,对其他数据库的支持(比如 Oracle)也正在进行。现在 New SQL Parser 正在进行中。计划在这个版本发布对 Oracle、PG 以及 SQLServer 的支持。对于 Or
acle 以及 SQLServer 主要的支持在于特殊关键词识别和分页。
New SQL Parser 确实工作量比较大,虽然目前整体代码已经梳理得差不多了,但想稳定的提供服务还需要一些时间。预计 4 月份提供 snapshot,6 月份提供稳定版。
New SQL Parser 在 Git 的 parser 分支持续更新中,欢迎继续关注。
还和大家分享了很多数据库相关的使用经验和心得
Q:现在用着自己写的 Sharding,不过在解析语句这块比较尴尬,有些语句解析不来,所以自己封装 jsqlparser,Druid,自写正则三个方法来取表名,老师有什么建议?
jsqlparser 用的是 JavaCC 的方式解析 SQL,相对于 Druid 来说,性能比较低。正则解析的话,性能应该会更低,而且这两种方式都比较难调优。
Druid 采用的词法和语法分析的方式解析 SQL,编码工作量大,但性能会提升很多。Druid 的 SQL 解析器对于开发者而言稍微有些不易上手。Shariding-JDBC 采用与 Druid 相同的 SQL 解析方式,但为?Sharding 做了优化。
只是获取表名的话,jsqlparser 和 Duird 都没问题,如果考虑性能问题,还是建议用 Druid 或者参考下 Sharing-JDBC 的做法。
Q:对于分布式事务这块,有什么实践经验分享吗?
分布式事务这块,我们认为 XA 多阶段提交的方式,虽然对分布式数据的完整性有比较好的保障,但会极大的降影响应用性能,并未考虑采用。我们采用的是两种方式,一种称之为弱 XA,另一种是柔性事务,即 BASE。
弱 XA 就是分库之后的数据库各自负责自己事务的提交和回滚,没有统一的调度器集中处理。这样做的好处是天然就支持,对性能也没有影响。但一旦出问题,比如两个库的数据都需要提交,一个提交成功,另一个提交时断网导致失败,则会发生数据不一致的问题,而且这种数据不一致是永久存在的。
柔性事务是对弱 XA 的有效补充。柔性事务类型很多。
Sharding-JDBC 主要实现的是最大努力送达型。即认为事务经过反复尝试一定能够成功。如果每次事务执行失败,则记录至事务库,并通过异步的手段不断的尝试,直至事务成功(可以设置尝试次数,如果尝试太多仍然失败则入库并需要人工干预)。在尝试的途中,数据会有一定时间的不一致,但最终是一致的。通过这种手段可以在性能不受影响的情况下牺牲强一致性,达到数据的最终一致性。最大努力送达型事务的缺点是假定事务一定是成功的,无法回滚,因此不够灵活。
还有一种柔性事务类型是 TCC,即 Try Confirm Cancel。可以通过事务管理器控制事务的提交或回滚,更加接近原生事务,但仍然是最终一致性。其缺点是需要业务代码自行实现 Try Confirm Cancel 的接口,对现有业务带来一定冲击。未来 Sharding-JDBC 会带来对 TCC 的支持。
还有一些其他的分布式事务,如 Google 提出的 F1 等,由于 Shariding-JDBC 仍然使用数据库的原有存储引擎,并未改变,因此暂时不考虑对此类型事务的支持。
Q:请问何时需要分表?目前我们都是按照业务分库。
分库分表分为水平拆分和垂直拆分。按照业务分库或分表属于垂直拆分。水平拆分是将同样的库或表按照一定的分片规则拆成多个。
分库和分表都可以有效的处理由于数据量大而导致的查询性能下降的问题。分库还可以缓解高并发对数据库带来的压力,但仅分表可以使用本地事务代替分布式事务。因此分库和分表的合理使用是需要根据业务场景来决定的。
Sharding-JDBC 作为开发的基础类库,支持分库和分表,将选择的余地留给业务开发的工程师。
Q:请教一下,根据主键分片,以用户名登录,如何知道用户落在哪个分片上?
如果用户名是主键,则可以直接根据您定义的分片策略计算,算出该用户最终落在哪个库的哪张表上。
如果用户名不是主键,则必须通过全路由查询,一个一个的找,直到找到为止。
张亮老师还和大家畅谈了很多其他关于数据库的问题
Q:我有一个很大的问题,就是如何判断自己需要搞魔改还是换数据库呢?MySQL 各种魔改的成本恐怕未必比买高端数据库便宜吧。特别是现在数据库很多都有云服务可以选择,买个 Oracle 或者微软的云服务数据库,入门成本现在应该可以被中小企业接受了吧。
这个问题比较大,需要从整体的角度来讨论一下。
MySQL + 开源分片中间件是公司将技术核心抓在了自己的手里,互联网公司大多愿意采用。这个不仅是眼前的经济成本问题,还包括了技术问题解决成本、对业务发生变化时对技术的控制能力等。比较成熟的公司都会沉淀出适合自己的中间件架构,以及各种监控、治理等辅助系统。
NoSQL 也是一种选择,但它们的定位是关系型数据库的有益补充,并不是要完全替换掉关系型数据库,因此,关系型数据库 + 分片仍然有其存在价值。
对于 Oracle,我的看法是重要的业务数据可以考虑,而一些周边数据,就没什么必要。当然如果公司不差钱,定位又非技术导向,而是纯业务导向的话,完全依赖 Oracle 也是可以的。只不过 Oracle 不能满足互联网的全部场景。各种云数据库和 Oracle 差不多,公司对自我的定位很重要。如果有核心业务,完全可以把技术全包出去。
个人理解,当业务量较小或适中的情况下,采用 Oracle 和云数据库是合理的选择。而在公司的业务爆炸式增长的大型互联网公司,这些方案未可行,因为独角兽级别的公司遇到业务场景基本都是独一无二的,其解决方案并不是第三方功能能够直接给予的。成长到一定程度的公司大多会选择自研 + 开源的组合,保证其技术的适应度以及和业务的匹配度。
Q:所以说选型其实是针对 OLTP 业务模型和数据量的变化作为主要考虑指标?在初期未必有足够的技术和资金的时候,选择免费的 MySQL 先用起来。然后等活下来有能力做大,数据也暴涨了,这时候就招人来魔改,或者选择已有魔改方案。传统商业数据库集中在财务等关键地方,或者 OLAP 这种 MySQL “草鸡”的领域(也可能完全不用数据库选择大数据产品)。不知道我理解得是否正确。
是的,正确。
简单说,刚起步用 MySQL;有钱并且业务量适中用 Oracle,核心业务用 Oracle,非核心业务用云数据库;资金不充足业务量较大用 MySQL + 开源中间层;业务量超大只能自研。
大数据和关系型数据库不是一个方向,主要用于存储其他类型数据了,订单、交易等数据一般不会放大数据,更适合日志,浏览记录等。
Q:另外在选型上,我还想提一下 PG 这个数据库。业内选择 MySQL 比较多,PG 比较少。是不是就是因为 PG 在大规模集群魔改方面一直没有成功案例的关系?起码自从谷歌魔改 MySQL 开始,我们听说了太多的案例。PG 就好像没听说过了。
用了 MySQL,哪怕有各种糟糕,但是因为有各种成功案例和各种第三方开源魔改集群方案,起码我知道可以做得够大。但是 PG 虽然特性上远远强过 MySQL,但是因为本身不像 MySQL 那么灵活,所以采用的反而少。有钱的买商业,没钱的 MySQL+Hadoop。
Sharding-JDBC 的服务对象是任何关系型数据库,无论是 MySQL 还是 PG。
不过针对这个问题可以再大致聊一下。很多公司的技术选型在于平衡,尤其是数据库选型这块。不一定 MySQL 就是最好的数据库,某些方面 PG 确实要更好,但 MySQL 是在各个方面受认可最多的数据库。比如周边的 MHA 套件、开发和 DBA 对数据库的熟悉程度等。因此,即使是 MySQL 的分支版本 MariaDB 或 Percona,无论功能性能再怎么提升、引擎再怎么变化,其总体的认可度也还是不如 MySQL 的。
Q:有一个问题一直很疑惑,目前分库分表的中间件有两种思想,分别是:
类似 Sharding-JDBC 及 TDDL 的增强版 JDBC 驱动思想
类似 Mycat 增加中间层,然后在中间层进行分库分表思想
我想问的是,这两种思想都有什么优势和劣势呢,大公司的主流选型又是哪种?
两种方式各有优缺点。
JDBC 驱动版的优点:
轻量,范围更加容易界定,只是 JDBC 增强,不包括 HA、事务以及数据库元数据管理
开发的工作量较小,无需关注 nio,各个数据库协议等
运维无需改动,无需关注中间件本身的 HA
性能高,JDBC 直连数据库,无需二次转发
可支持各种基于 JDBC 协议的数据库,如:MySQL,Oralce,SQLServer
Proxy 版的优点:
可以负责更多的内容,将数据迁移,分布式事务等纳入 Proxy 的范畴
更有效的管理数据库的连接
整合大数据思路,将 OLTP 和 OLAP 分离处理
因此两种方式互相可以互补,建议使用 Java 的团队,且仅 OLTP 的互联网前端操作。有可能会使用多种数据库的情况,可以选择 JDBC 层的中间件;如果需要 OLAP 和 OLTP 混合,加以重量级的操作,如数据迁移,分布式事务等,可以考虑 Proxy 层的中间件。但目前开源的数据迁移和分布式事务的完善解决方案还不常见。NewSQL 这种改变数据库引擎的方式就不在这里讨论了。
原作者: oschina|来自: oschina
这里是每天都很困的 JAVA 爱好者,如果您跟我一样每天睡不饱却依然热爱 JAVA!
那就关注我吧!
才疏学浅请多指教。
评论