溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

發(fā)布時(shí)間:2023-03-15 11:40:07 來(lái)源:億速云 閱讀:90 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢”文章能幫助大家解決問(wèn)題。

服務(wù)的邊界職責(zé) 

大數(shù)據(jù)層取數(shù)統(tǒng)一實(shí)現(xiàn)入口(數(shù)據(jù)源的路由,ADB/CK/HBASE... 大數(shù)據(jù)操作層數(shù)據(jù)源的路由)

支持多實(shí)例、多庫(kù)、多表的異構(gòu)數(shù)據(jù)查詢

通過(guò) 查詢 語(yǔ)義分析+元信息解析,拆解 查詢輸入 中的異構(gòu)數(shù)據(jù)源處理,所有異構(gòu)數(shù)據(jù)處理采用異步 Callback 方式

解決的問(wèn)題 

多個(gè)數(shù)據(jù)來(lái)源寫入到不同實(shí)例、不同庫(kù)中,并且一個(gè)圈選可以支持圈多個(gè)實(shí)例(不同庫(kù))中的標(biāo)簽、事件數(shù)據(jù)

單表數(shù)據(jù)量過(guò)大,目前只能通過(guò)壓縮保留時(shí)間解決,需要可以進(jìn)行按時(shí)間段拆表分表查詢數(shù)據(jù)

單實(shí)例配置上限問(wèn)題,實(shí)例升級(jí)配置是有上限的成本也很高,支持多實(shí)例后就可以使用多實(shí)例中等配置無(wú)限擴(kuò)展

無(wú)法支持場(chǎng)景 

同一個(gè)圈選不支持跨不同類型數(shù)據(jù)庫(kù)混用,類似一個(gè)圈選包含了ADB+CK兩種類型數(shù)據(jù)庫(kù)的配置

創(chuàng)建庫(kù)表的時(shí)候,需要有原則:

不同實(shí)例的庫(kù)、表名字如果完全一樣,默認(rèn)他們代表的業(yè)務(wù)語(yǔ)意也是一致的,如果不一致會(huì)出現(xiàn)問(wèn)題

場(chǎng)景描述: 

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

架構(gòu)全景圖 

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

傳統(tǒng)數(shù)據(jù)庫(kù)中間件的幾種模式: 

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

種類

優(yōu)勢(shì)

缺點(diǎn)

JAR方式嵌入到應(yīng)用端

  • 接入簡(jiǎn)單,無(wú)需單獨(dú)部署獨(dú)立服務(wù)

  • 小數(shù)據(jù)量場(chǎng)景下速度很快,比原先直連JDBC性能損失很低

  • 調(diào)試使用簡(jiǎn)單

  • 與應(yīng)用資源公用,互相影響

  • 大數(shù)量場(chǎng)景下會(huì)有很多連帶問(wèn)題

  • 對(duì)應(yīng)用端代碼有一定的入侵性

  • 擴(kuò)展性差

中間件方式存在,偽裝數(shù)據(jù)庫(kù)代理層

  • 對(duì)應(yīng)用代碼無(wú)入侵,只需要修改配置層

  • 資源獨(dú)立,不會(huì)有捆綁風(fēng)險(xiǎn)

  • 可以分層獨(dú)立擴(kuò)展,可擴(kuò)展性強(qiáng)

  • 適合大數(shù)據(jù)量的場(chǎng)景中

  • 讓應(yīng)用層基本無(wú)感知中間件的存在

  • 開發(fā)維護(hù)成本高

  • 中間件編碼復(fù)雜,需要對(duì)接開源數(shù)據(jù)庫(kù)的各種代理協(xié)議以及字節(jié)碼轉(zhuǎn)換邏輯

  • 小數(shù)據(jù)量的請(qǐng)求場(chǎng)景中性能比直連的性能損耗嚴(yán)重30%~40%

  • 在JDBC上面無(wú)法再次擴(kuò)展,傳輸協(xié)議和模型固定

中間件方式存在,不偽裝數(shù)據(jù)庫(kù)代理層

  • 中間件開發(fā)簡(jiǎn)單,無(wú)需對(duì)接各種開源數(shù)據(jù)庫(kù)的代理轉(zhuǎn)換協(xié)議

  • 資源獨(dú)立,不會(huì)有捆綁風(fēng)險(xiǎn)

  • 可以分層獨(dú)立擴(kuò)展,可擴(kuò)展性強(qiáng)

  • 適合大數(shù)據(jù)量的場(chǎng)景中

  • 脫離應(yīng)用端到中間件的JDBC協(xié)議,擴(kuò)展性自由

  • 應(yīng)用接入層會(huì)有感知,配置層缺失了原先的JDBC配置,SQL操作也無(wú)法使用原先的數(shù)據(jù)庫(kù)框架而是要將SQL通過(guò)Dubbo方式交互

  • 小數(shù)據(jù)量的請(qǐng)求場(chǎng)景中性能比直連的性能損耗嚴(yán)重30%~40%

模塊說(shuō)明:

模塊名

執(zhí)行邊界

輸入描述

輸出描述

代理模塊

模型接入

請(qǐng)求模型

結(jié)果模型

運(yùn)行模式模塊

執(zhí)行線程池處理

在線模式/離線模式

執(zhí)行線程池

計(jì)劃模塊

離線模式和在線模式都需要?jiǎng)?chuàng)建入口執(zhí)行計(jì)劃和執(zhí)行日志

離線異構(gòu)取數(shù)場(chǎng)景,每一層內(nèi)嵌取數(shù)都是單獨(dú)計(jì)劃和執(zhí)行日志,完成后上推執(zhí)行計(jì)劃

計(jì)劃存在父子計(jì)劃任務(wù)

創(chuàng)建計(jì)劃

查詢可執(zhí)行計(jì)劃任務(wù)數(shù)據(jù)

更新計(jì)劃狀態(tài)

可執(zhí)行的計(jì)劃任務(wù)

解析模塊

解析查詢請(qǐng)求的參數(shù),轉(zhuǎn)換成 AST 語(yǔ)法樹

查詢語(yǔ)句,可以是 SQL,可以是 JSON

也可以是規(guī)則XML

AST語(yǔ)法樹對(duì)象、核心解析模型

權(quán)限校驗(yàn)?zāi)K

判斷token是否有使用的實(shí)例、庫(kù)、表權(quán)限

根據(jù)token,庫(kù),表查詢到有權(quán)限的實(shí)例信息

是否有權(quán)限,以及有權(quán)限的實(shí)例信息

路由模塊

獲取有權(quán)限且最優(yōu)的實(shí)例

請(qǐng)求來(lái)源的系統(tǒng),請(qǐng)求來(lái)源的庫(kù),請(qǐng)求來(lái)源的表

符合權(quán)限校驗(yàn)的實(shí)例 ID+庫(kù)信息

連接池管理模塊

管理各種數(shù)據(jù)源的連接池

庫(kù)元信息

連接池連接

數(shù)據(jù)執(zhí)行模塊

取數(shù)執(zhí)行邏輯,根據(jù)改寫后的SQL進(jìn)行分實(shí)例分庫(kù)分表查詢,最終匯總到臨時(shí)表,在進(jìn)行完整原始SQL改寫的執(zhí)行

大數(shù)據(jù)量臨時(shí)表通過(guò)生成SQL執(zhí)行語(yǔ)句導(dǎo)入到OSS

取數(shù)語(yǔ)句分析拆分后的執(zhí)行語(yǔ)句

異構(gòu)數(shù)據(jù)的話返回實(shí)例名+庫(kù)名+表名

非異構(gòu)數(shù)據(jù)返回?cái)?shù)據(jù)結(jié)果集

計(jì)費(fèi)模塊

根據(jù)臨時(shí)表數(shù)據(jù)量,跨庫(kù)+跨表數(shù)量進(jìn)行公式化計(jì)費(fèi)

AST語(yǔ)法樹對(duì)象、SQL

最終成本費(fèi)用

復(fù)用模塊

數(shù)據(jù)復(fù)用的邏輯判斷

執(zhí)行語(yǔ)句,間隔時(shí)間

是否復(fù)用模型

熔斷模塊

對(duì)執(zhí)行中的計(jì)劃進(jìn)行強(qiáng)制熔斷,沒(méi)有任何業(yè)務(wù)邏輯,只是提供熔斷標(biāo)示

計(jì)劃ID

是否熔斷

項(xiàng)目模塊依賴描述:(開發(fā)分之:multiple-instances)(項(xiàng)目名:datacenter-night-watchman) 

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

模塊間邏輯交互

  • 支持單實(shí)例多庫(kù)查詢

  • 支持多實(shí)例多庫(kù)查詢

  • 支持單實(shí)例單庫(kù)查詢

  • 異構(gòu)數(shù)據(jù)統(tǒng)一異步匯總臨時(shí)表,非異構(gòu)數(shù)據(jù)默認(rèn)實(shí)時(shí)傳輸返回

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

運(yùn)行模式模塊  

  • 在線模式(只支持非異構(gòu)取數(shù)),先落地實(shí)時(shí)計(jì)劃表,然后實(shí)時(shí)交互查詢數(shù)據(jù),返回?cái)?shù)據(jù)

  • 離線模式(支持異構(gòu)和非異構(gòu)取數(shù)),先實(shí)時(shí)創(chuàng)建父子計(jì)劃,然后返回父計(jì)劃ID,異步調(diào)度執(zhí)行計(jì)劃進(jìn)行取數(shù),接入方通過(guò)計(jì)劃ID查詢計(jì)劃狀態(tài)和異構(gòu)存儲(chǔ)表

  • 每一個(gè)計(jì)劃都對(duì)應(yīng)一個(gè)取數(shù)任務(wù)

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

計(jì)劃表結(jié)構(gòu):(Mysql-watchman庫(kù)) 

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

CREATE TABLE `extract_data_calculation_log`  (   `id` bigint(32) NOT NULL,   `exe_id` bigint(32) NOT NULL COMMENT '計(jì)劃表主鍵ID',   `last_exe_id` bigint(32) NOT NULL COMMENT '最大用戶ID',   `exe_state` tinyint(1) NOT NULL COMMENT '執(zhí)行狀態(tài),1-執(zhí)行中 2-執(zhí)行成功  3-執(zhí)行失敗',   `create_time` datetime(0) NOT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '記錄創(chuàng)建時(shí)間',   `updat_time` datetime(0) NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '記錄更新時(shí)間',   `version` int(8) NOT NULL COMMENT '記錄版本號(hào)',   `exe_quantity` bigint(32) NULL COMMENT '數(shù)據(jù)冗余字段,執(zhí)行的數(shù)據(jù)量',   PRIMARY KEY (`id`),   INDEX `exe`(`circle_exe_id`) ) COMMENT = '提取數(shù)據(jù)日志表';  
CREATE TABLE `extract_data_execute`  (   `id` bigint(32) NOT NULL,   `storage_result` json NOT NULL COMMENT '{"type":"存儲(chǔ)類型,1-adb  2-rmq  3-oss  4-ck","result":"adb/ck 代表表名,rmq代表topic,oss代表存儲(chǔ)地址","example":"實(shí)例地址","database":"庫(kù)地址"}',   `create_time` timestamp(0) NOT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '記錄創(chuàng)建時(shí)間',   `updat_time` timestamp(0) NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '記錄更新時(shí)間',   `plan_logic` tinyint(1) NOT NULL DEFAULT 1 COMMENT '計(jì)劃邏輯,1-正常 2-暫不執(zhí)行',   `priority` int(8) NOT NULL DEFAULT 1 COMMENT '任務(wù)優(yōu)先級(jí),數(shù)字越小優(yōu)先級(jí)越高',   `data_type` tinyint(1) NOT NULL COMMENT '執(zhí)行模式,1-立即執(zhí)行  2-離線執(zhí)行',   `parent_id` bigint(0) NOT NULL DEFAULT 0 COMMENT '父級(jí)計(jì)劃ID ',   `rewrite_result` json NOT NULL COMMENT '改寫模型',   PRIMARY KEY (`id`) ) COMMENT = '數(shù)據(jù)取數(shù)計(jì)劃表';  
ALTER TABLE `extract_data_calculation_log` ADD CONSTRAINT `exe` FOREIGN KEY (`circle_exe_id`) REFERENCES `extract_data_execute` (`id`); 
ALTER TABLE `extract_data_execute` ADD CONSTRAINT `config` FOREIGN KEY (`circle_config_id`) REFERENCES `circle_config` (`id`);

查詢解析模塊 

  • 解析模塊使用shardingjdbc5內(nèi)部的sql解析引擎,druid很久不更新了,很多新的語(yǔ)法支持不好

  • 解析模塊代碼寫到底層工具包,包含SQL、JSON解析

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

Sharding5 的解析引擎已經(jīng)支持多種數(shù)據(jù)庫(kù)包含各種數(shù)據(jù)庫(kù)新增的函數(shù)語(yǔ)法解析,主要是Mysql、Pg、Sqlserver、Oracle 

<dependency>     
  <groupId>org.apache.shardingsphere</groupId>     
  <artifactId>shardingsphere-sql-parser-engine</artifactId> 
</dependency> 
 
<dependency>     
  <groupId>org.apache.shardingsphere</groupId>     
  <artifactId>shardingsphere-sql-parser-mysql</artifactId> 
</dependency> 
 
<dependency>     
  <groupId>org.apache.shardingsphere</groupId>     
  <artifactId>shardingsphere-infra-federation-optimizer</artifactId> </dependency> 
  
<dependency>     
  <groupId>org.apache.calcite</groupId>     
  <artifactId>calcite-core</artifactId> 
</dependency>

Clickhouse和ADB目前都是支持原生mysql協(xié)議的,那么進(jìn)入的數(shù)據(jù)庫(kù)解析方言使用mysql引擎即可 

ShardingSphere解析引擎模塊代碼示例: 

public static void main(String[] args) {     
    CacheOption cacheOption = new CacheOption( 128, 1024L, 4 );     			  SQLParserEngine sqlParserEngine = new SQLParserEngine( "MySQL", cacheOption, true );     
    ParseContext parseContext = sqlParserEngine.parse( "select * from user where id in (select id from city where id = 11);", true );     
    SQLVisitorEngine visitorEngine = new SQLVisitorEngine( "MySQL", "STATEMENT", new Properties() );     
    SelectStatement selectStatement = visitorEngine.visit( parseContext );      	SelectStatementConverter selectStatementConverter = new SelectStatementConverter();     
    SqlSelect sqlSelect = (SqlSelect) selectStatementConverter.convertToSQLNode( selectStatement );     
    System.out.println( sqlSelect.getSelectList() );     
    System.out.println( sqlSelect.getFrom() );     
    System.out.println( sqlSelect.getWhere() ); 
}  
輸出結(jié)果: 查詢字段:* 查詢表:user 查詢條件:`id` IN (SELECT `id` FROM `city` WHERE `id` = 11)

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

解析模塊注意點(diǎn): 

  • 解析引擎只做原始解析,然后封裝到輸出模型中

  • 解析輸出模型需要考慮嵌套SQL的模型存在以及同層級(jí)union的模型存在

  • 解析輸出模型聚合根已經(jīng)調(diào)整好,缺失的字段或者模型在進(jìn)行微調(diào)

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

權(quán)限校驗(yàn)?zāi)K:(此模塊代碼接口預(yù)留,邏輯暫不實(shí)現(xiàn)) 

  • 有了圈選解析模型,已經(jīng)獲取到使用的實(shí)例、庫(kù)、表相關(guān)所有信息了

  • 根據(jù)入?yún)oken判斷實(shí)例和庫(kù)的權(quán)限情況

  • 表結(jié)構(gòu)需要有,數(shù)據(jù)需要按照規(guī)范填入,后期做代碼邏輯實(shí)現(xiàn)

  • 暫時(shí)無(wú)實(shí)現(xiàn),所以默認(rèn)所有實(shí)例都可用,全部返回到模型

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

改寫引擎 

  • 負(fù)責(zé)將可能涉及到多實(shí)例、多庫(kù)、多表的聯(lián)合查詢拆分

  • 拆分過(guò)程中需要考慮聯(lián)合查詢的where條件、group by 條件、order by 條件

  • 如果解析模型傳遞過(guò)來(lái)的數(shù)據(jù)中,不存在跨庫(kù)場(chǎng)景,那么改寫引擎不進(jìn)行任何操作邏輯

改寫案例描述: 

  • 將復(fù)合嵌套的SQL平鋪,按照庫(kù)為單位,最內(nèi)層開始為最小粒度

  • 每一層都會(huì)同時(shí)存在4中類型改寫語(yǔ)句

  • 取數(shù)語(yǔ)句

  • 替換符語(yǔ)句

  • 聚合語(yǔ)句


  • 建表語(yǔ)句

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

改寫模型描述: 

怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢

路由模塊 

  • 通過(guò)權(quán)限模型中返回的有權(quán)限的實(shí)例,判斷最優(yōu)的CPU實(shí)例

  • 根據(jù)實(shí)例+庫(kù)名去連接池模塊中獲取相應(yīng)的連接池信息

  • 分庫(kù)分表邏輯后續(xù)實(shí)現(xiàn),暫不做設(shè)計(jì)

鏈接池模塊 

需要支持通配符方式的連接配置,案例:

# 同一個(gè)實(shí)例下不同庫(kù)的通配連接 db.datasource.watchman.jdbcUrl=jdbc:mysql://A.mysql.rds.aliyuncs.com:3306/{db1,db2,db3} 
db.datasource.watchman.username={A.db1:dw_datacenter_A,A.db2:dw_datacenter_B,A.db3:dw_datacenter_C} db.datasource.watchman.password= {A.db1:password_A,A.db2:password_B,A.db3:password_C}   
# 不同實(shí)例下同庫(kù)的通配連接 db.datasource.watchman.jdbcUrl=jdbc:mysql://{A,B}.mysql.rds.aliyuncs.com:3306/db1 
db.datasource.watchman.username={A.db1:dw_datacenter_A,B.db1:dw_datacenter_B} db.datasource.watchman.password= {A.db1:password_A,B.db2:password_B}   
# 同一個(gè)實(shí)例下不同庫(kù)的區(qū)間通配連接 db.datasource.watchman.jdbcUrl=jdbc:mysql://A.mysql.rds.aliyuncs.com:3306/{db[1~20]} 
db.datasource.watchman.username={A.db1:dw_datacenter_A,A.db2:dw_datacenter_B,A.db3:dw_datacenter_C,A.db...} db.datasource.watchman.password= {A.db1:password_A,A.db2:password_B,A.db3:password_C,A.db...}   
# 多數(shù)據(jù)源連接配置 db.datasource.watchman.jdbcUrl.ck=jdbc:mysql://A.mysql.rds.aliyuncs.com:3306/{db[1~20]} 
db.datasource.watchman.username.ck={A.db1:dw_datacenter_A,A.db2:dw_datacenter_B,A.db3:dw_datacenter_C,A.db...} db.datasource.watchman.password.ck= {A.db1:password_A,A.db2:password_B,A.db3:password_C,A.db...}  db.datasource.watchman.jdbcUrl.adb=jdbc:mysql://A.mysql.rds.aliyuncs.com:3306/{db[1~20]} 
db.datasource.watchman.username.adb={A.db1:dw_datacenter_A,A.db2:dw_datacenter_B,A.db3:dw_datacenter_C,A.db...} db.datasource.watchman.password.adb= {A.db1:password_A,A.db2:password_B,A.db3:password_C,A.db...}

鏈接池內(nèi)部使用druid框架,沒(méi)有單獨(dú)對(duì)數(shù)據(jù)源進(jìn)行druid參數(shù)配置的話全部采用守夜人默認(rèn)提供的運(yùn)行參數(shù),如果需要單獨(dú)對(duì)不同數(shù)據(jù)源進(jìn)行配置,那么原先druid的配置加上對(duì)應(yīng)的后綴

db.datasource.watchman.jdbcUrl.adb=jdbc:mysql://A.mysql.rds.aliyuncs.com:3306/{db[1~20]} 
db.datasource.watchman.username.adb={A.db1:dw_datacenter_A,A.db2:dw_datacenter_B,A.db3:dw_datacenter_C,A.db...} db.datasource.watchman.password.adb= {A.db1:password_A,A.db2:password_B,A.db3:password_C,A.db...}

關(guān)于“怎么用Java設(shè)計(jì)實(shí)現(xiàn)多實(shí)例多庫(kù)查詢”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI