自学内容网 自学内容网

《技术栈选型之跨库查询分析》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗

🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,欢迎多多交流。👍

写在前面的话

近期,博主所在公司处于新产品建设阶段,需要考虑票据模板设计器的设计开发,由于要考虑大数据量下数据库的性能瓶颈问题,因此业务数据库要考虑按业务域垂直拆分,这也对传统票据语法的查询实现带来挑战。

本篇文章主要介绍了跨域需求和解决方案的分析过程,后续篇章会针对具体技术点进行展开介绍。


跨库需求分析

背景说明

传统模式下,将数据集中存储至单一节点的解决方案,在性能、可用性和运维成本这三方面已经难于满足海量数据的场景。

通过分库和分表进行数据的拆分来使得各个表的数据量保持在阈值以下,以及对流量进行疏导应对高访问量,是应对高并发和海量数据系统的有效手段,数据分片的拆分方式又分为垂直分片和水平分片。

基于公司项目建设需要,期望将不同业务域(Schema)拆分为若干物理独立的数据库,同时不允许业务服务连接非本业务相关的数据库,即使用业务垂直分库。

那么,这里暂不讨论水平分库,先重点讨论垂直分库。

垂直分库的介绍

按照业务拆分的方式称为垂直分片,又称为纵向拆分,它的核心理念是专库专用。 在拆分之前,一个数据库由多个数据表构成,每个表对应着不同的业务。而拆分之后,则是按照业务将表进行归类,分布到不同的数据库中,从而将压力分散至不同的数据库。

按业务域垂直分库是一种常见的数据库架构设计,用于提高系统的可扩展性和性能,更好得实现业务域的模块化管理,也带来安全性的提升等多方面优势。然而,也要考虑跨库查询对编码阶段带来一定的复杂性。

垂直分库的困难

早期产品所有业务表都在同一个库,访问没有限制,大部分查询需求都是直接书写表关联语法,不需要考虑跨库问题,编码阶段较为便捷。

现有产品若要使用按业务域垂直分库,首当其冲,需要考虑如下问题:

1、 如何解决跨域查询的技术问题,实现高效跨库查询;

2、 现有产品目前都采用模型元类JSON方式生成SQL,怎么更好和跨域查询场景贴合;

3、 拆分的粒度如何,如何划分业务域;

关于第三点,拆分的粒度,本篇文章暂不讨论,主要从技术实现可行性方面,探讨问题1和2。

跨域查询解决方案

在业界,垂直分库是一种常见的数据库架构设计,用于提高系统的可扩展性和性能。然而,跨库查询会带来一定的复杂性,通常解决方案如下:

1、 应用层聚合:在应用层进行数据聚合,分别从不同的数据库中查询所需的数据,然后在应用层进行合并。这种方式简单直接,但可能会增加网络延迟和应用层的复杂性。

2、 建设数据中心或数据仓库:使用数据实时或定时抽取机制,将需要跨库查询的数据同步到一个统一的查询数据库,然后在这个数据库上进行查询。这种方式适合于分析和报表场景。

3、 分布式查询引擎:使用 Apache Drill、Presto 等分布式查询引擎,来处理跨库查询。这些引擎能够连接多个数据源,并在它们之间执行查询。

4、 通过 API 网关将不同的微服务(每个服务对应一个数据库)进行整合,提供统一的接口供外部调用。API 网关可以负责聚合不同服务的响应。

5、 数据库中间件:使用 ShardingSphere、Cobar 等数据库中间件来处理跨库查询,这些中间件可以透明地处理路由和聚合,简化应用层的复杂性。

6、 …

结合实际分析

下文会针对需求背景下的垂直分库的技术方案进行分析梳理,当然这一过程也是要贴合医疗相关场景进行,诸如实际业务、票据、报表、综合查询等。

1、 诸如正常业务场景,要从设计上尽量从本业务域读取数据,尽量减少跨域查询的场景,适当使用分布式缓存。

2、 诸如报表和综合查询这类型的场景,最恰当的方式就是建设数据中心,实时性要求没那么高,可以接受适当的数据延迟。

3、 诸如票据查询这类型的场景,SQL语法涉及较多关联,拆库后,SQL很可能跨越多个库,同时实时性要求较高,这情况如何应对。

本文也主要讨论垂直分片背景下,票据这类对实时性要求较高的查询场景,如何解决跨库查询困难。


具体分案分析

1、 建设数据中心

描述

引入数据中心(Data Center)是解决跨库关联查询的一种有效方案。

● 数据同步,将分散在不同业务库中的相关数据,通过 ETL 工具或数据同步平台,实时或定时同步到数据中心。

● 数据整合,在数据中心对来自不同业务库的数据进行清洗、转换、整合,构建统一的数据模型和视图,消除数据孤岛,为跨库查询提供基础。

● 数据服务,数据中心可以对外提供统一的数据服务接口,例如 API、查询引擎等,供其他应用系统或用户进行跨库查询和数据分析。

分析

数据中心适合数据量大的场景,也规避了分库带来问题,可以实现语法自由组装,带来较高的查询效率。

类似公司早期建设的数据中心那样,抽取了全院数据,供各院内业务系统执行查询操作,十分便捷,也开放了统一查询服务。

但数据中心可能存在的问题是,及时性问题,即使依靠OGG等实时同步技术,也不能保证数据是及时、稳定、可靠的,早期项目因为OGG宕机造成的影响,屡见不鲜。

报表业务,实时性要求每那么高,可能比较适合查询数据中心,而票据业务,如果实时性相对高,那需要继续选择数据中心的话,那必须针对及时性做出进一步研究改进。

点评

报表和综合查询等业务,适合这一方案,但票据业务的查询实时性要求较高,建设数据中心方式不合适。

2、建设中间查询服务

描述

既然不想数据中心及时性存在不足,又不允许业务服务连接其他数据库,那要如何实现票据的跨库查询逻辑呢?比较直接可以想到的方式,就是创建中间查询服务。

具体措施就是,创建一个负责中间查询的统一查询服务,只有该服务允许访问多个数据源,其职责是对外提供查询接口,通过切换数据源的方式,从不同的业务数据库中查询SQL获取数据,并将结果在应用层进行聚合处理后,返回数据给票据系统。

当然,除了切换数据源,这里也可以通过查询具体业务服务提供的接口,来查询相应的数据,但这种方式可能不太灵活。

模拟传统实现

Step1、查询用户信息:
中间服务切库或调用用户服务的 API,传入用户ID,获取用户信息。
GET /api/users/{userId}

Step2、查询订单信息:
中间服务切库或调用订单服务的 API,传入用户ID,获取该用户的所有订单信息。
GET /api/orders?userId={userId}

Step3、聚合数据:
在中间服务中,将用户信息和订单信息进行聚合处理。
例如,将用户信息和订单列表组合成一个对象:
{
  "user": {
    "id": "123",
    "name": "John Doe",
    "email": "john@example.com"
  },
  "orders": [
    {  
      "userId": "123",
      "orderId": "456",
      "amount": 100,
      "status": "shipped"
    },
    {
      "userId": "123",
      "orderId": "789",
      "amount": 200,
      "status": "pending"
    }
  ]
}

Step4、组装聚合结果
[
  {
    "userId": "123",
    "orderId": "456",
    "amount": 100,
    "status": "shipped",
"name": "John Doe",
    "email": "john@example.com"
  },
  {
    "userId": "123",
    "orderId": "789",
    "amount": 200,
    "status": "pending",
"name": "John Doe",
    "email": "john@example.com"
  }
]

分析

这种方式的优点是:

1、 较为灵活,可以根据具体需求手动优化查询,选择最优的查询策略;

2、 开发者可以完全控制查询的执行过程,可能在某些特定场景下获得更好的性能;

3、 与业务系统解耦,查询职责清晰,业务系统不需要改造;

但缺点也是很明显的,包含但不限于:

1、 适合数据量较小的场景,否则应用层聚合可能会导致性能问题;

2、 复杂性的增长,需要手动管理多个数据库的连接和查询,代码复杂且容易出错;

3、 维护成本的增加,随着业务的增长,手动处理的代码可能会变得难以维护;

4、 性能瓶颈,如果查询逻辑不够优化,可能会导致性能瓶颈;

点评

手动编码的方式可能存在考虑不全面、以及性能问题,该方案待验证。

3、PostgreSQL FDW

描述

FDW 是 PostgreSQL 提供的一种扩展机制,允许 PostgreSQL 访问外部数据源,就像访问本地表一样。它通过创建一个外部数据源的“包装器”(Wrapper),将外部数据源映射到 PostgreSQL 中,并使用 SQL 语句进行查询。通过这种方式配置,最终可以在当前库,类似访问本地表的方式访问其他库的表。

传统模拟实现

-- Step1、安装 FDW 扩展:
-- PostgreSQL 自带了 postgres_fdw,用于访问其他 PostgreSQL 数据库。如果你需要访问其他类型的数据源,可能需要安装相应的 FDW 扩展。
-- 例如,安装 postgres_fdw:
CREATE EXTENSION postgres_fdw;

-- Step2、创建外部服务器:
-- 使用 CREATE SERVER 命令定义要连接的外部数据库。
CREATE SERVER foreign_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'remote_host', dbname 'remote_db', port '5432');

-- Step3、创建用户映射:
-- 为连接外部服务器的用户创建映射。
CREATE USER MAPPING FOR local_user
SERVER foreign_server
OPTIONS (user 'remote_user', password 'remote_password');

-- Step4、创建外部表:
-- 定义外部表,以便在本地查询时使用。
CREATE FOREIGN TABLE foreign_table (
    id integer,
    name text
)
SERVER foreign_server
OPTIONS (table_name 'remote_table');

-- Step5、执行查询:
-- 现在可以像查询本地表一样查询外部表。
SELECT * FROM foreign_table;

分析

初步了解功能,较为便捷,不需要额外技术投入,但可能存在如下问题:

1、如果有多个业务库,每个业务库都需要分别指定外部表,会增加维护的复杂性和压力;

2、都需要指定外部库,是否类似dblink方式,都存在当前库可以访问外部库的风险;

3、跨域关联查询的性能和复杂性支持程度,似乎比下面要介绍的ShardingSphere来得低;

点评

后续还要国产化数据库等多种数据库方式,同时在可维护和安全性都不太适宜,该方案暂不考虑。

4、ShardingSphere 联邦查询

描述

Apache ShardingSphere 是一款分布式 SQL 事务和查询引擎,可通过数据分片、弹性伸缩、加密等能力对任意数据库进行增强。

使用 ShardingSphere 进行数据库分片和联邦查询时,可以有效地简化多个业务库的管理,不需要在每个库中手动创建外部表。通过配置和透明的查询处理,ShardingSphere 提供了一种高效的方式来管理和查询分布式数据。这样可以大大降低维护压力,提高开发和运维的效率。

ShardingSphere最为核心的产品有两个:

1、ShardingJDBC 客户端分库分表

ShardingSphere-JDBC 定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。

2、ShardingProxy 服务端分库分表

ShardingSphere-Proxy 定位为透明化的数据库代理端,通过实现数据库二进制协议,对异构语言提供支持。 目前提供 MySQL 和 PostgreSQL 协议,透明化数据库操作,对 DBA 更加友好。

Tips:ShardingSphere 还可以用于数据分片、读写分离、分布式事务、数据库治理,当然不是这里的重点,不展开介绍。

模拟效果

这里以Proxy-Mysql方式为例说明,在Proxy的数据库,创建一个testdb数据库,不建任何表。

再分别创建demo1和demo2数据库,里面分别有user和phone表。

这时候,在testdb数据库,是可以直接关联查询方式查询到数据。

意味着,采用这种方式,我们的程序可以不需要任何改造,直接借助Proxy实现跨库查询。

【模拟步骤】

Step1、配置数据源:
在 ShardingSphere 的配置文件中,你需要定义 a 和 b 两个数据源。

Step2、配置分片规则:
你需要为 user 表和 order 表配置分片规则。虽然这两个表在不同的数据库中,但 ShardingSphere 会根据配置来处理它们的分片和路由。

Step3、编写 SQL 查询:
可以直接编写 SQL 查询,例如:
SELECT u.*, o.*
FROM a.user u
JOIN b.order o ON u.id = o.user_id
WHERE u.status = 'active';

Step4、执行查询:
当你通过 JDBC 或其他支持的方式执行这个查询时,ShardingSphere 会自动处理跨库的查询逻辑,包括路由、数据聚合等。

优点

1、 相比PostgreSQL FDW,ShardingSphere提供了更强大的功能和灵活性,在处理大数据集的 JOIN 操作时,ShardingSphere 联邦查询通常比 PostgreSQL FDW 表现更好(未验证);

2、 ShardingSphere 作为一个中间件,能够透明地处理跨库查询,开发者无需关心底层的复杂性,当然,也可以采用ShardingSphere-JDBC,然后创建中间服务完成对接;

3、 ShardingSphere 可以自动路由到正确的数据源,简化了查询逻辑;

缺点

1、 复杂性,配置和调试可能会比较复杂,尤其是在涉及多个数据源和复杂的分片规则时;

2、 限制,某些复杂的 SQL 语句可能不被支持,或者需要额外的调整;

3、 ShardingSphere 目前是5.5.0,联邦查询仍然在持续完善当中。

点评

根据分析,ShardingSphere 较为贴合跨域查询的需求场景。

是否适合处理复杂的的语法场景,以及性能如何,待验证。

5、公用查询数据冗余

描述

介于分业务库和建设数据中心的中间方案,将票据查询需要用到的业务数据提炼出来,这类型数据看是否合适与各个查用业务库冗余存储。这里如果采用 ShardingSphere 的话,也可以借助其广播表的能力。

Tips:ShardingSphere 的广播表(Broadcast Table)功能允许在分布式数据库环境中,将某些表的数据复制到所有的数据库节点上。这意味着这些表的数据在每个节点上都是相同的,所有节点都可以访问这些数据,而无需进行数据分片。

分析

这种方式需要从业务上分析是否可行,如果业务上允许,那这种方式将以较小投入获得票据跨域效果。

点评

票据覆盖业务可能较广,而且可能是动态的,无法准确评估需要公用冗余的业务表。

6、具体业务接口拼接

描述

传统的方式,各业务服务依然查自己的库,开放Feign接口给其他业务服务查询,将查询到的业务数据再进行汇总,这里还可细分两种方式:

1、一种是票据调具体服务A(通常是主表所在服务),再由A调其他服务,将结果进行聚合;

2、也是通过中间查询服务,分别查询各个业务数据,再进行聚合;

分析

优点是不需要考虑SQL组装,直接用最原始的编码方式解决问题;

缺点是每个业务服务都需要封装对外查询接口,接口的个数取决于功能设计,另外也存在数据量大时聚合的性能问题,以及是否支持全部场景;

从整体来看,这种方式可能还不如中间查询服务的方式。

点评

是否适合处理复杂的的语法场景,以及性能如何,待验证。

7、分布式查询引擎

描述

使用 Apache Drill、Presto 等分布式查询引擎,来处理跨库查询。这些引擎能够连接多个数据源,并在它们之间执行查询。

以 Apache Drill 为例,它和 ShardingSphere 都可以实现跨数据源查询,但是它们实现方式和应用场景有所不同。

Drill 是一个低延迟的分布式海量数据查询引擎,Drill 可以直接连接并查询多种数据源,包括 HDFS、HBase、MongoDB、Hive 等,而无需进行数据迁移。它使用 SQL 语法进行查询,并支持跨数据源的 JOIN 操作。

优点:能够处理海量数据和多种数据源,适用于数据分析和报表生成等场景。

局限:配置和使用相对复杂,对 SQL 语法有一定的扩展,更适合数据分析人员使用。

分析

据了解,适合大数据场景,性能接近ShardingSphere,待进一步验证。


总结陈词

本篇文章大体介绍了跨库查询的背景和常用方案,由于篇幅所限,会在后续篇章针对重点方案展开详细验证过程,并分享

最终的方案选择思路。

💗 后续也会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。


原文地址:https://blog.csdn.net/syb513812/article/details/143937343

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!