文章目录
- 内核工作原理
- 配置管控
- SQL Parser: SQL解析引擎
- SQL Router- SQL 路由引擎
- SQL Rewriter : SQL 优化引擎
- SQL Executor : SQL执行引擎
- Result Merger: 结果归并
内核工作原理
ShardingSphere的整体架构图是这样的:
配置管控
在进入ShardingSphere的内核之前,ShardingSphere做了大量的配置信息管控。
不光是将应用的配置信 息进行解析,同时ShardingSphere还支持将这些配置信息放到第三方的注册中心,从而可以实现应用层的水 平扩展。
SQL Parser: SQL解析引擎
解析过程分为词法解析和语法解析。
词法解析器用于将SQL拆解为不可再分的原子符号,称为Token。并根据不同数据库方言所提供的字典,将其归类为关键字、表达式、字面量和操作符。
再使用语法解析器将 SQL转换为抽象语法树(简称AST, Abstract Syntax Tree)。
例如对下面一条SQL语句:
SELECT id, name FROM t_user WHERE status = 'ACTIVE' AND age > 18
会被解析成下面这样一颗树:
SQL解析是整个分库分表产品的核心,其性能和兼容性是最重要的衡量指标。
ShardingSphere在1.4.x之前采用的是性能较快的Druid作为SQL解析器。
1.5.x版本后,采用自研的SQL解析器,针对分库分表场景,采取对SQL半理解的方式,提高SQL解析的性能和兼容性。
然后从3.0.x版本后,开始使用ANLTR作为SQL解析引擎。这是个开源的SQL解析引擎,很多开源产品都使用他来解析SQL。比如像Druid、Flink、Hive、RocketMQ、Elasticsearch等等。ShardingSphere在使用ANLTR时,还增加了一些AST的缓存功能。针对ANLTR4的特性,官网建议尽量采用PreparedStatement的预编译方式来提高SQL执行的性能。
SQL Router- SQL 路由引擎
根据解析上下文匹配数据库和表的分片策略,并生成路由路径。对于携带分片键的 SQL,根据分片键的不同可以划分为
- 单片路由(分片键的操作符是等号)
- 多片路由(分片键的操作符是 IN)
- 范围路由(分片键的操作符是 BETWEEN)
- 不携带分片键的 SQL 则采用广播路由。
- 全库路由:对数据库的操作都会遍历所有真实库。 例如 set autocommit=0
- 全库表路由:对于不带分片键的DQL、DML以及DDL语句,会遍历所有的库表,逐一执行。
- 全实例路由:对于DCL语句,每个数据库实例只执行一次,例如
CREATE USER
创建用户语句 - 单播路由:仅需要从任意库中获取数据即可。 例如 DESCRIBE course
- 阻断路由:屏蔽SQL对数据库的操作。例如 USE coursedb。就不会在真实库中执行,因为针对虚拟表操作,不需要切换数据库。
SQL Rewriter : SQL 优化引擎
首先,在数据方言方面。Apache ShardingSphere 提供了 SQL 方言翻译的能力,实现数据库方言之间的自动转换。
例如,用户可以使用 MySQL 客户端连接 ShardingSphere 并发送基于 MySQL 方言的 SQL,ShardingSphere 能自动识别用户协议与存储节点类型自动完成 SQL 方言转换,访问 PostgreSQL 等异构存储节点。
接下来,用户只需要面向逻辑库和逻辑表来写SQL,最终由ShardigSphere的改写引擎将SQL改写为在真实数据库中可以正确执行的语句。
SQL改写分为正确性改写和优化改写。
正确性改写
在包含分表的场景中,需要将分表配置中的逻辑表名称改写为路由之后所获取的真实表名称。仅分库则不需要表名称的改写。除此之外,还包括补列和分页信息修正等内容。
优化改写
优化改写的目的是在不影响查询正确性的情况下,对性能进行提升的有效手段。它分为单节点优化和流式归并优化。比如我们之前提到,在ShardingJDBC5版本下,对一个分片库的多次查询,会通过UNION 合并成一个大的SQL,这也是一种优化改写。
SQL Executor : SQL执行引擎
ShardingSphere 采用一套自动化的执行引擎,负责将路由和改写完成之后的真实 SQL 安全且高效发送到底层数据源执行。它不是简单地将 SQL 通过 JDBC 直接发送至数据源执行;也并非直接将执行请求放入线程池去并发执行。它更关注平衡数据源连接创建以及内存占用所产生的消耗,以及最大限度地合理利用并发等问题。执行引擎的目标是自动化的平衡资源控制与执行效率。
这里主要是理解内存限制模式和连接限制模式。简单理解,
- 内存限制模式只需要保持一个JDBC连接,单线程即可完成某一个真实库的所有数据访问。
- 连接限制模式就需要保持多个JDBC连接,也就需要多线程并发完成某一个真实库的所有数据访问。
Result Merger: 结果归并
将从各个数据节点获取的多数据结果集,组合成为一个结果集并正确的返回至请求客户端,称为结果归并。
其中重点是理解流式归并与内存归并:
- 流式归并是指每一次从结果集中获取到的数据,都能够通过逐条获取的方式返回正确的单条数据,它与数据库原生的返回结果集的方式最为契合。遍历、排序以及流式分组都属于流式归并的一种。通常内存限制模式就可以使用流式归并,比较适合OLTP场景。
- 内存归并则是需要将结果集的所有数据都遍历并存储在内存中,再通过统一的分组、排序以及聚合等计算之后,再将其封装成为逐条访问的数据结果集返回。通常连接限制模式就可以使用内存归并,比较适合OLAP场景。