線上教育知識付費系統原始碼一鍵更新五網合一

zzkey發表於2022-05-15

  這篇文章描述了我前段時間在一家以前的公司工作時發生的一個真實情況。這裡的主要目標是解釋問題和解決方案。我想我可以分享它,以便它也可以幫助將來最終可能遇到同樣問題的人。

  事不宜遲,讓我們開始吧。我正在開發一種創新的知識付費系統原始碼,需要開發的用例之一是使用者有可能知道另一個給定實體正在使用或引用哪些實體(任何型別),這些實體有什麼樣的關係它們之間,以及其他功能。

  完整原始碼:zx.xcxyms.top

  我們的原始碼系統是使用具有越來越多服務的微服務架構構建的,所以這不是一件容易的事,因為我們遵循Database Per Service模式,一方面它很好,因為它允許我們解耦我們的服務並使用更適合每個資料庫的技術(SQL 與 NoSQL),但另一方面,它產生了連線資訊的問題,這些資訊持久存在於分離的資料庫中。簡而言之,我們需要建立一種可擴充套件的、通用的和抽象的資訊查詢方式,而不管實體型別如何。

  問題

  我們的領域模型由幾個知識付費業務概念組成,但為了簡化,讓我們使用“Person”和“Movie”等簡單概念對問題進行類比。

  讓我們假設一部電影是由它的標題和發行日期組成的,而一個人是由它的名字和出生日期組成的。關於關係,知識節點可以由一個或多個人執導,一個人可以在一個知識節點或多個知識節點中提現。

  圖 1. 架構模型

  假設我們為每個實體提供服務,people-api並且movies-api通過 API 閘道器公開。該people-api服務負責通過 REST API 為“Person”實體提供 CRUD 功能,並且該movies-api服務還負責通過 REST API 為“電影”實體提供 CRUD 功能。圖 2 中的下圖描述了當前架構。

  圖 2. 初始化架構

  一個可能的解決方案是通過 API 閘道器和聚合響應進行同步的服務間通訊,但這會有點難以編碼,並且會增加我們服務的耦合,降低內聚性,並且每個服務都必須知道其他 API 合約,損害了擁有微服務架構的全部意義。在這種特殊情況下,它會起作用,是的,但是如果我們要處理數百甚至數千個微服務呢?如果我們有數百個業務概念,它們之間有數百萬種不同的關係,並且必須實現每一個可能的查詢組合呢?你明白了。

  記住前面的問題,我們可以讓事情變得更復雜一些。

  假設我們在域模型中新增了一個新的“目錄”實體。例如,目錄可以是電影的集合,它可以有名稱和類別。我們的新域模型最終將如圖 3 所示。

  圖 3. 更新的原始碼模型

  為了反映我們的領域模型,我們需要建立一個新的微服務來負責處理我們的新實體。這個新的微服務將被命名為catalogue-api.

  然後,我們的架構將變成如圖 4 所示的樣子。

  在這種情況下,使用者現在可能想知道哪些目錄引用了給定的人。但是,等一下!目錄不直接引用一個人。相反,它們參考了知識節點,並且是那些參考人的知識節點。我們現在如何才能實現我們的目標?

  解決方案

  經過幾次長時間的會議和討論,我們決定通過做一些概念證明來調查我們的問題的一些可能的解決方案,並最終提出了一個可擴充套件的解決方案,並且不會影響我們以前的解決方案。

  我們開始考慮我們的業務域模型,就好像它是一個圖,其中節點是實體,邊是它們的關係。按照這種想法,圖 5 中的下一張圖是我們的實體如何建模的示例。

  圖 5. 圖表示例

  保持這種思路,我們提出了使用Neo4j資料庫提供新服務的想法,該資料庫將保留我們所有的實體及其關係。然後,該服務將能夠通過利用密碼查詢語言以任何所需的關係長度遍歷知識圖,以更友好、更簡單的方式進行所有這些複雜的查詢。

  但是還有一個問題我們還沒有弄清楚如何解決:

  我們如何聚合所有資料庫中持久化的所有資料並將其持久化到一個單一的資料庫中,並且仍然保持持續的一致性?

  使用發件箱模式更改資料捕獲

  這個問題的解決方案是使用帶有發件箱模式的CDC(變更資料捕獲)技術實現非同步資料複製機制。我們通過向所有寫入事務新增一個新語句來實現這一點,該語句負責生成一個發件箱事件,該事件最終將被Kafka源聯結器捕獲並放入一個主題中,任何有興趣瞭解狀態的人正在使用該主題已經改變了,特別是我們的知識庫。

  根據我們的初始架構,如圖 2 所示,然後我們可以將 Kafka 和這個新服務新增到我們的系統中。該服務將被命名knowledge-base並有兩個應用程式:knowledge-base-consumer使用發件箱事件,以及knowledge-base-api提供 REST API 來查詢實體及其關係。

  構建示例專案

  下圖描述了最終的架構,這正是我在這個小示例專案中實現的以支援本文。KrakenD被用作 API 閘道器,所有服務都是使用Quarkus框架在Kotlin中編寫的。並且每個都有一個MongoDB資料庫,而有一個Neo4j資料庫。people-apimovies-apiknowledge-base

  圖 6. 最終架構

  每當movies-api或people-api想要對其資料庫執行寫入操作時,它們還會發出一個帶有相應更改的發件箱事件,然後將其放入正在由knowledge-base-consumer. 這種方法保證所有對源資料庫的寫入最終都會複製到目標資料庫(最終一致性)。

  如果 Kafka 當機,更改仍會保留在源資料庫的事務日誌中,因此沒有什麼害處,因為一旦 Kafka 恢復正常,聯結器將讀取事務日誌並使用丟失的最新事件填充主題。另一方面,如果消費者當機,事件仍然會到達 Kafka,因此一旦消費者恢復,它將消費這些事件,從而使整體解決方案具有彈性和容錯性。

  下面的圖 7 有一個小圖來解釋這種情況下的發件箱模式。

  使用 CDC(更改資料捕獲)的發件箱模式

  圖 7. 使用 CDC(變更資料捕獲)的發件箱模式

  測試專案

  在 和 上執行一些 CRUD 操作後people-api,movies-api我們可以看一下在knowledge-base-api的 Neo4j 資料庫中持久化的內容的示例,如圖 8 所示。

  節點和關係示例

  圖 8. 節點和關係示例


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70017807/viewspace-2894228/,如需轉載,請註明出處,否則將追究法律責任。

相關文章