欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java 高并發(fā)編程之最實用的任務(wù)執(zhí)行架構(gòu)設(shè)計建議收藏

 更新時間:2021年10月28日 11:37:37   作者:劍客阿良_ALiang  
高并發(fā)(High Concurrency)是互聯(lián)網(wǎng)分布式系統(tǒng)架構(gòu)設(shè)計中必須考慮的因素之一,它通常是指,通過設(shè)計保證系統(tǒng)能夠同時并行處理很多請求,高并發(fā)相關(guān)常用的一些指標有響應(yīng)時間(Response Time),吞吐量(Throughput),每秒查詢率QPS(Query Per Second),并發(fā)用戶數(shù)等

前言

隨著互聯(lián)網(wǎng)與軟件的發(fā)展,除了程序員,架構(gòu)師也是越來越火的職業(yè)。他們伴隨著項目的整個生命過程,他們更像是傳統(tǒng)工業(yè)的設(shè)計師,將項目當做生命一般細心雕琢。

目前對于項目架構(gòu)而言,基本都會需要設(shè)計的幾個架構(gòu)。

1、業(yè)務(wù)架構(gòu)

項目或者產(chǎn)品的市場定位、需求范圍、作用場景都是需要在項目啟動初期進行系統(tǒng)性分析的。在設(shè)計業(yè)務(wù)架構(gòu)中,架構(gòu)師還需要明確角色。我看過很多關(guān)于架構(gòu)的文章,談到角色的很少。

什么是角色?

例如:商場作為一個整體系統(tǒng),角色就有消費者、店員、收費員、保安等等。各個角色完成好自己角色所需要承擔的任務(wù),整體系統(tǒng)就能完美的運行。

對應(yīng)到軟件系統(tǒng)中,根據(jù)產(chǎn)品的定位和需求,也會有著對照的角色,比如:用戶、數(shù)據(jù)審核者、產(chǎn)品制作者、運維人員等。在項目啟動初期,架構(gòu)師需要對項目中的每個角色做好職責定位,我相信在這點上,大部分開發(fā)同學(xué)在工作中,或多或少都有過職責不明確帶來的困擾。

2、技術(shù)架構(gòu)

在軟件項目研發(fā)過程中,我們會用到許多外部組件。在使用組件中,架構(gòu)師必須結(jié)合業(yè)務(wù)需求合理的選擇各個組件。項目是個生命,她會成長,架構(gòu)師需要明白如果一開始就選擇重量級組件會讓還是個孩童的項目不受重負,架構(gòu)師也需要明白如果技術(shù)架構(gòu)的設(shè)計不具備拓展性,那么這個孩子無法茁壯成長。所以技術(shù)架構(gòu)尤為重要。

3、物理架構(gòu)

物理架構(gòu)又叫做部署架構(gòu),項目產(chǎn)品如果要在生產(chǎn)環(huán)境穩(wěn)定運行,一個穩(wěn)定又高效的物理架構(gòu)是必不可少的。而且往往物理架構(gòu)和技術(shù)架構(gòu)是相輔相成的,性能監(jiān)控、異常告警、業(yè)務(wù)日志等等設(shè)計,都是為了讓項目做更好的自己。

高并發(fā)任務(wù)執(zhí)行架構(gòu)

在我十年的工作中,業(yè)務(wù)相關(guān)、中間件、大數(shù)據(jù)都有做過。本文主要分享一下高并發(fā)任務(wù)執(zhí)行框架設(shè)計,會由淺入深的講述一下設(shè)計演化過程。如果你不只是想做業(yè)務(wù)后端開發(fā),那么本文會給你一個全新的視野。

需求場景

我們列一下該項目的需求場景,看看工作中是否遇到過。

1、有個復(fù)雜的數(shù)據(jù)需要制作,而且制作的時間很長,無法讓請求方持續(xù)等待。所以請求方只能給你個回調(diào)地址,需要你完成這個制作后將產(chǎn)物通知他。

2、復(fù)雜的制作過程需要消耗資源,而且資源有限,無法無限量提供。如果你有接觸過AI,就會比較了解資源有限的感受。除了ASR、TTS這類識別類型的AI功能能做到近實時的反饋,大部分的算法在運行的時候都會消耗整張顯卡,而且耗時很長。

初看場景,很多后端可能會第一時間想到elastic-job(一個分布式任務(wù)調(diào)度框架)。即便你熟悉使用elastic-job,一開始就選擇重框架是不是有種殺雞用牛刀的感覺。不著急,我們一步步分析,一步步設(shè)計。

業(yè)務(wù)架構(gòu)設(shè)計

高度抽象一下我們的業(yè)務(wù),對產(chǎn)品設(shè)計者而言,貌似是個簡單的不能再簡單的東西。等到了技術(shù)架構(gòu),我們深入分析其中演化的功能點,就會發(fā)現(xiàn)這是個龐大的機器。我們先給他起個簡單的名字:Task Execution Engine(縮寫:TEE)

技術(shù)架構(gòu)設(shè)計

下面我們開始進行核心模塊的技術(shù)架構(gòu)設(shè)計,按照我們的初始需求開始我們的設(shè)計旅程。

初始設(shè)計

設(shè)計說明:

1、業(yè)務(wù)后端發(fā)出q1請求,我們首先需要對該請求的參數(shù)做矯正,為了可用性考慮。

2、參數(shù)校驗過后,給到執(zhí)行引擎模塊。執(zhí)行引擎主要的職責有從資源表獲取資源數(shù)據(jù)、將任務(wù)參數(shù)與資源參數(shù)封裝到任務(wù)對象內(nèi)、將任務(wù)提交線程池。有一點要說明執(zhí)行引擎最好使用隊列模式,任務(wù)先進隊列,可以通過while循環(huán)方式或者定時線程池都可以,后面會推薦更好的。

3、任務(wù)執(zhí)行的狀態(tài)與結(jié)果需要同步到數(shù)據(jù)庫中,建議使用mysql。

小結(jié):

按照初始需求,該設(shè)計相對比較簡單,完全夠用了。但是按照產(chǎn)品的迭代,業(yè)務(wù)方的需求不會僅限于此。繼續(xù)演化。

演化階段一

隨著業(yè)務(wù)的上線,業(yè)務(wù)端會馬上迎來新的問題。

1、由于提交的任務(wù)太多了,排在后面的任務(wù)遲遲無法等到自己獲取到資源執(zhí)行任務(wù)。當然我們可以完全靠增加資源來解決,但是資源的數(shù)量在產(chǎn)品前期是不可知的。所以需要有一些策略,比如讓用戶可以取消自己任務(wù),而不是一直等待。

2、任務(wù)的種類開始增加,業(yè)務(wù)端不滿足于單一制作,開始要求多樣化。

3、任務(wù)的執(zhí)行過程開始需要用到其他資源,不再是一個資源對一個任務(wù)的模式了。

4、任務(wù)的整體執(zhí)行情況不可知,需要一定的量化分析,至少讓業(yè)務(wù)組知道每天的任務(wù)成功率。

按照需求進行第二版的設(shè)計,在盡量不改變原來整體設(shè)計的情況下,補充功能。

設(shè)計說明:

1、為了解決排隊問題,增加了雙隊列算法來解決。用圖解的方式解釋一下雙隊列。

邏輯簡單說明一下,任務(wù)優(yōu)先提交至執(zhí)行隊列,引擎的定時讀取隊列的順序優(yōu)先為等待隊列。如果等待隊列中的任務(wù)可以獲取所需資源,則立即啟動線程執(zhí)行,否則原封不動回到等待隊列。引擎其次讀取執(zhí)行隊列,如果無法獲取資源則進入等待隊列,如獲取資源,則立即啟動線程執(zhí)行。

那么取消隊列,則只需要將隊列中的任務(wù)踢出隊列即可。在送回隊里的過程中,一定要保證隊列的有序性。

2、創(chuàng)建了任務(wù)池,增加了任務(wù)封裝層,在任務(wù)池中挑選需要執(zhí)行的任務(wù)類。

3、增加了策略機模塊,添加資源調(diào)度策略,由資源調(diào)度策略堆任務(wù)所需資源合理分配??梢杂蓸I(yè)務(wù)方提供分配方案,盡可能保證任務(wù)的公平性。

4、數(shù)據(jù)庫增加統(tǒng)計表,可以考慮使用定時任務(wù),將任務(wù)表的數(shù)據(jù)統(tǒng)計存入統(tǒng)計表。

小結(jié):

現(xiàn)在看上去已經(jīng)比較完善了,合理了任務(wù)調(diào)度、增加了任務(wù)種類、合理的資源調(diào)度,好像還不錯。但是產(chǎn)品總會有新要求的,那么繼續(xù)演化。

演化階段二

漸漸的,你設(shè)計的引擎還不錯。那么新的挑戰(zhàn)來了。

1、更多的業(yè)務(wù)方找到你,希望也使用你的項目進行任務(wù)制作,但是他們并不想共享資源,而是希望有自己的獨立資源,和獨立的隊列。但并不是所有的資源都需要獨立,一些可以支持高并發(fā)的資源,是可以共享的。簡而言之,更多的業(yè)務(wù)方,由業(yè)務(wù)方為維度的獨立隊列,獨立和共享的資源分配。

2、業(yè)務(wù)方找到你,說如果把任務(wù)1的結(jié)果給到任務(wù)2,其實就能拿到我要的結(jié)果。問題來了,原子任務(wù)要具備可以編排成復(fù)雜任務(wù)的能力。

3、任務(wù)的狀態(tài)過程無法監(jiān)控。OK,任務(wù)狀態(tài)機。

4、既然大家都需要對接你的項目,能不能提供標準的sdk,我只需要引入就可以完美的對接你的系統(tǒng)。

5、相同的任務(wù)參數(shù),是不是制作出來的結(jié)果一致呢?那么是否需要增加結(jié)果緩存,降低對資源的消耗呢?

6、完正的生產(chǎn)項目必然需要將日志、告警等關(guān)鍵信息傳遞出來,一旦發(fā)生問題可以馬上定位到問題的起因。

這些問題對于新人來說還是很有挑戰(zhàn)的,需要對系統(tǒng)深層的含義有充足的理解。沒事,我來好好來說下設(shè)計所需要掌握的知識點。

設(shè)計說明:

1、需要在資源表中區(qū)別資源類型,共享資源組所有業(yè)務(wù)組都可以使用,獨立資源則資源具備業(yè)務(wù)標識。在執(zhí)行引擎的隊列管理中,也需要區(qū)分業(yè)務(wù)組,避免共用排隊。這里給一個建議,共享的資源一定要是可以支持并發(fā)或者可以部署多個實例的,避免所有的業(yè)務(wù)組產(chǎn)品制作癱瘓。

2、增加了高級任務(wù)概念,高級任務(wù)可以將任意的原子任務(wù)進行組合編排,形成全新的任務(wù)。需要定義專屬于TEE的語法規(guī)則。對語法規(guī)則引擎的開發(fā),有一些建議。你可能會選擇規(guī)則引擎,建議其實可以自己開發(fā),畢竟語法不會太過復(fù)雜,沒必要引入三方的引擎。

3、增加任務(wù)狀態(tài)機,執(zhí)行引擎在提交線程的同時,也想任務(wù)狀態(tài)機提交任務(wù)線程信息。任務(wù)的進度狀態(tài)可以同步給任務(wù)狀態(tài)機中,同時一旦任務(wù)執(zhí)行過長的時間,除了任務(wù)自己的超時機制外,也可由狀態(tài)機的看門狗程序?qū)⒖ㄋ谰€程釋放、資源回收。

4、研發(fā)屬于TEE的SDK,作為內(nèi)部系統(tǒng)不建議SDK增加鑒權(quán)模塊。畢竟你對接的往往都是業(yè)務(wù)后端,鑒權(quán)不通過的話根本滲透不到TEE層面。給開發(fā)SDK一些建議,盡量引用較少的包,避免業(yè)務(wù)端引入帶來的包沖突。SDK也需要添加一些回調(diào)Consumer或者Function,盡可能讓業(yè)務(wù)端對接起來代碼簡單。

5、增加了緩存策略,可以設(shè)想一下,大部分情況下,相同的參數(shù)制作出來的結(jié)果也必然相同。使用redis,將任務(wù)參數(shù)與任務(wù)結(jié)果進行緩存,主鍵可以采用任務(wù)參數(shù)的MD5值。任務(wù)在提交給任務(wù)執(zhí)行引擎前,檢查緩存中是否已經(jīng)存在結(jié)果。緩存的過期時間按照具體情況而定。

6、增加日志系統(tǒng)和監(jiān)控系統(tǒng)的對接,狀態(tài)機與任務(wù)執(zhí)行中的信息接入到日志系統(tǒng)中。對于日志系統(tǒng)的建議是,最好采用成熟的ELK架構(gòu)??梢钥紤]兩種方式

a、將日志異步推送到消息隊列(例如:kafka),使用flink將kafka存入es。

b、使用logstash將日志內(nèi)容清洗處理,推送到es。

兩種方式都可以,但是一定要異步推送日志,避免任務(wù)阻塞。

告警系統(tǒng)的接入可以使用Prometheus,將TEE的指標信息開放出來,特別是告警信息。在Prometheus的告警監(jiān)控規(guī)則中,可以將告警信息按照某些策略發(fā)送郵件或者短信,通知運維人員。

小結(jié):

做到這里,我們再看看我們的技術(shù)架構(gòu)圖,是不是感到很滿足。但是這真的夠了嗎?

演化階段三

隨著業(yè)務(wù)愈發(fā)繁重,一個新的問題出現(xiàn)。

1、TEE在本機運行很順利,但是每個任務(wù)都是需要消耗線程的,單臺模式線程必然不是無限的,總有吃滿的時候。問題來了,TEE得支持分布式部署結(jié)構(gòu)。但是有資源管理的存在,你無法通過加實例的方式來實現(xiàn),因為資源調(diào)度必然混亂。

2、假設(shè)TEE掛掉,則等于業(yè)務(wù)組此刻提交的任務(wù)均失敗,容災(zāi)機制需要建立。

到了這一步,很多小伙伴可能覺著一陣頭大,分布式不是大數(shù)據(jù)的東西嗎?不是的,不是大數(shù)據(jù)就不能分布式部署嗎?就不能有主從節(jié)點嗎?就不能有注冊中心嗎?要跨過內(nèi)心的固有思想,我們往下看。

設(shè)計說明:

1、需要先將TEE項目做一下代碼分解,將管理調(diào)度模塊與任務(wù)執(zhí)行模塊拆解開了。消耗性能和線程較高的是任務(wù)執(zhí)行模塊,定義為TEE執(zhí)行節(jié)點。消耗性能和線程較低,卻需要參數(shù)校驗、任務(wù)封裝、資源調(diào)度、隊列管理的是管理調(diào)度模塊,定義為TEE管理節(jié)點。

2、TEE執(zhí)行節(jié)點可以多實例,形成節(jié)點池。管理節(jié)點可以考慮做成共享任務(wù)隊列的管理池。這里有個難點,如何共享任務(wù)隊列。建議使用zookeeper或者緩存方式,但是不管哪種方式都要注意使用集群,避免單點故障導(dǎo)致隊列數(shù)據(jù)丟失。

3、關(guān)于注冊中心,可以使用開源組件,nacos、zookeeper都可以。在該架構(gòu)設(shè)計中,其實注冊中心并沒有太多功能,如果你對自己有信心,可以嘗試自己寫一個注冊中心,核心功能就是服務(wù)注冊與心跳檢測??梢杂胣etty架構(gòu)做一做,提高一下自己的代碼能力。

4、在管理池的調(diào)用方面,增加網(wǎng)關(guān)代理,可以使用nginx、konga等。主要功能是業(yè)務(wù)端調(diào)用的時候,隨機打到管理節(jié)點上,就算一個管理節(jié)點掛了,也不會影響使用,保證了生產(chǎn)線的穩(wěn)定。

小結(jié):

分布式架構(gòu),主從節(jié)點模式也好、哨兵模式也好、選舉模式也好,按照自己的業(yè)務(wù)需求選擇最適合自己的。不是大數(shù)據(jù)才有分布式,它是一種設(shè)計思想,要知道開發(fā)大數(shù)據(jù)組件的大佬們,也是一行行java寫出來的。大佬們可以,為什么你不可以呢?

代碼設(shè)計

在著手開發(fā)該系統(tǒng)的時候,我給大家一些代碼開發(fā)的建議:

1、定時任務(wù)的實現(xiàn),從最簡單的while死循環(huán)加sleep,到定時線程池,或者springboot的@Scheduled注解,都可以實現(xiàn)。我在這里推薦一下時間輪算法TimeWheel,有興趣的可以去了解一下。

2、異步消息處理,如果你只是想在項目內(nèi)部使用消息總線,推薦使用guava包內(nèi)的EventBus。按照消息的數(shù)量級,考慮使用RabbitMQ或者Kafka作為消息中間件。

3、任務(wù)執(zhí)行,推薦使用CompletableFuture進行異步非阻塞任務(wù)編程。

4、在資源的使用中,可能存在多種協(xié)議類型http、ws、tcp等。所以代碼設(shè)計中,盡可能提供完整全面的協(xié)議工具類。

總結(jié)

最近和一個同事閑聊的時候,他和我說了說最近面試高級研發(fā)的情況??偨Y(jié)一下,現(xiàn)在想招一個做過高并發(fā)場景的太難了,大部分人選只做業(yè)務(wù)相關(guān)。這讓我想到了十年前,我剛工作的時候。那時候沒有那么多框架,大部分功能需要看很多資料研究底層的原理與算法。隨著軟件行業(yè)的日益成熟,從以前拿著谷歌翻譯看國外的組建說明,到從阿里云直接對接功能,軟件研發(fā)的成本和時間也在大大縮短。漸漸失去了研究分析的動力,框架什么都有為什么要抓破腦袋自己寫。

怎么成長?怎么進步?

上面給出的架構(gòu)圖,看上去都挺好理解。但真要自己去代碼實現(xiàn),中間各個環(huán)節(jié)出現(xiàn)的問題真的好解決嗎?冰凍三尺,非一日之寒。沒有日積月累的學(xué)習,是很難成功的。不要懼怕那些你看上去遙遠的東西,獲取你的幾個晚上的學(xué)習,它就成了你最趁手的武器。對學(xué)習而言,難的永遠不是過程,而是踏出第一步。

高并發(fā)任務(wù)執(zhí)行架構(gòu)中,有一個模塊看上去很不起眼,但是在你研發(fā)的過程就會發(fā)現(xiàn)他會給你制造大麻煩-資源調(diào)度。以后有時間我會單獨做一篇關(guān)于資源調(diào)度的架構(gòu)設(shè)計,與大家說道說道里面的坑。

最后說一句:為什么不ban猛犸?

到此這篇關(guān)于Java 高并發(fā)編程之最實用的任務(wù)執(zhí)行架構(gòu)設(shè)計建議收藏的文章就介紹到這了,更多相關(guān)Java 高并發(fā)編程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論