0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Java多線程應(yīng)用程序的數(shù)據(jù)存儲(chǔ)庫(kù)使用改進(jìn)

汽車玩家 ? 來源:黑馬程序員 ? 作者:黑馬程序員 ? 2020-05-05 20:46 ? 次閱讀

當(dāng)執(zhí)行的查詢數(shù)量很大時(shí),數(shù)據(jù)存儲(chǔ)庫(kù)通常是高要求系統(tǒng)的瓶頸。延遲批處理執(zhí)行器(DelayedBatchExecutor)是一個(gè)組件,可通過在Java多線程應(yīng)用程序中對(duì)所需查詢進(jìn)行批處理來減少所需查詢的數(shù)量。

n個(gè)查詢1個(gè)參數(shù)與1個(gè)查詢n個(gè)參數(shù)

讓我們假設(shè)一個(gè)Java應(yīng)用程序執(zhí)行對(duì)關(guān)系數(shù)據(jù)庫(kù)的查詢,以在給定其唯一標(biāo)識(shí)符(id)的情況下檢索Product實(shí)體(行)。

查詢看起來像這樣:

Java多線程應(yīng)用程序的數(shù)據(jù)存儲(chǔ)庫(kù)使用改進(jìn)

現(xiàn)在,要檢索n種產(chǎn)品,可以通過兩種方法進(jìn)行:

對(duì)一個(gè)參數(shù)執(zhí)行n個(gè)獨(dú)立查詢:

Java多線程應(yīng)用程序的數(shù)據(jù)存儲(chǔ)庫(kù)使用改進(jìn)

使用IN運(yùn)算符或OR的組合,對(duì)n個(gè)參數(shù)執(zhí)行一次查詢以同時(shí)檢索n個(gè)產(chǎn)品

后者在網(wǎng)絡(luò)流量和數(shù)據(jù)庫(kù)服務(wù)器資源(CPU和磁盤)方面更為有效,因?yàn)椋?/p>

到數(shù)據(jù)庫(kù)的往返次數(shù)為1,而不是n。

數(shù)據(jù)庫(kù)引擎針對(duì)n個(gè)參數(shù)優(yōu)化了其數(shù)據(jù)遍歷過程,即,它可能只需要對(duì)每個(gè)表進(jìn)行一次掃描而不是n次掃描。

這不僅適用于SELECT操作,而且適用于其他操作,例如INSERT,UPDATE和DELETE,實(shí)際上,JDBC API包括這些操作的批處理操作。

這同樣適用于NoSQL存儲(chǔ)庫(kù),其中大多數(shù)都顯式提供BULK操作。

延遲批處理執(zhí)行器

需要從數(shù)據(jù)庫(kù)檢索數(shù)據(jù)的Java應(yīng)用程序(如REST微服務(wù)或異步消息處理器)通常實(shí)現(xiàn)為多線程應(yīng)用程序(* 1),其中:

每個(gè)線程在其執(zhí)行的某個(gè)時(shí)刻執(zhí)行相同的查詢(每個(gè)查詢具有不同的參數(shù))。

并發(fā)線程數(shù)很高(每秒數(shù)十或數(shù)百)。

在這種情況下,數(shù)據(jù)庫(kù)很可能在很短的時(shí)間間隔內(nèi)多次執(zhí)行相同的查詢。

如前所述,如果將這1個(gè)參數(shù)的n個(gè)查詢替換為具有n個(gè)參數(shù)的單個(gè)等效查詢,則應(yīng)用程序?qū)⑹褂幂^少的數(shù)據(jù)庫(kù)服務(wù)器和網(wǎng)絡(luò)資源。

好消息是,可以通過以下涉及時(shí)間窗口的機(jī)制來實(shí)現(xiàn)它 :

第一個(gè)嘗試執(zhí)行查詢的線程將打開一個(gè)時(shí)間窗口,因此其參數(shù)存儲(chǔ)在列表中,并且該線程已暫停。在時(shí)間窗口內(nèi)執(zhí)行相同查詢的其余線程會(huì)將其參數(shù)添加到列表中,并且也會(huì)被暫停。此時(shí),尚未在數(shù)據(jù)庫(kù)上執(zhí)行任何查詢。

時(shí)間窗口結(jié)束或列表已滿(預(yù)先定義了最大容量限制)后,便會(huì)使用列表中存儲(chǔ)的所有參數(shù)執(zhí)行單個(gè)查詢。最后,一旦數(shù)據(jù)庫(kù)提供了該查詢的結(jié)果,每個(gè)線程將接收其相應(yīng)的結(jié)果,并且所有線程將自動(dòng)恢復(fù)。

我為自己(延遲批處理執(zhí)行器)構(gòu)建了此機(jī)制的簡(jiǎn)單輕便的實(shí)現(xiàn),可以輕松在新的或現(xiàn)有的應(yīng)用程序中使用。它基于 Reactor庫(kù),并且使用帶有通量的Flux緩沖發(fā)布者作為參數(shù)列表。

使用延遲批處理執(zhí)行器的吞吐量和延遲分析

讓我們假設(shè)一個(gè)針對(duì)產(chǎn)品的REST微服務(wù),它公開了一個(gè)端點(diǎn),用于從給定的數(shù)據(jù)庫(kù)中檢索產(chǎn)品數(shù)據(jù) productId。如果不使用 延遲批處理執(zhí)行器,則說到端點(diǎn)每秒有200次命中,則數(shù)據(jù)庫(kù)每秒執(zhí)行200個(gè)查詢。如果端點(diǎn)使用的 時(shí)間窗口延遲批處理執(zhí)行器配置為50毫秒,最大容量 = 10個(gè)參數(shù),則數(shù)據(jù)庫(kù)每秒僅執(zhí)行20個(gè)查詢,每個(gè)參數(shù)10個(gè)參數(shù),但代價(jià)是最多在50毫秒內(nèi)增加延遲(* 2)對(duì)于每個(gè)線程執(zhí)行。

換句話說,為了將等待時(shí)間增加50 ms(* 2),在保持系統(tǒng)整體吞吐量的同時(shí),數(shù)據(jù)庫(kù)每秒收到的查詢減少了10倍。

其他有趣的配置:

窗口時(shí)間 = 100毫秒,最大容量 = 20個(gè)參數(shù)→20個(gè)參數(shù)的10個(gè)查詢(查詢減少20倍)

窗口時(shí)間 = 500毫秒,最大容量 = 100個(gè)參數(shù)→2個(gè)查詢,共100個(gè)參數(shù)(查詢減少100倍)

延遲批處理執(zhí)行器在行動(dòng)

深入研究Product微服務(wù)示例,假設(shè)對(duì)于每個(gè)傳入的HTTP請(qǐng)求,微服務(wù)的控制器都要求我們檢索提供其ID的Product(Java Bean),因此它將調(diào)用該方法:

public Product getProductById(Integer productId) DAO組件的ProductDAO。

讓我們看看不帶和帶的DAO的實(shí)現(xiàn) 延遲批處理執(zhí)行器。

沒有延遲批處理執(zhí)行器

Java多線程應(yīng)用程序的數(shù)據(jù)存儲(chǔ)庫(kù)使用改進(jìn)

使用延遲批處理執(zhí)行器

Java多線程應(yīng)用程序的數(shù)據(jù)存儲(chǔ)庫(kù)使用改進(jìn)

首先,延遲批處理執(zhí)行器必須在DAO中創(chuàng)建的實(shí)例,在本例中為delayedBatchExecutorProductById。它需要以下三個(gè)參數(shù):

時(shí)間窗口(在此示例中為50毫秒)

參數(shù)列表的最大容量(在此示例中為10個(gè)參數(shù))

將使用參數(shù)列表調(diào)用的方法(我們將在后面詳細(xì)介紹)。在此示例中,方法是retrieveProductsByIds

注意:我們將在后面看到為什么延遲批處理執(zhí)行器的標(biāo)識(shí)(delayedBatchExecutor ProductById)是該類的實(shí)例DelayedBatchExecutor2

其次,DAO方法public Product getProductById(Integer productId)已經(jīng)過重構(gòu),可以簡(jiǎn)單地調(diào)用實(shí)例的execute方法,僅此delayedBatchExecutor ProductById而已。所有的“魔術(shù)”都是由DelayedBatchExecutor。

之所以delayedBatchExecutor ProductById是的實(shí)例,DelayedBatchExecutor2是因?yàn)槠鋏xecute方法返回一個(gè)Product實(shí)例并接收一個(gè)Integer實(shí)例作為其參數(shù)。因此,我們有: DelayedBatchExecutor2.

如果execute方法需要接收兩個(gè)參數(shù)(例如an Integer和a String)并返回的實(shí)例Product,則定義為DelayedBatchExecutor3 ,依此類推。

最后,該 retrieveProductsByIds方法必須返回a List并接收a List作為參數(shù)。

如果我們使用DelayedBatchExecutor3,則retrieveProductsByIds必須是List retrieveProductsByIds(List productIdsList, List stringList)

就是這樣。

一旦運(yùn)行,執(zhí)行控制器邏輯的并發(fā)線程將getProductById(Integer id)在某個(gè)時(shí)候調(diào)用該方法,并且該方法將返回相應(yīng)的乘積。他們不會(huì)知道他們實(shí)際上可能已經(jīng)被暫停并恢復(fù)了延遲批處理執(zhí)行器.

超越數(shù)據(jù)倉(cāng)庫(kù)

盡管本文與數(shù)據(jù)存儲(chǔ)庫(kù)有關(guān), 延遲批處理執(zhí)行器 但是可以在其他上下文中使用,例如,在對(duì)REST微服務(wù)的請(qǐng)求中。同樣,用一個(gè)參數(shù)啟動(dòng)n個(gè)GET請(qǐng)求要比使用n個(gè)參數(shù)啟動(dòng)1個(gè)GET要昂貴得多。

延遲批處理執(zhí)行器的改進(jìn)

我創(chuàng)建 延遲批處理執(zhí)行器并使用了一段時(shí)間,以有效地處理由個(gè)人項(xiàng)目中的并發(fā)線程啟動(dòng)的多個(gè)查詢的執(zhí)行。我相信它對(duì)其他人也可能有用,所以我決定將其公開。

話雖如此,仍有很大的改進(jìn)空間并可以擴(kuò)展所提供的功能 延遲批處理執(zhí)行器。最有趣的是能夠根據(jù)執(zhí)行的特定條件動(dòng)態(tài)更改參數(shù) 延遲批處理執(zhí)行器(窗口時(shí)間和最大容量),以最大程度地減少等待時(shí)間,同時(shí)利用具有n個(gè)參數(shù)的查詢。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2952

    瀏覽量

    104489
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    504

    瀏覽量

    19636
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Python中多線程和多進(jìn)程的區(qū)別

    Python作為一種高級(jí)編程語(yǔ)言,提供了多種并發(fā)編程的方式,其中多線程與多進(jìn)程是最常見的兩種方式之一。在本文中,我們將探討Python中多線程與多進(jìn)程的概念、區(qū)別以及如何使用線程池與進(jìn)程池來提高并發(fā)執(zhí)行效率。
    的頭像 發(fā)表于 10-23 11:48 ?234次閱讀
    Python中<b class='flag-5'>多線程</b>和多進(jìn)程的區(qū)別

    華納云:java web和java有什么區(qū)別java web和java有什么區(qū)別

    的平臺(tái),Java可以用于開發(fā)桌面應(yīng)用程序、移動(dòng)應(yīng)用程序、企業(yè)級(jí)應(yīng)用程序等。 – Java Web是Jav
    的頭像 發(fā)表于 07-16 13:35 ?619次閱讀
    華納云:<b class='flag-5'>java</b> web和<b class='flag-5'>java</b>有什么區(qū)別<b class='flag-5'>java</b> web和<b class='flag-5'>java</b>有什么區(qū)別

    多線程設(shè)計(jì)模式到對(duì) CompletableFuture 的應(yīng)用

    最近在開發(fā) 延保服務(wù) 頻道頁(yè)時(shí),為了提高查詢效率,使用到了多線程技術(shù)。為了對(duì)多線程方案設(shè)計(jì)有更加充分的了解,在業(yè)余時(shí)間讀完了《圖解 Java 多線程設(shè)計(jì)模式》這本書,覺得收獲良多。本篇
    的頭像 發(fā)表于 06-26 14:18 ?253次閱讀
    從<b class='flag-5'>多線程</b>設(shè)計(jì)模式到對(duì) CompletableFuture 的應(yīng)用

    bootloader開多線程做引導(dǎo)程序,跳app初始化后直接進(jìn)hardfualt,為什么?

    如標(biāo)題,想做一個(gè)遠(yuǎn)程升級(jí)的項(xiàng)目,bootloader引導(dǎo)區(qū)域和app都是開多線程跑的,就是自己寫了個(gè)小的任務(wù)調(diào)度器,沒什么功能主要是想讓程序快速的響應(yīng),延時(shí)不會(huì)對(duì)其他程序造成堵塞,程序
    發(fā)表于 04-18 06:07

    鴻蒙OS開發(fā)實(shí)例:【ArkTS類庫(kù)多線程CPU密集型任務(wù)TaskPool】

    CPU密集型任務(wù)是指需要占用系統(tǒng)資源處理大量計(jì)算能力的任務(wù),需要長(zhǎng)時(shí)間運(yùn)行,這段時(shí)間會(huì)阻塞線程其它事件的處理,不適宜放在主線程進(jìn)行。例如圖像處理、視頻編碼、數(shù)據(jù)分析等。 基于多線程
    的頭像 發(fā)表于 04-01 22:25 ?772次閱讀
    鴻蒙OS開發(fā)實(shí)例:【ArkTS類<b class='flag-5'>庫(kù)</b><b class='flag-5'>多線程</b>CPU密集型任務(wù)TaskPool】

    鴻蒙APP開發(fā):【ArkTS類庫(kù)多線程】TaskPool和Worker的對(duì)比

    TaskPool(任務(wù)池)和Worker的作用是為應(yīng)用程序提供一個(gè)多線程的運(yùn)行環(huán)境,用于處理耗時(shí)的計(jì)算任務(wù)或其他密集型任務(wù)??梢杂行У乇苊膺@些任務(wù)阻塞主線程,從而最大化系統(tǒng)的利用率,降低整體資源消耗,并提高系統(tǒng)的整體性能。
    的頭像 發(fā)表于 03-26 22:09 ?572次閱讀
    鴻蒙APP開發(fā):【ArkTS類<b class='flag-5'>庫(kù)</b><b class='flag-5'>多線程</b>】TaskPool和Worker的對(duì)比

    java實(shí)現(xiàn)多線程的幾種方式

    Java實(shí)現(xiàn)多線程的幾種方式 多線程是指程序中包含了兩個(gè)或以上的線程,每個(gè)線程都可以并行執(zhí)行不同
    的頭像 發(fā)表于 03-14 16:55 ?550次閱讀

    ArkTS語(yǔ)言基礎(chǔ)類庫(kù)-解析

    Promise和async/await等標(biāo)準(zhǔn)的JS異步并發(fā)能力。 TaskPool為應(yīng)用程序提供一個(gè)多線程的運(yùn)行環(huán)境,降低整體資源的消耗、提高系統(tǒng)的整體性能,開發(fā)者無需關(guān)心線程實(shí)例的生命周期。 Worker支持
    發(fā)表于 02-20 16:44

    redis多線程還能保證線程安全嗎

    是單線程的,多個(gè)客戶端請(qǐng)求會(huì)按序執(zhí)行,每個(gè)請(qǐng)求使用一個(gè)線程完成,這樣可以避免多線程之間的競(jìng)爭(zhēng)條件和鎖等帶來的開銷。但是,由于Redis是存儲(chǔ)內(nèi)存中的
    的頭像 發(fā)表于 12-05 10:28 ?1635次閱讀

    redis使用多線程處理操作命令

    Redis 是一個(gè)使用多線程處理操作命令的開源內(nèi)存數(shù)據(jù)庫(kù)系統(tǒng)。它以其高性能、可擴(kuò)展性和靈活性而聞名,通常被用作緩存、消息代理和數(shù)據(jù)存儲(chǔ)等各種應(yīng)用場(chǎng)景。在本文中,我們將詳盡、詳實(shí)、細(xì)致地
    的頭像 發(fā)表于 12-05 10:25 ?531次閱讀

    mfc多線程編程實(shí)例

    (圖形用戶界面)應(yīng)用程序的開發(fā)。在這篇文章中,我們將重點(diǎn)介紹MFC中的多線程編程。 多線程編程在軟件開發(fā)中非常重要,它可以實(shí)現(xiàn)程序的并發(fā)執(zhí)行,提高
    的頭像 發(fā)表于 12-01 14:29 ?1377次閱讀

    開發(fā)java應(yīng)用程序的基本步驟是

    ava是一種面向?qū)ο蟮木幊陶Z(yǔ)言,廣泛用于開發(fā)各種類型的應(yīng)用程序。在開發(fā)Java應(yīng)用程序時(shí),有一些基本步驟需要遵循,以確保應(yīng)用程序的正確性和可靠性。 1.確定需求:這是開發(fā)任何
    的頭像 發(fā)表于 11-28 16:52 ?1494次閱讀

    如何查看java程序的內(nèi)存分布

    程序計(jì)數(shù)器: 程序計(jì)數(shù)器是一塊較小的內(nèi)存空間,它的作用是指示當(dāng)前線程所執(zhí)行的字節(jié)碼指令的行號(hào)。在多線程環(huán)境下,每個(gè)線程都有一個(gè)獨(dú)立的
    的頭像 發(fā)表于 11-23 14:47 ?987次閱讀

    多線程如何保證數(shù)據(jù)的同步

    多線程編程是一種并發(fā)編程的方法,意味著程序中同時(shí)運(yùn)行多個(gè)線程,每個(gè)線程可獨(dú)立執(zhí)行不同的任務(wù),共享同一份數(shù)據(jù)。由于
    的頭像 發(fā)表于 11-17 14:22 ?1112次閱讀

    多線程并發(fā)查詢oracle數(shù)據(jù)庫(kù)

    多線程并發(fā)查詢Oracle數(shù)據(jù)庫(kù)是指在同一時(shí)間內(nèi)有多個(gè)線程同時(shí)執(zhí)行數(shù)據(jù)庫(kù)查詢操作。這種并發(fā)查詢的方式可以提高系統(tǒng)的吞吐量和響應(yīng)速度,提高數(shù)據(jù)庫(kù)
    的頭像 發(fā)表于 11-17 14:22 ?3561次閱讀