<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          AeronCluster學(xué)習(xí)筆記-高效業(yè)務(wù)邏輯

          共 4390字,需瀏覽 9分鐘

           ·

          2022-11-18 19:45

          本文我們學(xué)習(xí)如何利用AeronCluster實現(xiàn)高效的業(yè)務(wù)邏輯。

          正確且有效地將業(yè)務(wù)邏輯添加到 Aeron Cluster 可能是一件具有挑戰(zhàn)性的事情,但是如果我們在使用AeronCluster的時候遵守以下規(guī)則時則會相對簡單地實現(xiàn)高效業(yè)務(wù)邏輯:

          • 考慮Cluster集群的有界上下文
          • 在選擇集群編解碼器的時候保持謹(jǐn)慎
          • 使用最合適的數(shù)據(jù)結(jié)構(gòu)和技術(shù)來實現(xiàn)業(yè)務(wù)邏輯(這不是廢話么)
          • 將驗證邏輯前置到網(wǎng)關(guān)
          • 將長期運行的任務(wù)外部化(比如說,一些耗時、耗費IO資源、耗費內(nèi)存資源的定時任務(wù),從核心業(yè)務(wù)系統(tǒng)分離出去)
          • 使用定時器來細(xì)粒度拆分無法外部化的長時間運行的任務(wù),讓任務(wù)不要長時間占據(jù)CPU,而是按照一定頻率觸發(fā)
          • 保持系統(tǒng)核心鏈路高性能,輕量級,減少遍歷等耗時邏輯,優(yōu)化算法,提升性能
          • 通過分片方式進(jìn)行資源隔離,提升并發(fā)度,降低鎖競爭

          其中許多規(guī)則與對抗利特爾定律有關(guān) - 請參閱性能限制  https://aeroncookbook.com/aeron-cluster/performance-limits/。

          !! 利特爾法則可用于一個穩(wěn)定的、非占先式的系統(tǒng)中。其內(nèi)容為:

          在一個穩(wěn)定的系統(tǒng)(L)中,長期的平均顧客人數(shù),等于長期的有效抵達(dá)率(λ),乘以顧客在這個系統(tǒng)中平均的等待時間(W);或者,我們可以用一個代數(shù)式來表達(dá):L=λW

          利特爾法則可用來確定在途存貨的數(shù)量。此法則認(rèn)為,系統(tǒng)中的平均存貨等于存貨單位離開系統(tǒng)的比率(亦即平均需求率)與存貨單位在系統(tǒng)中平均時間的乘積。

          雖然此公式看起來直覺性的合理,它依然是個非常杰出的推導(dǎo)結(jié)果,因為此一關(guān)系式“不受到貨流程分配、服務(wù)分配、服務(wù)順序,或任何其他因素影響”。

          此一理論適用于所有系統(tǒng),而且它甚至更適合用于系統(tǒng)中的系統(tǒng)。舉例來說,在一間銀行里,顧客等待的隊伍就是一個子系統(tǒng),而每一位柜員也可以被視為一個等待的子系統(tǒng),而利特爾法則可以>套用到任何一個子系統(tǒng),也可以套用到整個銀行的等待隊伍之母系統(tǒng)。

          唯一的條件就是,這個系統(tǒng)必須是長期穩(wěn)定的,而且不能有插隊搶先的情況發(fā)生,這樣才能排除換場狀況的可能性,例如開業(yè)或是關(guān)廠。

          我的個人理解是說,排隊場景下,一個很小的延時,在大量積累之后都會導(dǎo)致顯著的耗時,或許用長尾效應(yīng)解釋也比較合適。

          !! 還有一個額外的且牢不可破的規(guī)則:你編寫的任何業(yè)務(wù)邏輯都必須是確定性的。如果沒有確定性的業(yè)務(wù)邏輯,如果集群領(lǐng)導(dǎo)者失敗,你可能會面臨數(shù)據(jù)丟失的窘境(因為邏輯不是確定性的,即便從崩潰中恢復(fù)也無法恢復(fù)到崩潰前的狀態(tài))。

          考慮集群的有界上下文(Consider the cluster's bounded context)

          來自領(lǐng)域驅(qū)動設(shè)計的限界上下文模式是考慮Cluster的職責(zé)和邏輯的好方法。

          我們要努力將Cluster中的邏輯集中在核心系統(tǒng)狀態(tài)上——換句話說,在Cluster集群中處理無狀態(tài)邏輯幾乎沒有價值。(Cluster本質(zhì)上是基于Raft協(xié)議實現(xiàn)的有狀態(tài)機(jī))

          當(dāng)你發(fā)現(xiàn)需要多個有界上下文(例如,匹配功能和結(jié)算功能),請考慮將集群拆分為兩個獨立的集群。(上下文隔離,領(lǐng)域驅(qū)動設(shè)計中的做法)

          因為耦合多個上下文會引入了新的復(fù)雜性,不過這可以帶來更高的性能和更容易的開發(fā)和維護(hù)過程。

          對于兩個Cluster集群而言,你需要通過一個集群客戶端網(wǎng)關(guān)來訪問這兩個集群——這需要提前考慮協(xié)議版本控制和部署的復(fù)雜性。(很好理解,這其實是微服務(wù)的架構(gòu)模式,內(nèi)部多套系統(tǒng),對外只有一套入口也就是這里說到的網(wǎng)關(guān))。

          慎重選擇集群編解碼器(Select the cluster codec carefully)

          Aeron Cluster 使用類似洋蔥的架構(gòu)運行,通常有 4 層:

          1. FIX、JSON、Protobuf、Avro 或用于外部連接的任何數(shù)據(jù)格式
          2. 外部連接是通過網(wǎng)關(guān)進(jìn)程建立的,網(wǎng)關(guān)進(jìn)程本質(zhì)上屬于集群客戶端
          3. 集群客戶端使用集群的內(nèi)部編解碼器與集群進(jìn)行通訊
          4. 而在這個架構(gòu)中心,則是Cluster集群本身

          !! 注意: 除非通過集群客戶端,否則 Aeron 集群業(yè)務(wù)邏輯不應(yīng)直接與任何 I/O 交互。與往常一樣,這條規(guī)則也有例外(例如日志記錄、指標(biāo)、可觀察性等場景,就不得不避免IO交互),但條規(guī)則本身是一個指導(dǎo)設(shè)計的良好基準(zhǔn)。

          內(nèi)部集群編解碼器的設(shè)計和實現(xiàn)方式,應(yīng)當(dāng)保證在業(yè)務(wù)邏輯中花費最少的處理時間。

          使用簡單二進(jìn)制編碼(SBE, Simple Binary Encoding)或類似方法可以讓耗時保持在一位數(shù)或兩位數(shù)納秒。

          如果你在這里使用 JSON 之類的文本數(shù)據(jù)結(jié)構(gòu),即便你用的是最高效的庫也仍然需要花費數(shù)百微秒來解析消息。

          讓我們大膽想象一下,加入我們解析一條用 JSON 格式發(fā)送的集群命令需要 600μs,那么集群吞吐量將限制在 ±1,667 個請求/秒。

          如果我們使用SBE,平均在這個任務(wù)上花費 50ns,集群吞吐量將被限制在 2,000,000 個請求/秒。性能相關(guān)數(shù)據(jù)請參考 https://aeroncookbook.com/aeron-cluster/performance-limits。

          使用最適合的數(shù)據(jù)結(jié)構(gòu)和技術(shù)實現(xiàn)業(yè)務(wù)邏輯

          從上文中仔細(xì)選擇集群編解碼器(cluster codecs)可以看出,處理命令所花費的時間對集群最大吞吐量有很大影響。

          如果你選擇了類似 Simple Binary Encoding 這樣的編解碼器,你需要仔細(xì)考慮業(yè)務(wù)邏輯在內(nèi)部是如何運作的。并且你需要考慮以下問題:

          1. 考慮到命令處理的數(shù)據(jù)量,哪些數(shù)據(jù)結(jié)構(gòu)最適合業(yè)務(wù)邏輯?例如,你是否使用 Maps、TreeMaps、Arrays 等?
          2. cluster集群中允許哪些數(shù)據(jù)類型?例如,頻繁使用字符串會導(dǎo)致大量 GC。你有必要使用它們嗎?
          3. 你想預(yù)先分配所有內(nèi)容并使用自己管理的 DirectBuffers 嗎(不出意外的話,這里是堆外內(nèi)存)?還是說你信任 Java 虛擬機(jī)的 GC?
          4. 你怎么記錄日志?你的日志庫對性能是否有明顯影響?日志記錄過程會導(dǎo)致明顯的 GC 暫停嗎?

          將驗證邏輯前置到系統(tǒng)邊緣(Push validation to the edges)

          通過將驗證前置到系統(tǒng)的邊緣——無論是在校驗命令本身是否有效以及集群的初始化數(shù)據(jù)是否合理等(參見數(shù)據(jù)庫與AeronCluster https://aeroncookbook.com/aeron-cluster/databases/)方面,你的集群業(yè)務(wù)域邏輯都可以更簡單,并且可能運行得更快。

          驗證邏輯必須首先進(jìn)行,因為回滾消息的處理過程可能非常復(fù)雜 - 例如,如果你已經(jīng)提交了交易請求(比如說提交了下單請求),但隨后業(yè)務(wù)邏輯意識到用戶資金額度不足,那么你現(xiàn)在必須找到 一種能夠正確取消交易的方法。

          如果在交易之前先進(jìn)行驗證,那么就可以提前消除處理復(fù)雜回滾場景的需要(其實這里說的有點多余,眾所周知,業(yè)務(wù)系統(tǒng)中,尤其是交易系統(tǒng),20%是核心業(yè)務(wù)邏輯,80%都是校驗和失敗處理、異常處理邏輯,這其實體現(xiàn)了 做設(shè)計要面向失敗)。

          將長期運行的任務(wù)外部化(Externalise long running tasks)

          有時我們需要在集群Cluster內(nèi)對數(shù)據(jù)執(zhí)行復(fù)雜、耗費資源的計算過程。應(yīng)當(dāng)盡可能將這類型邏輯外部化,以達(dá)到保護(hù)集群,并且不影響吞吐量的目的。

          這方面的技術(shù)因計算的性質(zhì)而異,這里介紹一種常見的方法:提前準(zhǔn)備計算所需的所有數(shù)據(jù)、狀態(tài)的快照,并將其作為單個數(shù)據(jù)包發(fā)送到專用的業(yè)務(wù)網(wǎng)關(guān)。

          在準(zhǔn)備好快照后,確定版本,鎖定相關(guān)狀態(tài),以便業(yè)務(wù)邏輯可以知道結(jié)果是否可以被安全地接受并在網(wǎng)關(guān)返回時加以應(yīng)用(是不是賊像對賬系統(tǒng),實際上對賬就是這么做的,尤其是T+1對賬,都是基于確定的數(shù)據(jù),進(jìn)行聚合計算,并將結(jié)果輸出)。

          使用Cluster定時器來監(jiān)控外部任務(wù)的運行情況——例如,設(shè)置一個定時器在500ms后過期,如果還沒有收到結(jié)果,那么就重試。當(dāng)結(jié)果返回后,如果版本及鎖定狀態(tài)都符合要求,那么就取消任何相關(guān)的計時器并將更改應(yīng)用于集群狀態(tài)(實際上這種方式還是比較危險并且謹(jǐn)慎使用,一般在核心業(yè)務(wù)系統(tǒng)中,對狀態(tài)進(jìn)行計算要么就異步化,要么就在本系統(tǒng)中同步進(jìn)行,待結(jié)果返回之后再繼續(xù)后續(xù)的流程)。

          使用定時器或消息分解長時間運行的任務(wù)

          如果任務(wù)必須在集群內(nèi)執(zhí)行,并且不能安全地發(fā)送到外部。那么在這種情況下,不要將命令作為單個長時間運行的任務(wù)來處理,而是將其進(jìn)行分解。

          在執(zhí)行長時間運行的任務(wù)時,集群將無法處理新的命令并且延遲可能會飆升。

          在集群中存儲有關(guān)長進(jìn)程所需的狀態(tài),并通過集群計時器以chunk(塊)的形式調(diào)度任務(wù)。這將允許繼續(xù)處理其他命令,并且可以降低對延遲的影響。最好在上一個處理的子任務(wù)完成后就安排下一個子任務(wù),這個過程可以通過計時器或通過向集群發(fā)送消息來完成。

          我個人理解,這里要表達(dá)的是,對長任務(wù)進(jìn)行分治,拆分,進(jìn)而降低長任務(wù)對CPU、內(nèi)存資源的長期占用。

          保持核心鏈路清潔(Keep the hot path clean)

          當(dāng)我們在 Aeron Cluster 中加入新的業(yè)務(wù)邏輯/邏輯變更時,請保持核心路徑?jīng)]有任何同步的任務(wù)。

          例如,如果你需要進(jìn)行下單交易并希望將其存儲在數(shù)據(jù)庫中,請不要hold集群同步進(jìn)行數(shù)據(jù)庫寫入(禁止在cluster核心鏈路中進(jìn)行IO操作,這將使Cluster掛起無法接受新的請求(可以類比一下Netty的線程模型,我們是不允許在Netty eventLoop中執(zhí)行耗時操作的,這其實是一個道理))。

          正確且推薦的做法是將持久化操作發(fā)送到可以寫入數(shù)據(jù)庫的網(wǎng)關(guān)。信任集群會保留訂單狀態(tài) - 這需要保持確定性的業(yè)務(wù)邏輯這一牢不可破的規(guī)則。(在實際中,我們會將下單Log經(jīng)過Cluster的Raft共識之后,通過Archive進(jìn)行異步回放,從而落庫。)

          分片處理(Shard Processing)

          https://aeroncookbook.com/aeron-cluster/on-sharding/

          如果volumes(卷)和latency(延遲)需要的話,則可以對業(yè)務(wù)處理邏輯進(jìn)行分片處理。

          這樣做需要仔細(xì)考慮你在什么維度上進(jìn)行分片——例如在金融交易中,你是在合約(交易標(biāo)的,如某只股票)、人(如userId)還是通過其他維度進(jìn)行分片?

          這個決定特定于每個實現(xiàn),是一種按需采用的策略。我們需要考慮網(wǎng)關(guān)的設(shè)計以及分片對外部用戶和系統(tǒng)的影響——例如,集群是否完全獨立,或者網(wǎng)關(guān)是否需要跨集群進(jìn)行通信?(這里其實是說,分片固然能夠提升效率,降低延遲,但是如果涉及到數(shù)據(jù)的聚合,跨集群數(shù)據(jù)同步,分布式事務(wù)等場景,是需要好好進(jìn)行設(shè)計和思考。其實就是說,軟件開發(fā)領(lǐng)域沒有銀彈)

          本文原文  https://aeroncookbook.com/aeron-cluster/efficient-business-logic/


          瀏覽 138
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  丁香五月天婷婷激情网 | 放荡少妇三p黄色毛片 | 欧美乱伦一区二区三区 | 操逼在线观看视频 | 先锋影音精品三级 |