Newbe.Claptrap - 一套以 「事件溯源」 和「Actor 模式」做爲基本理論的服務端開發框架

本文是關於 Newbe.Claptrap 項目主體內容的介紹,讀者能夠經過這篇文章,大致瞭解項目內容。html

輪子源於需求

隨着互聯網應用的蓬勃發展,相關的技術理論和實現手段也在被不斷創造出來。諸如 「雲原生架構」、「微服務架構」、「DevOps」 等一系列關鍵詞愈來愈多的出如今工程師的視野之中。總結來看,這些新理論和新技術的出現,都是爲了解決互聯網應用中出現的一些技術痛點:git

更高的容量擴展性要求。在商業成功的基礎前提下,互聯網應用的用戶數量、系統壓力和硬件設備數量等方面都會隨着時間的推移出現明顯的增加。這就對應用本省的容量可擴展性提出了要求。這種容量可擴展性一般被描述爲 「應用須要支持水平擴展」。github

更高的系統穩定性要求。應用程序可以不間斷運行,確保商業活動的持續進展,這是任何與這個應用系統相關的人員都但願見到的。可是要作到這點,一般來講是十分困難的。而現今的互聯網應用在面對諸多同類競爭者的狀況下,若是在這方面作得不夠健全,那麼極可能會失去一部分用戶的青睞。數據庫

更高的功能擴展性要求。「擁抱變化」,當人們提到 「敏捷項目管理」 相關的內容時,都會涉及到的一個詞語。這個詞語充分體現了當今的互聯網應用若要成功,在功能性上作到出彩作到成功是多麼的重要。也從一個側面體現了當前互聯網環境下產品需求的多變。而做爲系統工程師,在應用創建之初就應該考慮這點。編程

更高的開發易用度要求。這裏所屬的開發易用度是指,在應用系統自身在進行開發時的難易程度。要作到越易於開發,在應用自身的代碼結構,可測試性,可部署性上都須要做出相應的努力。多線程

更高的性能要求。這裏提到的性能要求,是特指在系統容量增長時的性能要求。避免系統的單點性能問題,讓應用系統具有可水平擴展的特性。一般來講,在性能出現問題時,若能夠經過增長物理設備來解決問題,一般來講是最爲簡單的辦法。而在不一樣的系統容量之下,系統性能的優化方案一般是不一樣的。所以結合應用場景進行技術方案的選型一直都是系統工程師所須要考慮的問題。架構

本項目,就是基於以上這些系統功能特性要求所總結出來的一套開發框架。這其中包含了相關的理論基石、開發類庫和技術規約。併發

世界上本也不存在 「銀彈」。一套框架解決不了全部問題。 ——不肯意透露姓名的月落框架

從需求出發

在講解分佈式系統時,經常會用到 「帳號轉帳」 這個簡單的業務場景來配合描述。這裏闡述一下這個業務場景。異步

假設咱們須要建設一個具有帳號體系的業務系統。每一個帳號都有餘額。如今須要執行一次轉帳操做,將帳號 A 的餘額中的 300 劃轉給帳號 B。另外,基於上節的基本要求,咱們在實現這個場景時,須要考慮如下這些內容:

  • 須要應對系統容量的激增。應用初期可能只有 1000 個初始用戶。因爲應用推廣效果良好以及機器人帳號的涌入,用戶數量實現了在一個月內實現了三個數量級的攀升,也就是增加到了百萬級別。
  • 須要考慮系統的穩定性和可恢復性。儘量減小系統總體的平均故障時間,即便出現系統故障也應該是儘量易於恢復的。也就是,要避免出現單點故障。
  • 須要考慮業務的可擴展性。後續可能須要增長一些業務邏輯:按照帳戶等級限制日轉帳額、轉帳成功後進行短信通知、轉帳支持必定額度的免密轉帳、特定的帳號實現 「T+1」 到帳。
  • 須要考慮代碼的可測試性。系統的業務代碼和系統代碼可以良好的分離,可以經過單元測試的手段初步驗證業務代碼和系統代碼的正確性和性能。

輪子的理論

本節將介紹一些和本框架緊密結合的理論內容,便於讀者在後續的過程當中理解本框架的工做過程。

Actor 模式

Actor 模式是一種併發編程模型。經過這種編程模型的應用能夠很好的解決一些系統的併發問題。這裏所提到的併發問題是指計算機對同一數據進行邏輯處理時,可能因爲存在多個同時發起的請求可能致使數據出現不正確的問題。這個問題在進行多線程編程時必定會遇到的問題。舉個簡單的例子,假如在不加同步鎖的狀況下,使用 100 個線程併發對內存中的一個int變量執行++操做。那麼最終這個變量的結果每每小於 100。此處 Actor 模式是如何避免此問題的。

首先,爲了便於理解,讀者在此處能夠將 Actor 認爲是一個對象。在面向對象的語言(Java、C# 等)當中,能夠認爲 Actor 就是經過new關鍵詞建立出來的對象。不過這個對象有一些特別的特性:

擁有屬於自身的狀態。對象均可以擁有自身的屬性,這是面嚮對象語言基本都具有的功能。在 Actor 模式中,這些屬性都被統稱爲Actor的狀態(State)。Actor 的狀態由 Actor 自身進行維護。

這就強調了兩點:

第1、Actor 的狀態只能由自身進行改變,若要從外部改變 Actor 的狀態,只能經過調用 Actor 才能改變。

更新Actor狀態

第2、Actor 的狀態只在 Actor 內部進行維護,不與當前 Actor 以外的任何對象共享。這裏說的不共享也是強調其不能經過外部某個屬性的改變而致使 Actor 內部狀態的變化。這點主要是爲了區別於一些具有 「對象引用」 語言特性的編程語言而言的。例如:在 C# 的classpublic屬性,假如是引用類型,那麼在外部得到這個class以後是能夠改變class中的屬性的。可是這在 Actor 模式當中是不被容許的。

共享Actor狀態

不過從 Actor 內部讀取數據到外部,這仍然是容許的。

讀取Actor狀態

單線程。Actor 一般同一時間只能接受一個調用。這裏所述的線程不徹底是指計算機中的線程,是爲了凸顯 「Actor 同一時間只能處理一個請求的特性」 而使用的詞語。假如當前 Actor 正在接受一個調用,那麼剩餘的調用都會阻塞,直到調用結束,下一個請求才容許被進入。這其實相似於一個同步鎖的機制。經過這種機制就避免了對 Actor 內部狀態進行修改時,存在併發問題的可能。具體一點說明:若是使用 100 個線程對一個 Actor 進行併發調用,讓 Actor 對狀態中的一個int變量進行++操做。最終這個狀態的數值必定是 100。

併發調用Actor

不過單線程也不是絕對的,在不存在併發問題的請求狀況下,容許併發處理。例如讀取 Actor 中的狀態,這一般不會有併發問題,那麼此時就容許進行併發操做。

併發讀取Actor

讀到 Actor 單線程特性時,一般讀者會考慮到這是否會致使 Actor 自己處理過慢而產生性能問題呢?關於這點,但願讀者繼續持有這個問題日後閱讀,尋找答案。

事件溯源模式

事件溯源模式是一種軟件設計思路。這種設計思路一般與傳統的採用增刪查改(CRUD)爲主的系統設計思路相區別。CRUD 應用一般存在一些侷限性:

  1. 一般來講 CRUD 應用會採用直接操做數據存儲的作法。這樣的實現方式可能會因爲對數據庫優化不足而致使性能瓶頸,而且這種作法會較難實現應用伸縮。
  2. 在特定的領域一般存在一些數據須要注意對併發問題進行處理,以防止數據更新的錯誤。這一般須要引入 「鎖」、「事務」 等相關的技術來避免此類問題。但這樣又有可能引起性能上的損失。
  3. 除非增長額外的審計手段,不然一般來講數據的變動歷史是不可追蹤的。由於數據存儲中一般保存的是數據最終的狀態。

與 CRUD 作法對比,事件溯源則從設計上避免了上述描述的侷限性。接下來圍繞上文中提到的 「轉帳」 業務場景簡述事件溯源的基礎工做方式。

採用 CRUD 的方法實現 「轉帳」。

採用CRUD的方法實現「轉帳」

採用事件溯源的方式實現 「轉帳」。

採用事件溯源的方法實現「轉帳」

如上圖所示,經過事件溯源模式將轉帳業務涉及的餘額變更採用事件的方式進行存儲。一樣也實現了業務自己,而這樣卻帶來了一些好處:

  • 經過事件,能夠還原出帳號任何階段的餘額,這就必定程度實現了對帳號餘額的跟蹤。
  • 因爲兩個帳號的事件是獨立處理的。所以,兩個帳號的處理速度不會相互影響。例如,帳號 B 的轉入可能因爲須要額外的處理,稍有延遲,但帳號 A 仍然能夠的轉出。
  • 能夠經過訂閱事件來作一些業務的異步處理。例如:更新數據庫中的統計數據,發送短信通知等其餘的一些異步操做。

固然引入事件溯源模式以後也就引入了事件溯源相關的一些技術問題。例如:事件所消耗的存儲可能較爲巨大;不得不該用最終一致性;事件具有不可變性,重構時可能較爲困難等。相關的這些問題在一些文章中會有較爲細緻的說明。讀者能夠閱讀後續的延伸閱讀內容,進而進行了解與評估。

系統複雜度是不會由於系統設計變化而減小的,它只是從一個地方轉移到了另外的地方。——總說本身菜的月落

讓輪子轉起來

基於讀者已經大致理解了上節理論的基礎上,本節將結合上述描述的 「轉帳」 業務場景,介紹本框架的工做原理。首先讀者須要瞭解一下本框架的兩個名詞。

Claptrap

Claptrap

Claptrap 是本框架定義的一種特殊 Actor。除了上文中提到 Actor 兩種特性以外,Claptrap 還被定義爲具備如下特性:

狀態由事件進行控制。Actor 的狀態在 Actor 內部進行維護。Claptrap 一樣也是如此,不過改變 Claptrap 的狀態除了在 Actor 以外,還限定其只能經過事件進行改變。這就將事件溯源模式與 Actor 模式進行告終合。經過事件溯源模式保證了 Actor 狀態的正確性和可追溯性。這些改變 Claptrap 狀態的事件是由 Claptrap 自身產生的。事件產生的緣由能夠是外部的調用也能夠是 Claptrap 內部的類觸發器機制產生的。

Minion

Minion

Minion 是本框架定義的一種特殊 Actor。是在 Claptrap 基礎上作出的調整。其具有如下特性:

從對應的 Claptrap 讀取事件。與 Claptrap 相同,Minion 的狀態也由事件進行控制。不一樣的是,Minion 就像其字面意思同樣,老是從對應的 Claptrap 處獲取事件,從而改變自身的狀態。所以,其能夠異步的處理 Claptrap 產生事件以後的後續操做。

業務實現

接下來有了前面的基礎介紹,如今介紹一下本框架如何實現上文中的 「轉帳」 場景。首先能夠經過下圖來了解一下主要的流程:

Claptrap & Minion

如上圖所示,整個流程即是本框架實現業務場景的大致過程。另外,還有一些須要指出的是:

  • 圖中 Client 與 Claptrap 的調用等待只有第一階段的時候存在,也就是說,這使得 Client 能夠更快的獲得響應,沒必要等待整個流程結束。
  • Claptrap A 在處理完自身請求,並將事件發送給 Minion A 以後就能夠從新接受請求,這樣提升了 Claptrap A 的吞吐量。
  • Minion 不只僅只能處理 Claptrap 之間的調用代理。在 Minion 當中還能夠根據業務需求進行:發送短信,更新數據庫統計數據等其餘操做。
  • Minion 也能夠具有本身的狀態,將部分數據維持在自身的狀態中以便外部能夠從自身進行查詢,而不須要從對應的 Claptrap 中進行查詢。例如:統計該帳號最近 24 小時的轉帳變更,以便快速查詢。

業務容量

前文提到本框架須要建設的是一個能夠水平擴展的系統架構,只有如此才能應對業務容量的持續增加。在這點上,本框架現階段採用的是微軟開源的 OrleansService Fabric 搭配,實現應用程序和物理設備的放縮。固然,涉及數據存儲部分時勢必也涉及到數據庫集羣等一系列問題。這些屬於技術應用的細節,而非框架理論設計的內容。所以,此處只代表本框架能夠基於以上的開源架構進行容量放縮。應用過程當中的實際問題,讀者能夠在後續的項目內容中尋求解答。

輪廠現狀

當前項目正處於設立初期,主體的體系結構設計與編碼仍在進行中,讀者能夠經過項目地址瞭解項目的最新進展:

Github,主要項目源碼管理:https://github.com/newbe36524/Newbe.Claptrap

Gitee,碼雲倉庫地址:https://gitee.com/yks/Newbe.Claptrap

延伸閱讀

如下這些內容都對本框架產生了深遠的影響。讀者能夠經過閱讀如下這些內容,增長對本框架的理解。

  • 本文做者: Newbe36524
  • 版權聲明: 本博客全部文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!
相關文章
相關標籤/搜索