<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>

          詳解 CQRS 架構(gòu)模式

          共 2776字,需瀏覽 6分鐘

           ·

          2021-04-27 20:33

          點擊上方“服務(wù)端思維”,選擇“設(shè)為星標

          回復(fù)”669“獲取獨家整理的精選資料集

          回復(fù)”加群“加入全國服務(wù)端高端社群「后端圈」


          作者 | Kislay Verma
          出品 | 王者

          從一開始,軟件系統(tǒng)就被用于各種用途,針對它們的需求也隨著時間的推移而增長。需求的變更可能與業(yè)務(wù)邏輯、伸縮性或系統(tǒng)的其他方面有關(guān)。


          為了滿足這些相互矛盾或重疊的需求,工程師必須在設(shè)計系統(tǒng)時做出各種各樣的權(quán)衡。問題在于,很多權(quán)衡在一開始并不是必需的,而當(dāng)需要做出權(quán)衡時,系統(tǒng)已經(jīng)演變成到無法做出權(quán)衡的地步。


          在我看來,最有害的設(shè)計鎖定通常發(fā)生在數(shù)據(jù)層。在設(shè)計典型的應(yīng)用程序數(shù)據(jù)模型時,通常會結(jié)合考慮領(lǐng)域知識與性能因素。領(lǐng)域知識規(guī)定了實體是什么以及它們在邏輯上如何相互關(guān)聯(lián),性能因素決定了它們是如何在物理層面實現(xiàn)的(例如:采用關(guān)系型數(shù)據(jù)庫還是 NoSQL 數(shù)據(jù)庫、主鍵、索引等)。這兩個方面的選型讓應(yīng)用程序能有效地為目標場景提供服務(wù)。



          數(shù)據(jù)及其不同的視圖


          在擁有大量數(shù)據(jù)和復(fù)雜實體模型的大型應(yīng)用程序中,一些實現(xiàn)細節(jié)隨著時間推移變成了“核心”部分。有時候,這些東西是工程師在很明確的情況下完成的,但更多的是以一種隱式甚至是無意的方式發(fā)生。于是,新需求可能與現(xiàn)有的實現(xiàn)不一致,以至于根本無法很好地容納它們。


          這類問題在不同的情況下需要不同的解決方案。在本文中,我將重點關(guān)注一種情況,即從應(yīng)用程序讀取數(shù)據(jù)的方式與向系統(tǒng)寫入數(shù)據(jù)的方式非常不同時所出現(xiàn)的問題。這里的不同點可以是指查詢模式、輸出格式或規(guī)模方面的不同。


          我在這篇文章里寫了自己所遇到的這種情況。我當(dāng)時正在開發(fā)的訂單管理系統(tǒng)使用了實體 ID (訂單 ID、商品 ID 等),但是隨著時間推移,出現(xiàn)了一些復(fù)雜的讀取需求,我們的數(shù)據(jù)模型無法支持這些需求。問題出在兩個方面:


          一方面,現(xiàn)有的實現(xiàn)很難有效地滿足新的查詢模式。另一方面,訂單數(shù)據(jù)的讀取方希望有一種截然不同的數(shù)據(jù)模型。例如,電子商務(wù)平臺上的賣家希望他們的大客戶數(shù)據(jù)切片能以特定的方式來呈現(xiàn),而面向客戶的應(yīng)用程序希望數(shù)據(jù)看起來與購物車中的樣子一樣。


          這種情況并不少見,特別是對于擁有核心實體的系統(tǒng)。它們封裝的數(shù)據(jù)被廣泛使用,因此需要提供多種不同的格式。


          那么,我們該如何彌合這一鴻溝?

          CQRS

          CQRS 是“命令查詢責(zé)任分離”(Command Query Responsibility Segregation)的縮寫。在基于 CQRS 的系統(tǒng)中,命令(寫操作)和查詢(讀操作)所使用的數(shù)據(jù)模型是有區(qū)別的。命令模型用于有效地執(zhí)行寫/更新操作,而查詢模型用于有效地支持各種讀模式。通過領(lǐng)域事件或其他各種機制將命令模型中的變更傳播到查詢模型中,讓兩個模型之間的數(shù)據(jù)保持同步。



          如果你覺得它們看起來就像是兩個不同的微服務(wù),那么我來說一說它們之間的一個細微區(qū)別。從物理實現(xiàn)層面來看,這兩個數(shù)據(jù)模型可以作為兩個獨立的微服務(wù),甚至可以用一個命令模型來支持多個查詢模型。但是,微服務(wù)架構(gòu)的一個關(guān)鍵構(gòu)造是兩個微服務(wù)通常代表兩個獨立的領(lǐng)域,而在 CQRS 中,無論運行時架構(gòu)是怎樣的,命令模型和查詢模型都屬于同一邏輯領(lǐng)域。如果查詢模型對命令模型一無所知,就無法發(fā)揮作用。這里的耦合是預(yù)期的,不同于微服務(wù)之間的解耦行為。


          CQRS 并沒有規(guī)定這兩個模型如何保持同步。同步可以通過同時更新兩個模型來同步實現(xiàn),也可以通過消息代理(如 Kafka)將命令從命令模型傳輸?shù)讲樵兡P蛠懋惒綄崿F(xiàn)。后一種比較常用,因為它讓系統(tǒng)更加可伸縮,盡管它需要在寫操作和讀操作的最終一致性方面做出權(quán)衡。



          這不就是緩存嗎?

          只用于讀取的數(shù)據(jù)模式看起來就像是一個緩存。事實上,查詢模型可以使用 Redis 這樣的緩存技術(shù)來實現(xiàn)。但是,CQRS 不只是為了分離數(shù)據(jù)的寫入和讀取,它的根本目的是為了實現(xiàn)數(shù)據(jù)的多重表示,每一種表示都能夠滿足某些用戶的需求。CQRS 可能會有多種查詢模式,每個模式可能使用不同的物理實現(xiàn)。有些可能使用數(shù)據(jù)庫,有些可能使用 Redis,等等。

          什么時候應(yīng)該使用 CQRS

          對于一部分場景,CQRS 是一種非常有用的架構(gòu)模式。


          第一個是我在前面已經(jīng)提到過的。如果同一個數(shù)據(jù)模型不能有效地滿足系統(tǒng)的讀和寫模式,那么通過應(yīng)用 CQRS 來解耦讀寫是很有意義的。解耦后的數(shù)據(jù)模型可以滿足特定的需求。CQRS 有效地將單個數(shù)據(jù)表示變成任意數(shù)量的(讀)表示,所有這些表示都與負責(zé)處理所有更新的核心表示保持一致。


          適用 CQRS 的第二個場景是將讀負載與寫負載分開。前面我講了緩存和 CQRS 的區(qū)別,緩存并不是應(yīng)用 CQRS 的目的。但是,通過分離命令模式和查詢模式,就有了對單個模式進行伸縮的可能性。查詢模型可以有自己的數(shù)據(jù)庫和緩存,可以使用最適合某些特定場景的技術(shù)來實現(xiàn)。但不管怎樣,命令模型的伸縮都不會受制于查詢模型。我在這里需要重申的是,它們不是獨立的系統(tǒng),盡管它們之間有深度的耦合,但這不是問題。

          什么時候不該使用 CQRS

          在系統(tǒng)中使用 CQRS 會帶來顯著的認知負擔(dān)和復(fù)雜性。開發(fā)人員必須面對至少兩個數(shù)據(jù)模型和多種技術(shù)選擇,所有這些都是不可忽略的負擔(dān)。


          第二個問題是如何保持命令模型和查詢模型的數(shù)據(jù)同步。如果選擇了異步方式,那么整個系統(tǒng)就要承擔(dān)最終一致性所帶來的后果。這可能非常麻煩,特別是當(dāng)用戶希望系統(tǒng)能夠立即反映出他們的操作時,即使是單個一致性要求也會危及整個系統(tǒng)的設(shè)計。


          如果我們選擇讓模型在任何時候都保持一致,就會有 CAP 和兩階段提交問題。如果兩個模型使用同一個支持 ACID 的數(shù)據(jù)庫,我們可以通過事務(wù)來保持它們的一致性,但 CQRS 的很多可伸縮性優(yōu)勢就發(fā)揮不出來了。如果要支持多個查詢模型,寫操作將會越來越慢,因為需要更新所有的查詢模型。


          因為這兩個問題的存在,在選擇是否使用 CQRS 時就要十分謹慎。如果使用得當(dāng),它可以極大提升應(yīng)用程序的伸縮性。但是,支持多個數(shù)據(jù)模型并不是件容易的事,所以應(yīng)該只在沒有其他方法可以滿足要求時才考慮這么做。


          — 本文結(jié)束 —


          ● 漫談設(shè)計模式在 Spring 框架中的良好實踐

          ● 顛覆微服務(wù)認知:深入思考微服務(wù)的七個主流觀點

          ● 人人都是 API 設(shè)計者

          ● 一文講透微服務(wù)下如何保證事務(wù)的一致性

          ● 要黑盒測試微服務(wù)內(nèi)部服務(wù)間調(diào)用,我該如何實現(xiàn)?



          關(guān)注我,回復(fù) 「加群」 加入各種主題討論群。



          對「服務(wù)端思維」有期待,請在文末點個在看

          喜歡這篇文章,歡迎轉(zhuǎn)發(fā)、分享朋友圈


          在看點這里
          瀏覽 29
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  中文字字幕在线中文 | 国产男女AV | 天天色天天日天天射 | 免费操比视频 | 免费看片18 |