PowerDotNet平臺化軟體架構設計與實現系列(14):平臺建設指南

2022-12-20 12:00:52

軟體開發中常見的幾種不同服務模型包括SaaS(軟體即服務)、LaaS(許可即服務)、PaaS(平臺即服務)、CaaS(容器即服務)、IaaS(基礎設施即服務)和FaaS(功能即服務)。

很多人認為IaaS和FaaS是趨勢,是未來軟體設計與開發人員的基本必備技能,PowerDotNet和PowerDotNetCore也特別注重這方面的設計開發和積累,目前已經做出了一些嘗試、實踐和探索。

PowerDotNet和PowerDotNetCore實現的公共服務按照主要功能模組進行劃分,可以分為基礎設施、框架工具以及業務(微)服務三大類,使用者端和前端也小有所成,工作量較為飽和。

根據個人經驗,框架類庫和各種流行中介軟體程式碼質量相對都比較高. 直接原因是需求明確,邏輯變動少,再加上有很多牛人出手或者設計優秀比較具有前瞻性,實現之後,通常都會穩定很多年不變。

PowerDotNet和PowerDotNetCore實現的公共服務雖然不完全等同於框架類庫和中介軟體,但也最大程度將穩定的改動極少的部分抽象提取出來沉澱固化,隔離變化點,面向介面程式設計應對變化。

物件導向程式設計的很多原則和規範同樣適用於PowerDotNet和PowerDotNetCore,經過積累、改進和優化,PowerDotNet經受了多次大規模實踐的檢驗,也逐漸形成了自己的一套平臺技術規約和接入規範。

本文結合自己的開發實踐經驗,給PowerDotNet和PowerDotNetCore應用開發、部署和運維等事項記個流水賬,畢竟積累歷史較為悠久且內容豐富,就算淡忘了也能做為參考檔案使用,咩哈哈。

一、根應用

在PowerDotNet和PowerDotNetCore中,DBKey是應用的起點和基石,是所有PowerDotNet和PowerDotNetCore應用中唯一需要設定資料庫連線串使用者名稱和密碼的地方。

一開始DBKeyApi服務在資料庫管理平臺進行管理,後續開發DataX應用的時候,經過重構和完善,所有關係型資料庫、NoSQL、NewSQL等連線和後設資料管理都被劃分到DataX資料同步平臺

1、DBKeyApi

DBKey服務所在的應用名稱叫Power.DataX.DBKeyApi,這是PowerDotNet必選應用,基於WebApi開發的服務介面,效能中規中矩,滿足絕大多數業務需求。

DBKeyApi需要對敏感字串進行加密解密處理,目前PowerDotNet和PowerDotNetCore預設直接使用Framework下的DESUtil類(也可設定使用AES),需要在本地組態檔中新增加密和解密元件設定。

PowerDotNet同時還開發了Power.DataX.ThriftDBKeyApi和Power.DataX.GrpcDBKeyApi兩個備選應用。

(1)、Power.DataX.ThriftDBKeyApi

這是備選應用,基於Thrift協定開發的服務介面,對比下來,效能最好。

(2)、Power.DataX.GrpcDBKeyApi

這也是備選應用,基於Grpc協定開發的服務介面,對比下來,效能最差。

如果追求極致的效能體驗,建議使用Thrift協定,根據我的效能測試對比,Thirft>WebApi>Grpc,預設推薦使用WebApi,畢竟DBKey服務屬於資料量極少的字典型應用,存取量並不大。

2、外部依賴

DBKeyApi是應用的基石介面,不依賴任何外部API服務,不接入設定中心紀錄檔平臺監控平臺,也不使用訊息佇列分散式快取,可以說是PowerDotNet和PowerDotNetCore中最簡單最穩定的應用。

3、安全呼叫

API服務開發好了總是需要被呼叫,對於內容敏感的DBKey服務,PowerDotNet做了最為嚴格的安全規約,呼叫方有IP和域名白名單限制,所有呼叫DBKey的應用必須新增應用安全存取審計紀錄檔。

在PowerDotNet的服務治理平臺中,所有應用對DBKey服務的呼叫都需要進行嚴格稽核和授權,APP、使用者端、前端等應用禁止直接通過內部或者外部閘道器呼叫DBKey服務。

4、心跳檢查

DBKey服務支援心跳檢查,服務啟動後會定時(預設5秒)非同步傳送心跳包到註冊中心,PowerDotNet和PowerDotNetCore服務治理框架對所有服務介面都支援心跳檢查。

因為DBKey是根應用,也就是需要被第一個部署和啟動的應用,而註冊中心是後續依賴DBKey的應用,那麼我們就會有疑問:註冊中心沒有啟動的情況下心跳檢查不是一種浪費嗎?

這個問題很好解決,一種是直接將PowerDotNet設定的心跳檢查設定為禁用,另一種是對心跳檢查結果進行特殊code處理,註冊中心不啟動的情況下,忽略心跳結果,延遲當前間隔的6倍時間再傳送心跳。

除了普通介面和頁面應用自動內建了心跳健康檢查,其他如關係型資料庫、NoSQL、Redis、MQ等都自動根據DBKey實現了簡易心跳檢查(判斷連線是否成功),排查問題有立竿見影的效果。

PowerDotNet和PowerDotNetCore從最初的設計開始算起,心跳就是最基礎最核心最穩定的功能之一,可以說很多系統可靠性和可用性的基礎就是心跳健康檢測。

二、根服務

有根應用,就有根服務。根應用和根服務就像核彈一樣,可以不用,但不能沒有^_^。

DBKeyApi應用下的所有介面都是全域性系統根服務,但是PowerDotNet和PowerDotNetCore的系統根服務遠遠不止DBKeyApi下的服務。

PowerDotNet全域性根服務介面名稱,不可被修改或清理(移除)。在服務治理平臺,根服務被修改時,系統會給出明顯的錯誤提示。

下面根據系統分組的不同列舉幾個PowerDotNet和PowerDotNetCore中典型的根服務。

1、資料庫管理

(1)、查詢DB資訊

(2)、查詢DBKey和DB型別資訊

(3)、清理DBKey本地快取

2、應用基礎

(1)、查詢系統資訊

(2)、查詢應用資訊(不含應用金鑰)

(3)、查詢應用金鑰

(4)、應用移入叢集

(5)、應用移出叢集

3、設定中心

(1)、查詢應用設定資訊

(2)、根據版本號增量查詢設定

(3)、回撥通知已獲取最新版本設定的應用和伺服器

(4)、查詢應用設定的DBKey資訊

4、監控預警

(1)、新增紀錄檔

(2)、新增監控

5、ETCD

(1)、查詢Etcd路由分組

(2)、重新整理ETCD鍵值對

6、服務治理

(1)、註冊應用伺服器

(2)、下線應用伺服器

(3)、註冊API服務

(4)、下線API服務

(5)、查詢API服務資訊

(6)、查詢可用的應用部署資訊

(7)、心跳檢查

(8)、查詢伺服器資訊

(9)、人工註冊API服務

(10)、查詢快取統計資訊

上面列舉的監控預警和ETCD介面都是可選的根服務,PowerDotNet內建了很多開關,如果你有更好的監控預警和一致性方案,完全可以自己按需二次開發。

三、監控預警

1、紀錄檔平臺

記錄紀錄檔API介面,不依賴於平臺基礎和服務治理根服務介面,也不依賴設定中心,僅依賴於DBKey服務。

DBKey服務不依賴於紀錄檔平臺,紀錄檔平臺則直接呼叫DBKey的服務。紀錄檔API介面需要保證極高的效能和穩定性,當然應對業務和流量變化的可控的開關必不可少。

紀錄檔平臺支援分片查詢,建議按照應用進行查詢,應用必選,支援全鏈路呼叫鏈跟蹤查詢。

紀錄檔平臺支援敏感資訊過濾功能,預設情況下,DEV和Test環境可設定為不過濾敏感資訊,便於發現並快速排查問題。

2、監控平臺

記錄監控API介面,不依賴於平臺基礎和服務治理根服務介面,也不依賴設定中心,僅依賴於DBKey服務和紀錄檔平臺。

和紀錄檔API介面非常類似,監控API介面也需要保證極高的效能和穩定性,當然應對業務和流量變化的可控的開關也是必不可少。

四、平臺基礎

1、應用基礎

應用基礎根服務直接呼叫DBKey服務,同時也依賴紀錄檔平臺和監控平臺,但不需要接入設定中心。

當然紀錄檔平臺和監控平臺是可選的,可按需要進行設定。因為應用基礎也是字典型應用,穩定後改動極少,為了保證穩定和效能,依賴的外部服務當然是越少越好。

注意,平臺應用基礎服務依賴快取,如使用Redis分散式快取,建議設定分散式快取優先 :

<add key="RedisCacheFirst" value="1"/>

2、設定中心

設定中心直接呼叫DBKey服務,同時也依賴紀錄檔平臺和監控平臺,當然紀錄檔平臺和監控平臺是可選的,可按需要進行設定。

設定中心定時非同步拉取資料,間隔時間預設為15秒,可以設定ConfigRefreshSeconds達到動態控制的目標,建議是15的整數倍。設定中心通過ETCD或者RDBMS和Redis達到設定「及時」更新的目的。

PowerDotNet建立的預設Power.Platform.RootApp是一個虛擬根應用,主要用於供其他新應用複製設定用,減少開發人員的設定工作量。

PowerDotNet開發的設定中心使用者端,對外暴露的類ConfigClientTool和KVConfigService,推薦ConfigClientTool類,但是如果需要取非當前應用的設定,可以使用KVConfigService類。

對於一些快取資料,建議應用拼接快取鍵的時候加上快取版本CacheVersion,這樣可以集中控制資料變更。

通過DBKey服務獲取的資料庫連線串通常不會修改,所以建議快取鍵不帶版本CacheVersion,且快取時間長一點,系統預設快取一天。

對於需要心跳檢查的應用,在設定中心設定心跳健康檢查相關引數時,建議將心跳間隔時間設定為快取時間的五分之一或十分之一,系統資料正常快取5分鐘,心跳間隔時間可以設定為1到2分鐘或30秒。

設定中心支援設定自動伺服器註冊引數,平臺部署的伺服器,如選擇docker容器,請降低docker銷燬頻率或者優先將docker設定固定ip地址,否則頻繁註冊伺服器容易導致服務不可達問題,畢竟心跳保活有時間間隔。

五、服務治理

1、對內閘道器

直接呼叫DBKey根服務和平臺基礎根服務,依賴紀錄檔平臺、監控平臺和設定中心,不需要向註冊中心註冊伺服器和介面資訊。紀錄檔平臺和監控平臺是可選的,可按需要進行設定。

因為對內閘道器和註冊中心的緊密關係,對內閘道器又被稱為註冊中心閘道器。

2、對外閘道器

和對內閘道器類似,對外閘道器直接呼叫DBKey根服務和平臺基礎根服務,依賴紀錄檔平臺、監控平臺和設定中心,不需要向註冊中心註冊伺服器和介面資訊。紀錄檔平臺和監控平臺是可選的,可按需要進行設定。

但是,對外閘道器對安全性要求極高,必須嚴格授權存取的服務介面,新增安全審計紀錄檔,而且通過對外閘道器呼叫的介面必須要進行簽名和token校驗,否則閘道器會直接報錯。

對內和對外閘道器主要業務邏輯差不多,對外閘道器多了些安全審計需求,通過設定中心的SecureGateway設定可以輕鬆切換對內或對外閘道器控制。

支付閘道器是一種特別典型的對外閘道器,大中型電商系統幾乎都會有完備的支付閘道器解決方案和實現,在行動網際網路時代,支付閘道器更加不可或缺。

3、閘道器呼叫

通常根據公司的業務需要,API服務閘道器可以拆分為線上(對外)閘道器和線下(對內)閘道器。

一個非常經典的範例,外部商戶系統和內部財務系統都需要呼叫支付服務,根據實際業務需要,可能外部商戶系統走公網通過線上閘道器呼叫支付介面,而內部財務系統則走內網通過線下閘道器呼叫支付介面。

線上閘道器可以根據業務規模,繼續進行拆分為PC閘道器、行動端閘道器、第三方應用閘道器等。如果業務資料量不大,終端呼叫也不復雜,可能一個線上閘道器就足夠應對業務需求。

如果業務邏輯複雜,呼叫量很大,終端型別很多,每種終端的業務邏輯差異也較大,線上閘道器可能就需要繼續拆分。

有些公司還需要為開放平臺或者合作商戶等開發專用的安全閘道器,閘道器選擇就更復雜更豐富了。

4、使用者端呼叫

除了通過閘道器進行API服務呼叫,也可以在設定中心設定使用者端形式的直接服務呼叫,支援主流的服務鑑權、負載均衡、黑白名單、限流、熔斷等功能。

上圖簡單展示了業務微服務通過使用者端方式呼叫基礎設施微服務,同理,業務微服務之間的呼叫或者基礎設施微服務之間互調也適用。

對於內網應用服務或者追求更高效能的應用服務,推薦使用使用者端形式的直接服務呼叫。

5、閘道器心跳

心跳檢查主要有推模式和拉模式兩種,PowerDotNet兩種心跳模式都支援,通過伺服器端BroadCast廣播進行健康檢查效能較差,註冊中心不採用此方案。

每一個接入註冊中心的應用API服務都會被自動賦予一個心跳檢查框架服務方法,這個心跳檢測根服務僅限內部呼叫。

應用伺服器會主動向註冊中心傳送心跳包,實現心跳健康檢查功能,對於呼叫使用者端或閘道器而言,從註冊中心查詢到的心跳正常的應用伺服器部署列表被認為是正常可用的。

如果部署的應用伺服器返回心跳停止,閘道器會嘗試呼叫API伺服器的心跳介面,超時時間預設為2秒,如果沒有返回正常心跳結果,就認為服務真的下線,移除快取中的部署資訊。

如果閘道器將檢測下線的部署伺服器移除後,發現所有的部署資訊都不存在了,重新讀取遠端部署伺服器資訊,做兜底嘗試,這個過程都是非同步完成,整體效能沒有太大影響。

如果閘道器呼叫API伺服器心跳成功,則閘道器會呼叫平臺基礎心跳介面,代替某個具體的API服務傳送一次心跳,這個邏輯主要是為了防止某些Web伺服器因為環境或心跳時間間隔不當導致的保活滯後。

6、註冊中心

註冊中心直接依賴對內閘道器、紀錄檔平臺和監控平臺,間接呼叫DBKey根服務和平臺應用基礎根服務。

註冊中心基礎服務,通過對內閘道器進行應用伺服器、API介面的註冊、查詢和下線,支援Power.Apix、WebApi、WebService、WCF、Thrift、gRPC和.Net Remoting等形式的RPC介面。

註冊中心專門開發了使用者端,支援自動註冊實體類,實體類的集合型別建議使用具體型別,而不是介面,比如推薦使用List而不是IList。

註冊中心強烈建議介面開發過程中不要再使用Hashtable、ArrayList、DataTable和DataSet等型別,也不要使用指代不明的字典和dynamic型別,API介面型別越具體越好。

註冊中心使用者端目前支援整合Power.Apix、WebApi、WebService、WCF、Thrift、gRPC和.Net Remoting等形式的介面並進行統一閘道器呼叫或直接遠端呼叫,減少使用者端各種服務呼叫設定。

注意:註冊中心基礎服務不需要通過註冊中心使用者端自動註冊伺服器和API介面資訊,因為這樣容易造成迴圈依賴,雖然註冊中心基礎服務也是介面。

在PowerDotNet和PowerDotNetCore中,開發API介面服務,可通過ApiCallClassAttribute和ApiCallMethodAttribute兩個特性,自動定位唯一服務方法。

但是介面中呼叫實際方法並不是通過ApiCallMethodAttribute來定位,而是根據註冊時反射的服務方法,註冊服務的時候有唯一別名和方法名,通常這兩個都是相同的。

註冊中心的服務治理支援白名單和黑名單功能,黑名單目前已經實現了IP、使用者、系統、APP黑名單功能,這些都需要後設資料支援,服務治理平臺可以設定出萬能黑名單功能。

7、自我保護

心跳健康檢查的優點很明顯,通用且實現簡單,但在SOA和微服務架構下,服務間通常都是跨程序呼叫,網路通訊往往會面臨著各種問題,比如微服務正常,但是網路分割區發生故障,導致心跳檢查失敗。

預設情況下,如果註冊中心在60秒內沒有接收到某個服務範例的心跳,會自動登出下線該服務範例。為什麼是60秒心跳失敗就自動下線呢?

因為PowerDotNet和PowerDotNetCore註冊中心的預設心跳間隔為15秒,心跳支援3次重試,加上網路延遲和重試等待時間,60秒是一個較為合適易記的數位。

在設定中心我們可以設定心跳健康檢查時間間隔(預設15秒),所以60秒只是預設情況,實際的時長應該是應用設定的心跳健康檢查間隔時間的4倍。

註冊中心除了通過應用心跳健康檢查實現服務可用性,也可以設定(設定分組SafeGuard)自我保護機制(參考了Eureka),防止因為網路分割區故障心跳健康檢查誤判導致的服務不可用問題。

因為網路問題導致固定時間內大量服務範例被登出下線,可能會嚴重威脅整個SOA或微服務架構的可用性,我們寧可將現有的服務節點都保留,也不能盲目登出下線任何健康的服務,這就是所謂的兜底思維。

PowerDotNet註冊中心開發的自我保護機制主要邏輯如下:

(1)註冊中心在執行期間會去統計15分鐘(可設定)內應用服務心跳失敗比例,如果心跳失敗比例低於80%(可設定),註冊中心即會進入自我保護機制(可在設定中心設定開關控制);

(2)進入自我保護機制後,通常認為現在註冊列表中的應用服務節點都是穩定可靠的,哪怕是長時間沒收到心跳而應該過期的服務節點,也不會再去主動登出移除並下線;

(3)註冊中心仍然能夠接受新服務的註冊和查詢請求,並通過ETCD嘗試同步資料,但不會強制要求這些新增的服務被全部同步(預設ETCD來同步)到其它節點上,保證當前節點依然可用;

(4)當網路穩定心跳健康檢查恢復以後,當前範例新的註冊資訊會被全部同步到其它節點中,也就是達到註冊服務的最終一致性,這時候註冊中心自動關閉自我保護機制。

特別注意,如果在自我保護開啟後在保護期內剛好有某個服務提供者非正常下線,服務消費者就會有一個無效的服務範例,此時呼叫這個範例的服務就會失敗,服務消費者要有一些容錯機制,比如重試等。

目前PowerDotNet和PowerDotNetCore服務消費使用者端支援簡單重試(預設3次,可設定)和自動切換可用服務範例嘗試,如果所有服務範例都呼叫不通,使用者端丟擲異常,自動非同步發出心跳檢查嘗試。

8、斷路器

在分散式系統中,重複故障可能會導致雪球效應並使整個系統癱瘓。為了限制操作的持續時間,我們可以使用超時機制,因為超時可以防止掛起操作並保持系統響應。

但是,在微服務中合適的超時設定是不可能精確到每個介面方法的,根據個人開發經驗,系統裡通常都是設定一個大概的全域性超時時間或框架預設超時時間。

系統處於高度動態的環境下,一段時間內,某些介面呼叫多,某些介面呼叫少,網路頻寬佔用也隨著介面呼叫而改變,超時時間不可能隨著環境和資源變化而動態改變。

有些公司會通過設定中心來自動適配超時時間,但是哪怕可以通過設定中心動態設定超時時間,開發和業務又不可能隨時隨地修改釋出合適的超時設定來適應環境變化。

為了解決靜態超時機制的不足,我們可以使用斷路器來處理錯誤,相對靈活動態應對環境變化。

斷路器(Circuit Breaker)以現實世界的電子元件命名,因為它們的作用是相同的。斷路器的主要工作原理是:

(1)、當特定型別的錯誤在短時間內多次發生時,斷路器會被開啟;

(2)、開路的斷路器可以防止進一步的請求,就像我們平時所說的電路跳閘一樣;

(3)、斷路器通常在一定時間後關閉,在這期間可以為底層服務提供足夠的空間來恢復。

一些斷路器也具有半開狀態。在這種狀態下,服務傳送第一個請求以檢查系統可用性,同時讓其他請求失敗。如第一個請求成功,它將使斷路器恢復到關閉狀態並使流量流動。否則,它保持開啟。

總的來說,斷路器的核心功能主要就是三大塊:

(1)、呼叫資料度量統計,比如介面異常或者超時次數等

(2)、維護斷路器自身的狀態,包括Closed(關閉)、Open(開啟)和Half Open(半開)三種狀態

(3)、基於前兩點保護包裹在斷路器中執行的呼叫

目前PowerDotNet和PowerDotNetCore實現的預設斷路器按照介面消費者介面呼叫異常和超時總次數,進行斷路器狀態的變更及快速失敗返回處理,個人認為這是最簡單的斷路器實現。

想給介面消費者應用新增呼叫介面斷路器功能,手動在設定中心點點,設定好三個引數釋出後就可以正常使用了,可任意控制斷路器開關啟停,極致的便利。

9、API風格

PowerDotNet和PowerDotNetCore的服務治理平臺早期支援RPC和REST兩種常見風格的API命名,隨著開發迭代積累,越來越發現REST相對RPC沒有任何優勢,多數情況下反而成為開發和管理的負擔。

信奉REST教條的老學究們在口頭理論上說的頭頭是道,開發者卻為想URL名、寫對接檔案以及返回code而苦不堪言,這些明明都是可以通過看RPC介面名和說明就能分分鐘搞定的事情。

PowerDotNet和PowerDotNetCore的服務治理平臺目前已經從REST邪路迴歸到RPC正途,尤其是所有基礎設施服務做了微服務改造後,極大地降低了開發者心智負擔,顯著減少了API對接工作量。

RPC風格的API命名也很有講究和規律,最直接最推崇的命名方式是【公司.產品線.系統.子系統.服務類名.服務方法】或者【公司.系統.子系統.服務類名.服務方法】,看公司規模大小,按需選擇介面命名方式。

六、基礎設施

基礎設施即服務。PowerDotNet和PowerDotNetCore現有的基礎設施服務已完成微服務改造,在穩定性可靠性高可用性最大程度得到保障的前提下,部署運維方便程度也有了極大提升。

將PowerDotNet和PowerDotNetCore依賴的所有基礎設施服務抽象並進行統一管理,能夠最大限度的複用,降低開發運營成本,提升開發效率。

下面列舉下PowerDotNet和PowerDotNetCore主要應用和服務的依賴關係和啟動順序。

1、啟動Power.DataX的Power.DataX.DBKeyApi服務

最穩定的介面服務,零依賴。

2、啟動Power.XLogger的Power.XLogger.WebApi服務

僅依賴Power.DataX的DBKey服務, 如紀錄檔服務使用佇列,還需啟動佇列消費者Power.XLogger.MQConsumer。

3、啟動Power.XMonitor的Power.XMonitor.WebApi服務

依賴Power.DataX的DBKey服務和Power.XLogger,如監控使用佇列 ,還需啟動佇列消費者Power.XMonitor.MQConsumer。

4、啟動Power.Platform的Power.Platform.WebApi服務

依賴Power.DataX的DBKey服務、Power.XLogger和Power.XMonitor,這個應用包含了應用基礎服務和設定中心相關服務。

5、啟動Power.RegistryCenter的閘道器Power.SGS.Gateway服務

依賴Power.DataX的DBKey服務、Power.XLogger、Power.XMonitor和Power.Platform

6、啟動Power.RegistryCenter的Power.SGS.RegistryWebApi服務

依賴Power.SGS.Gateway、Power.DataX的DBKey服務、Power.XLogger、Power.XMonitor和Power.Platform

7、啟動其他框架服務

PowerDotNet和PowerDotNetCore開發的其他常用框架服務,比如訊息佇列、快取、資料同步、定時任務等等,這些應用就無所謂順序了。

以上可以認為是PowerDotNet和PowerDotNetCore的平臺基礎設施,搭建好環境並啟動服務以後可以按需開發很多種形式的應用。

強烈建議將PowerDotNet和PowerDotNetCore的平臺基礎設施服務以非Web宿主的形式部署執行起來,這樣便於後續編寫啟動指令碼來控制啟動順序。

目前可以通過bat指令碼啟動這些基礎設施服務,對於多機器多容器多叢集部署,總體複雜度可控,不過隨著外部依賴和部署複雜度的增加,指令碼複雜度必然也會隨之增加。

PowerDotNet基礎設施服務看上去有點多,但如果你折騰過Dubbo、Nacos(Apollo)、Envoy、Redis等自建微服務環境或直接使用SpringCloud全家桶,PowerDotNet實在是太易用太人性化了。

從基礎設施服務可以看出,目前PowerDotNet和PowerDotNetCore還是屬於輕量級侵入式的名字服務範疇,不支援目前大廠比較流行的非侵入性的服務網格(Service Mesh)。

注:服務網格(Service Mesh)是一個對於業務開發而言「非侵入性」的基礎設施層,通常採用邊車(SideCar)模式,用於處理服務間通訊。典型代表包括Istio和Linkerd,還有後起之秀Dapr。

PowerDotNet和PowerDotNetCore核心功能已成熟穩定,且效能良好,能滿足絕大多數業務場景,對於服務網格,正如奧卡姆剃刀原理所說,如無必要,勿增實體,目前沒有進化到這個階段的迫切需求。

PowerDotNet和PowerDotNetCore基礎設施在通用性、可用性和易用性方面已經得到了充分驗證,遵循KISS原則,簡單即是美,反對恐龍設計,堅持自我,我就是我,是顏色不一樣的煙火,咩哈哈。

保證基礎設施的高可用是PowerDotNet開發的重中之重,目前主要技術選型都有完善的後臺管理和監控工具,也有兜底解決方案,比如新增備用節點排除單點,新增可啟停設定開關等,這些都是管理後臺點點按鈕的事情。

網路和IO是計算機上最典型的兩個瓶頸,尤其是網路,在互聯絡統中網路通常是最容易爆出問題的節點,同時也是各個大中小廠工程師們甩鍋的萬能藉口^_^。

PowerDotNet源於SOA架構,主要基礎設施原來是兩個單體服務,現在也按照微服務架構徹底拆分了,但是相比單體服務,拆分後出現事件的概率反而極低。

原因我猜可能是網路問題有了極大改善,因為千兆網路卡對中小公司可以算是標配,現在中大型公司自建IDC多數都是萬兆網路卡,土豪公司用RDMA網路卡也不稀奇。

PowerDotNet和PowerDotNetCore雖然內部基礎設施服務較多,呼叫關係複雜,呼叫鏈路冗長,但是在服務治理平臺治理下,已經在實踐中證明能夠保證服務的穩定可靠。

基礎設施服務除了要求穩定可靠之外,還要求像普通業務邏輯型API服務一樣支援無感橫向擴容,服務治理平臺支援所有API服務的無感橫向擴容,對於分散式場景下的穩定性保障非常有意義。

七、框架工具

這部分偏重於框架的工具服務能極大提升開發者工作效率,減少重複建設,比如定時任務排程平臺、資料同步平臺、快取平臺、訊息平臺、檔案平臺等等。

框架工具建議技術選型優先選擇成熟穩定使用者眾多資料齊全的,不迷信大廠或所謂大牛的新作品,當然私下自己學習參考這些新作品毫無問題,但一定要謹慎在生產環境推廣使用,否則出現問題自己體會吧。

當然這些框架工具服務是可選或者可延伸的,預設技術選型都是主流技術產品,預留出可延伸的介面定義,對於豐富PowerDotNet和PowerDotNetCore的技術選型大有裨益。

八、程式碼生成

PowerDotNet和PowerDotNetCore的自動程式碼生成工具主要包括基於DBKey和自研ORM一鍵前後端程式碼生成、服務代理自動生成、組態檔生成和自動心跳整合工具等。

有了這些輔助程式碼生成工具,對於日常開發工作而言,可以至少減少百分之八十的工作量,解放開發者的雙手,讓開發人員將更多時間和精力集中放在更有價值的事情上。

九、服務編排

我們開發的絕大多數業務邏輯型應用服務天生就會產生依賴關係(比如對保持高度穩定的基礎設施產生依賴),尤其是流行的SOA或者微服務架構,有時候呼叫鏈的複雜程度非常恐怖。

舉例來說,比如支付系統中的信用卡服務,在支付系統內部,信用卡服務依賴支付基礎、風控等服務,在公司內部可能還依賴個人使用者服務,在公司外部還依賴銀行、銀聯、清算中心等等。

為了編排服務的啟動順序,PowerDotNet參考了網上很多文章,比如Docker-compose、Docker Swarm、Helm、Kustomize、Apache Mesos和Google Kubernetes(K8S)等等解決方案。

經過權衡對比後,還是認為這些解決方案太重太複雜,單單一個重寫以支援容器部署就有不少的工作量,更不要說還需要人工寫很多易錯的啟動指令碼,和PowerDotNet的初衷背道而馳。

服務編排是PowerDotNet和PowerDotNetCore需要解決的一大技術難題,我個人所服務過的公司沒有一家有完美的解決方案,也許K8S是個不錯的選擇,或者土豪一把直接使用雲服務。

所謂傻人有傻福,笨人有笨方法,對於呼叫關係複雜的應用部署,PowerDotNet提供了簡易自檢程式,可以在啟動服務前,在自檢小程式中輸入服務名稱檢測服務是否可達。

同時服務治理平臺Power.RegistryCenter提供了快速呼叫服務助手,可以通過切換應用伺服器地址進行心跳健康檢查來達到檢測服務是否可用的目的,對於一般應用也堪堪夠用。

十、應用開發

亂花漸欲迷人眼,CRUD特別繁。現在的應用程式越來越呈現出依賴項多,業務流程冗長,呼叫鏈複雜等技術特點,由此也產生了很多依賴複雜的開發套件和工具,也出現了Serverless等新的架構模式。

和很多流行的全家桶式開發套件有異曲同工之妙,通過PowerDotNet和PowerDotNetCore的基礎設施、框架工具和自動程式碼生成工具,開發人員可以快速無障礙的流水線式開發業務邏輯型應用程式。

本文不直接比較流行的全家桶套件和PowerDotNet(PowerDotNetCore)的優缺點,看前面本系列的介紹你應該能感受到PowerDotNet和PowerDotNetCore的易用性。

下面簡單演示下在PowerDotNet和PowerDotNetCore環境中如何快速開發接入一個新應用,讓你直觀理解到開發業務邏輯型應用程式是多麼快速而幸福的事情。

1、建立應用

系統應用平臺負責建立系統和應用。

新增應用歸屬哪個產品線哪個系統,需要和業務部門負責人溝通好,應用開發和負責人都是必填的,後續監控預警傳送郵件等都需要這些人員資訊。

應用金鑰是必須的,對於內網應用,呼叫非敏感介面通常可以放行,但是如果服務治理中心勾選了驗證簽名,應用金鑰是最重要的驗籤引數,所以需要應用開發者妥善保管。

如果應用金鑰因為安全需要必須進行變更,需要業務部門負責人稽核才能修改,否則金鑰修改而應用端沒有及時更新造成大面積簽名失敗事件。

2、設定中心

系統應用平臺可直接初始化應用設定。

所有需要接入設定中心的新應用,都可以在系統應用平臺初始化應用設定,系統應用平臺提供快捷工具分組拷貝或者匯入設定,非常方便。

如果是前端、使用者端、APP等不需要接入設定中心的應用,可跳過自動初始化應用設定這一步,當然某些特殊情況下也支援使用者端通過閘道器自動獲取設定中心設定。

初始化的設定中,除了通用設定引數,心跳,服務治理,DBKey、RPC、快取、檔案、紀錄檔、監控等設定引數應有盡有,開發人員通常點點按鈕改幾個設定引數就好。

如果設定中心的設定直接複製於同系統下的相似應用,絕大多數情況下一個引數都不用改動,對於開發人員而言簡直摸魚偷懶神器。

特別提醒,紀錄檔資料庫的DBKey約定都以LogDB_開頭,比如:LogDB_Writer_MySQL,LogDB_Writer_PostgreSQL,LogDB_Writer_MongoDB,LogDB_Writer_ElasticSearch。

對於不需要應用自己直接寫紀錄檔資料庫記錄紀錄檔的情況,可以在設定中心設定紀錄檔服務地址,間接通過紀錄檔平臺記錄紀錄檔,這也是PowerDotNet推薦的做法。

3、應用範例

PowerDotNet有很多腳手架模板,包括WebForms、MVC、Winform、RF、Android、VUE、React、WebApi、WebService、Apix、WCF、.NET Remoting、Hessian、gRPC、Thrift等。

這些腳手架內建了接入PowerDotNet或PowerDotNetCore的預設設定,絕大多數應用只需要對預設設定稍作修改,開箱即用,大大降低了開發人員搭建環境的時間成本。

通過PowerDotNet和PowerDotNetCore,最多5分鐘就能建立一個自動整合閘道器、設定中心、註冊中心、快取、紀錄檔、監控等服務的新應用,想想用SpringCloud寫個HelloWorld搭建環境要折騰多久。

有了PowerDotNet和PowerDotNetCore基礎設施服務和框架工具的強有力的支撐,開發人員寫一個兩個應用,十個八個應用,幾十上百個應用甚至成千上萬個應用都不在話下。

(1)、後端應用

我們以一個典型的WebApi服務來舉例,新增一個應用,名稱叫Power.BaseData.WebApi,那麼這個應用的預設組態檔如下:

<?xml version="1.0" encoding="utf-8" ?>

<appSettings>
  <add key="SystemCode" value="BaseData" />
  <add key="AppName" value="Power.BaseData.WebApi" />
  <!--設定是否本地優先-->
  <add key="LocalFirst" value="0" />
  <!--閘道器相關設定 支援多個 以;或,分隔開-->
  <add key="GatewayURL" value="閘道器1;閘道器2;閘道器3"/>
  
  <!--API相關設定-->
  <!--自動推播Api介面服務實體-->
  <add key="App.AutoPushClazz" value="true" />
  <!--服務負載均衡型別  Random表示隨機  Polling表示輪詢-->
  <add key="App.LoadBalance" value ="Random"/>
  <!--服務介面是否為本地部署  偵錯選項用到 對應的是遠端伺服器部署-->
  <add key="App.UseLocal" value ="false"/>
  <!--應用入口URL 由協定、主機或域名及埠號構成 80或443埠可以省略-->
  <add key="App.HostUrl" value="http://{ServerIP}:{Port}" />
  <!--實際部署宿主應用型別 參考:WebApi、WebService、WCF、WindowsService、WinForm等-->
  <add key="App.DeployAppType" value="WebApi" />

  <!--資料庫相關設定-->
  <add key="DBType" value="MySQL"/>
  <!--啟用的資料庫型別 目前支援SQLServer、MySQL和PostgreSQL-->
  <add key="BaseDataDB_Writer_MySQL" value="BaseDataDB_Writer_MySQL"/>
    <!--紀錄檔資料庫型別 目前支援SQLServer、MySQL、PostgreSQL、MongoDB和ElasticSearch-->
  <add key="LogDB_Writer_MongoDB" value="LogDB_Writer_MongoDB"/>
</appSettings>
AppConfig

在系統應用平臺我們可以對IP、埠、域名等進行申請和繫結操作。

上面的設定中,App.HostUrl可以通過預留位置自動解析應用伺服器IP(當然也可以自己直接手動繫結IP或域名),埠號則需要在系統應用平臺指定,防止應用程式埠衝突,埠分配必須規範有序。

在開發環境中,我們可以將是否為本地部署App.UseLocal設定為true,這樣服務治理平臺就知道這是一個偵錯伺服器,暫時不拉人叢集給其他服務呼叫,對開發偵錯排除干擾非常有用。

一個後端服務,組態檔通常只有上面這麼多。其實範例中API相關設定(App.HostUrl必選)、資料庫相關設定都是可選的,這些都可以在設定中心處理。也就是說一個後端新應用,設定可精簡到只有5個。

如果某些應用的App.HostUrl就沒有,PowerDotNet自定義了一套規則,可以像下面這樣設定:

 <add key="App.HostUrl" value="none://{ServerIP}:noport" />

歸根結底,一個新應用,最多隻需要SystemCode、AppName、LocalFirst、GatewayURL最後再加一個App.HostUrl這5個設定,不能再多了,這樣就能享受到PowerDotNet開發的便利,咩哈哈。

(2)、使用者端應用

在PowerDotNet和PowerDotNetCore中,所有非後端應用都必須通過服務治理平臺的閘道器間接呼叫介面完成互動,所有非後端應用都不能直接呼叫敏感介面,如DBKey、支付、財務、結算、人員資訊等介面。

以一個WinForm程式舉例,應用名稱叫Power.BaseData.ApixTool,這是一個呼叫Apix介面的WinForm程式,它的預設設定可能是下面這樣的:

<?xml version="1.0" encoding="utf-8" ?>

<appSettings>
  <add key="SystemCode" value="BaseData" />
  <add key="AppName" value="Power.BaseData.ApixTool" />
  <!--設定是否本地優先-->
  <add key="LocalFirst" value="0" />
  
  <!--閘道器相關設定 支援多個 以;或,分隔開-->
  <add key="GatewayURL" value="閘道器1;閘道器2;閘道器3"/>
  <!--自動推播Api介面服務實體-->
  <add key="AppSecret" value="應用金鑰" />

</appSettings>
AppConfig

使用者端程式預設設定只是把App.HostUrl換成AppSecret,AppSecret內容可以是明文也可以是密文,如果是內網使用者端,被呼叫的服務都沒有勾選驗證簽名和token,AppSecret設定也不是必須的。

(3)、前端應用

最典型的就是Angular、VUE、React、Svelte等SPA單頁應用,設定好閘道器、系統、應用名和應用金鑰,通過Axios模板方法呼叫閘道器就可以間接通過服務治理平臺和後端服務進行資料互動。

上面範例是React應用,對於後端介面,除了驗籤,可能還會有登入token校驗邏輯,PowerDotNet和PowerDotNetCore都支援。

(4)、其他應用

其他應用包括安卓、RF、Pad、iOS等等形式的應用,和使用者端應用非常類似,設定好閘道器、系統、應用名和應用金鑰,就可以通過閘道器間接和後端服務進行資料互動,簡直神速。

4、服務治理

如果新增的應用是後臺服務介面,可通過設定中心自動註冊服務介面,也可以在服務治理平臺管理後臺人工註冊服務介面,預設註冊的新介面都會自動加入服務消費白名單。

新增應用如果需要呼叫並消費其他應用的API服務,分兩種情況進行處理:

(1)、閘道器間接呼叫介面,要看服務治理中心授權的服務是否勾選驗籤和驗證token,如果是外網閘道器,必須構造簽名和token驗證,否則介面消費驗證不通過。

(2)、使用者端直接呼叫介面,也要看服務治理中心授權的服務是否勾選驗籤和驗證token,當然如果是內網不敏感介面,直接呼叫即可。

5、叢集管理

系統應用平臺可進行大規模叢集管理。

所有後端應用,都可以在系統應用平臺將應用拉入某個資料中心的叢集,便於叢集管理,當然對於一些不需要叢集管理的後臺管理系統,這不是必須的。

對於所有後端服務介面應用,註冊應用API介面後,必須在系統應用平臺將應用拉入某個資料中心的叢集,進行叢集管理,釋出時可通過拉入拉出叢集控制伺服器是否可達。

系統應用進行叢集化管理可以實現應用的優雅上線和下線功能,軟體可以控制的事情就不要讓硬體來做,PowerDotNet能完成的事情就不要讓其他軟體來做。

6、紀錄檔管理

如果新增應用在設定中心接入了紀錄檔平臺,登入紀錄檔平臺管理後臺,自動同步DBKey即可在紀錄檔平臺查詢紀錄檔。

7、監控管理

如果新增應用在設定中心接入了監控平臺,登入監控平臺管理後臺,可以看到監控收集到的資料,尤其是對於後端應用,監控平臺能及時預警發現問題。

 十一、資料處理

我們平常所開發的大部分業務邏輯型應用程式都是資料密集型(data-intensive)而非計算密集型(compute-intensive),也就是說系統的瓶頸通常都來自於對資料的處理而非CPU。

資料庫、訊息佇列、快取、檔案等中介軟體或軟體工具都可以被統稱為資料系統,隨著技術的不斷髮展,它們之間的界限也越來越模糊。

比如某些NoSQL資料儲存軟體可以被當成訊息佇列用(參考Redis),而訊息佇列則帶有類似資料庫的持久保證(比如RabbitMQ、RocketMQ和Kafka等)。

PowerDotNet和PowerDotNetCore平臺化軟體的設計與實現偏重於資料處理,對主流的技術選型都做了大量深度開發,簡化運維部署的複雜度,提高資料系統的高可用性。

同時業務功能模型選擇也有很多講究,比如支付和財務平臺系統的壓力非常大,所以系統互聯互通的時候,優先推薦拉模式,而不是支付和財務平臺主動推播模式,雖然支付財務主動推播是標配。

對於經典的釋出-訂閱模式,建議採用訊息匯流排進行統一管理,PowerDotNet和PowerDotNetCore不建議接入應用方直接使用各種中介軟體的釋出訂閱功能,否則高並行下容易產生效能問題。

PowerDotNet和PowerDotNetCore已經開發出了典型的資料處理為主的公共服務平臺,如支付、財務、結算、CRM等系統,後續文章會講講支付平臺、財務平臺等系統的架構設計與開發。