為什么需要 SaaS?
軟件即服務(SaaS)是一種靈活的軟件分發模型,可以由少到一個人或多至上千人的組織來運作。云服務的問世讓任何人都可以獨立運行自己的 SaaS,并在此基礎上建立免費增值模式的業務。
與其他類型的軟件服務相比,它的系統設計相對簡單。但是,由于沒有合適的基準架構,如果我們在設計 SaaS 時沒有認真思考,其結果可能會變得一團糟。我見過的一些例子中,SaaS 平臺最終成為一個龐大卻脆弱的單體 Web 應用程序,其中遍布冗雜的功能。
本文的目的是為你提供一種參考架構,為 SaaS 實現可伸縮性和可維護性。
SaaS 平臺的需求
產品需求
- 用戶和用戶組的訪問控制。
- 向用戶和組織提供訂閱層,其中每種訂閱類型都可以訪問一組產品。
- 托管內部管理工具的能力。
- 可擴展的功能。我們應該能輕松添加新的產品和功能集。
設計目標
- 隔離的服務帶來清晰的責任歸屬與關注點分離。
- 減小任何更改的影響半徑,比如說分析儀表板中的錯誤不應該影響管理儀表板。
- 隔離運行 Web 應用程序。每個 Web 應用程序都提供一組相關的功能來服務我們的客戶。在大型公司中,每個 Web 應用程序都可以有自己的專門團隊來構建和運行。
解決方案:隔離和重用
將服務隔離到邏輯組件中的設計可以讓我們的 SaaS 有更好的可擴展性。我們應該針對我們的架構作出改進,在規模擴展時打破常規:規模越大,架構卻變得越容易管理。就算只有一位孤獨的車間開發人員,他也可以很容易運行并管理多個服務,尤其是現在我們已經擁有了各種各樣可以編排微服務的云服務,這種事情做起來就更簡單了。
因為計劃在 SaaS 平臺上運行這些功能 Web 應用(feature Web App),所以我們應該先思考“我們可以重用什么?”這個問題。
隔離
隔離的 Web 應用程序是將相關功能分組在一起形成的一個 Web 應用程序,或是代表一款產品的一組 Web 應用程序。具體而言,我將其稱為“產品 Web 應用”,后文將做更進一步的介紹。
在 Web 應用程序中分組相關功能
例如,所有 " 分析報告功能 " 都可以組合在一起,成為一個獨立的 Web 應用程序,該應用將由一個專門的團隊來構建和維護,且這個團隊在構建分析報告產品方面具有相關的領域知識。在大型公司中,每個產品 Web 應用都有自己專門的團隊來構建和運行。
內部與公共(可選)
你的產品 Web 應用也可以分為兩個部分:內部和公共部分。內部和公共部分之間明確區分開來后,你就能在自己的專用網絡內路由一組專用的安全管理工具。
在內部和公共區域代理這些服務的工作由 " 路由服務 " 處理,具體將在后面的章節中介紹。
重用
這些是不同的功能 Web 應用及其相應服務共享的通用功能。每種功能 Web 應用都需要利用下面列出的這些功能。
組件
下面這些是構成我們 SaaS 的邏輯組件。
路由服務
每個請求都需要路由到正確頁面。當用戶訪問 yourWebsite.com/your-path 時,/your-path 需要將用戶轉發到其關聯的請求頁面或功能 Web 應用。路由服務可確保用戶得到他們所請求的內容。
在本文的例子中,我們將需要路由服務(routing service)調用另一個服務以獲取路徑和 Web 應用程序 URL 映射,以及所需權限。
這些映射預計將在運行時更新。例如,在需要引入新頁面或更改用戶權限而無需發布的情況下更新。
路由服務還負責內部或公共的產品 Web 應用。可以將其部署到兩個單獨的運行實例中。
公共和私有路由服務設置的高級設計
實現技巧:Node.js 的 http-proxy-middleware 或 Nginx 的 Reverseproxy 是兩個可行的選擇。如果你不需要在運行時從其他服務中以編程方式檢索路徑、URL 和權限,則后者是理想的選擇。有關更多信息,請參見后文的 "Web 應用倉庫 " 章節。
產品 Web 應用
每個產品 Web 應用都通過一個可在內部訪問的 URL 公開,例如 https://my-product-app-1.mydomain.local。其中一些由路由服務路由,以供訂閱的用戶訪問,而另一些仍在內部訪問。
通過路由服務路由的產品 Web 應用
在后臺,這可以是單個或一組帶有 Web 前端的微服務。這些 Web 應用彼此獨立,有自己獨立的代碼庫、支持服務、部署管道,并且理想情況下是由不同的團隊所有。在 SaaS 平臺中,它們的分組方式與其所有團隊的結構保持一致。
這樣以來我們就能將大型 Web 項目分解為許多可管理的單元。可以將這種模式想象成是將大塊牛排切成許多小塊。一個產品 Web 應用包含一組不應與其他 Web 應用重疊的相關功能。
實現技巧:產品 Web 應用可以是任何 Web 應用程序,例如常見的 Express、Node.js 和 React 堆棧。將設計系統與可復用的微前端(例如 Mosaic 或 Open Components)搭配使用,可以讓你的產品擁有一致的外觀和體驗。
Web 應用存儲庫
這個服務負責保存多個團隊擁有的 Web 應用程序的記錄。路由服務調用 Web 應用存儲庫,以獲取與所請求路徑對應的 Web 應用 URL(匹配某個條目)。
路由服務檢索 Web 應用 URL 及其關聯的路徑
下面是一個 Web 應用存儲庫表示例,用來說明它的功能。
基于角色的訪問控制(RBAC)服務將提供權限信息,以幫助我們檢查登錄用戶是否有權訪問產品 Web 應用。
如果要維護的產品 Web 應用條目數量很少,這里就可以用一個簡單的路由和硬編碼哈希映射的代理。
實現技巧:這既可以是具有自己的 Web 管理 UI 的 RESTful 服務,也可以是簡單的基礎架構,比如說是位于路由服務中,或者來自對象存儲(如 AWSS3)的代碼配置文件。具體的實現方式將取決于所需的規模和可配置性。如果你要繼續考慮服務實現,則可以將 JAVA、Go 或 C#與 RDBMS 或 NoSQL 數據存儲搭配使用。
對于這個服務來說,驗證過程是非常重要的,如果路徑或 Web 應用 URL 的配置不正確,則可能會影響你服務的可用性。如果無法確定要支持的產品數量,請使用進化原型方法。你不必在開發周期的早期就構建這個服務,因為一開始只用一個簡單的配置文件就夠了。
身份驗證
應該有一個跨服務共享的專用身份驗證服務。這里 JSON Web 令牌就可以派上用場,因為我們能輕松地通過標頭跨多個服務傳遞令牌和其他有用的用戶信息。
可以從路由服務或產品 Web 應用中調用身份驗證服務。如果從產品 Web 應用調用身份驗證服務,就能讓產品 Web 應用所有者靈活地對他們想要保護的任何頁面實施身份驗證。這種靈活性讓服務所有者可以管理公共頁面,例如用戶注冊頁。這種方法還減少了在路由服務中執行的邏輯。
產品 Web 應用調用身份驗證。
或者也可以在路由服務中處理身份驗證過程。從安全角度來看,這使身份驗證處理更容易審核,因為我們無需查看每一個產品 Web 應用頁面。這也意味著,如果需要讓一個網頁開啟公開訪問權限,則應該采用某種形式的白名單。這是另一個可配置性折衷。
路由服務調用身份驗證。
實現技巧:AWSCognito、Auth0 或任意 JSON Web 令牌(JWT)身份驗證服務。
基于角色的訪問控制(RBAC)
驗證用戶身份后,我們需要能夠回答以下問題:
是否允許登錄用戶訪問此頁面或他們嘗試訪問的信息?
可能的答案有:
- 是的,用戶 Alice 屬于組織 A,該組織有權訪問內容 A。
- 否,用戶 Bob 屬于組織 B,該組織無權訪問內容 B。
是否允許登錄用戶執行此動作?
可能的答案有:
- 是的,用戶 Alice 具有管理員角色,該角色具有刪除已注冊用戶的權限。
- 否,用戶 Bob 只有成員角色,該角色對所有內容只有只讀權限。
RBAC 幫助我們回答上述問題,從而讓我們的 Web 應用可以允許或撤消用戶執行的特定動作。
產品 Web 應用從 RBAC 服務中檢索權限信息。
下圖顯示了對用戶進行身份驗證并使用 RBAC 檢查其權限時發生的事件流。
下面的偽代碼說明了如何在特定用例中使用 RBAC 服務。
檢查用戶是否具有查看頁面的權限。
if (userHasPermissionToViewPage(userId)) {
showPage();
}else {
showNoPermissionError();}
檢查用戶是否有權執行某個動作。
復制代碼
if (userHasPermissionToPerformaction(userId)) {
showButton();
} else {
doNothing();}
實現提示:與其他服務相比,這個服務的通信量預計會更高,具體取決于你的權限會有多少粒度。你可以考慮使用和 Web 應用存儲庫實現類似的選擇:Java、Go 或 C#,搭配 RDBMS 數據存儲和一個緩存系統。用戶權限管理需要一個 Web 管理 UI。
高階設計
下圖顯示了運行時中組件之間的交互方式。
這種解決方案的好處包括:明確所有權、重用通用功能以及關注點分離。
高階序列
下圖顯示了路由服務將用戶路由到請求頁面的序列。從 Web 應用存儲庫中檢索到產品 Web 應用詳細信息之后,便會發生這些序列。
選項 1
在產品 Web 應用中調用身份驗證。
在產品 Web 應用中調用身份驗證。
選項 2
在路由服務中調用身份驗證。
在路由服務中調用身份驗證
使用 Web 應用存儲庫、RBAC 和身份驗證頁面作為一個 Web 應用
Web 應用存儲庫、RBAC 和身份驗證服務需要它們自己的 Web UI 來管理數據或接收用戶輸入。Web 應用存儲庫、RBAC 和身份驗證服務均有它們自己的 Web 應用。使用另一個具有管理 UI 的 Web 應用可以管理對某個 Web 應用的訪問權限。
某些 Web 應用用作其他組件的 UI。
Web 應用存儲庫 UI 允許我們使用所需的權限來管理路徑和 Web 應用 URL。
RBAC UI 用于管理用戶、組織、角色和權限。
身份驗證服務的前端 UI(即登錄頁面)也被部署為 Web 應用。
技術說明
- 服務通過 HTTPS 調用進行通信。
- 服務是內部的,但某些 Web 應用由路由服務公開提供。
- 這里沒有詳細介紹冗余的信息。你可以簡單地在構成 SaaS 平臺的服務之前添加一個負載均衡器,并在多個區域中運行它們。
長期改進
下面總結了一些應該牢記的準則,可以幫助你成功運營 SaaS 平臺。
1. 將技術文檔視為產品一部分
關鍵在于要讓團隊能通過良好的文檔管理產品 Web 應用,同時充分利用可用的工具。好的文檔可以最大程度地減少你的團隊重復詢問 SaaS 平臺相關問題的需求。
2. 給工程師同事提供便利
你可以在用于 RBAC 和 Web 應用存儲庫的 Web UI 管理工具之上,再開發一個 NodeJS/React 模板,其中包括開箱即用的 RBAC 和身份驗證的客戶端,以盡量減少將 Web 應用添加到 SaaS 平臺所需的工作。
這樣你的工程師或你自己就可以方便地從這個模板創建新的 Web 應用,而無需花費很多精力將其集成到平臺中。
3. 工程設計審查
糟糕的代碼可能會浪費數天甚至數周的開發時間,但相比之下,糟糕的架構決策可能會浪費數月至數年的時間。對于大型公司而言,工程設計審查可能更容易推進;但如果你自己是一名開發人員,那么也可以從社區中認識的其他工程師那里獲得反饋。
花費合理的時間預先編寫工程設計文檔,并在工程設計審查期間獲得反饋,可以為你節省很多時間。應該驗證軟件設計假設,并讓其他工程師為你設計的軟件架構找出盡可能多的漏洞。