給公司部門設計的SOA架構

作者: 蘑菇先生  來源: 博客園  發布時間: 2015-03-05 21:11  閱讀: 6490 次  推薦: 8   原文鏈接   [收藏]  

新來老大年前開會說:各位同學,公司業務越來越重,未來幾年要成倍增長......,我們要梳理出一套新架構,才能更好的支持N萬用戶.....,以后升職加薪當上....打敗.....
想想還有點小激動呢,于是過年時樓主趁等待相親妹紙無聊的時候,反思了目前系統現狀,構思設計新架構如下。

閱讀目錄:

  1. 現有系統
  2. 新架構   
    2.1 邏輯架構圖 
    2.2 解釋說明
  3. 系統實施
    3.1 SOA管理中心
    3.2 發布服務
    3.3 訂閱服務
    3.4 采蘑菇示例
  4. 設計目標
    4.1 盡可能少的侵入
    4.2 服務自治&&水平擴展
    4.3 系統升級降級
  5. 常見問題
    5.1 ClientApi VS ServiceApi
    5.2 聚合服務
    5.3 服務分級
  6. 總結心得

現有系統

鄙司業務比較重,系統也有些年頭,各研發團隊、系統都比較穩定了。所以不差也不太好,總之也能滿足現有需求。但近2年O2O,移動互聯網等大行其道,老大們也都心動了,開始磨刀霍霍了。而現有系統應對復雜的變化,在一些地方頗顯不足:

  • 接口沒有統一管理
  • 很多組件無法復用/重復造輪子
  • 模塊間職責不清,耦合過深
  • 聯調排查問題比較慢
  • 開發前規劃不足,形成堆積
  • 缺乏API規范/文檔較少

新架構

邏輯架構圖:

查看大圖

解釋說明:

  • A開頭:是系統級別,可以獨立部署。即可寄宿在IIS/Windows Service等上面。
  • B開頭:是模塊級別,不可獨立部署。相對獨立的功能模塊,而又不大,所以依附其他系統或者和多個模塊組成一個子系統。模塊級別在項目中可以分多層,可根據分數升級成子系統(見系統升級降級)。
  • C開頭:是組件級別,不可獨立部署。大多數是公共性組件,一般是單獨類庫存在,以DLL提供使用。一些開源組件也歸到這里,例:Autofac,FluentData。 需要自搭Nuget服務器,進行統一版本管理。
  • 字母后面的數字:是代表服務的級別,見服務分級。
  • 系統通信: 各系統之間盡量走內網WCF/TCP,對外合作單位及各移動端走WebApi/Http。
  • 傳輸格式: Protobuffer、Json。
  • 數據交換: 優先通過數據服務接口,其次SSIS、Job。
  • 基礎平臺: 緩存Redis,隊列RabbitMq等。依賴抽象,框架可替換。
  • DB層: 每個子系統擁有自己的子DB,原則上不能跨庫讀其他的。
  • 高可用: 子系統自行做負載,服務變更通知使用zookeeper。
  • 單向2級:只能訂閱服務,不能發布服務,2級只能訂閱2級服務。
  • 定點:某個客戶端只能訂閱某個服務端提供的服務。

系統實施

SOA管理中心

這是新架構的核心部分,主要功能如下:

  • 提供發布/訂閱/ServiceAdapter組件
  • 提供Web管理界面
  • 對服務訪問的各種配置
  • 在高峰期對服務限流/報警
  • 服務訪問授權、描述

發布服務

各系統通過Web管理頁面進行服務配置發布。

也可以通過管理中心提供的組件,進行配置發布:

    protected void Application_Start()
    {
        ServicePublisher.Pushlish(new ServiceConfig()
        {
            ServiceName = "獲取預訂單詳情",
            Qps = 1000,
            Level = 1,
            Key = "xxxx-yyyy",
            Source = SubscribeSource.All,
            ServiceAddress = "/Order/GetDetail",
            //其他
        });
    }
    [ServiceFilter]
    void GetDetail()
    {
    }

訂閱訪問服務

各系統通過管理中心提供的組件,去獲取訂閱的服務,然后通過適配器去訪問接口,服務變更在心跳里面做:

    protected void Application_Start()
    {
        //獲取服務列表
        var serviceList = ServiceManager.GetServiceList();
        GlobalService.ServiceList=serviceList;
    }
    void Heartbeat()
    {
        var serviceList = ServiceManager.GetServiceList();
        GlobalService.ServiceList=serviceList;
    }
    ServiceAdapter.Access(GlobalService.ServiceList[0]);

采蘑菇示例

設計目標

盡可能少的侵入

這點是非常重要的,如果不能很好的重用已有的系統或侵入性太強,勢必會導致:

  • 新架構周期過長,長期維護二套結構。這種情況下,成本太高,不好推行下去或者還未推行就被砍了。
  • 開發人員的抵抗,每個猿類內心都有桀驁的脾氣、造輪子的天賦、重組世界的夢想...。如果太復雜、約束太強,天知道你們這群猿類會干出什么事情!

基于這種考慮,才采用服務分布式而不是服務集中式。

  • 每個系統在需要時,去訂閱服務,然后拉取服務地址/MyNeedServcie.list。
  • 然后通過ServiceAdapter訪問服務,ServiceAdapter中會做權限等一些校驗。
  • 在服務上增加ServiceFilter,Fileter會做權限校驗及服務被調用的信息采集。
  • 然后在管理中心添加服務,文檔描述。

好處是:A系統與B系統是直接交互的,服務調用不走中轉路由,性能也好。而組件的作用僅是輔助性的約束。

服務自治&&水平擴展

由于侵入性較小,所以各個系統之間的服務變更,維護完全由各自研發團隊維護。

本系統之間通訊不走服務,直接內部調用。調用通過ServiceAdapter組件訪問,ServiceAdapter包含對進程內、WCF、WebApi等訪問的封裝,這樣便于以后替換成其他服務。 各服務在擴展上不受管理中心節制,自行做負載、增加服務器即可。

系統升級降級

當有個新需要過來時,會根據產品是否需要獨立部署,和現有系統耦合性等因素,來評估是模塊級還是系統級。

對于舊模塊,根據重要程度、訪問量等評估出分數。達標的由模塊抽離出子系統,單獨管理。

同樣對于舊系統,不達標的進行降級處理,縮小成模塊整合到其他系統里面。

這塊其實很重要,如果不對項目做好評估的話,往往會導致一個系統越來越沉重。最后的結果就是維護越來越麻煩,經常出問題。最后逼不得已就推到重來,這個成本就較大些,當然成本的事情老大會考慮更多些。處于這種情況下猿類們會一邊吐槽著之前的同類渣渣,一邊躍躍欲試準備大展身手,讓你們瞧瞧什么叫DDD、TDD、設計模式......。

前提是在需求開發時,按模塊進行分小層而不是整個大層,這樣方便協作開發和抽取成子系統。

常見問題

ClientApi VS ServiceApi

ClientApi這個在前期用的比較多的辦法。優點很明顯:簡單快捷,從Nuget上安裝引用即可。這樣后期會問題越來越多。

就拿緩存Redis來說,多個系統都使用客戶端直接訪問Redis服務器。如果有個系統連接數忘記關閉,就會影響整個大系統,原因就是Client權限過大,客戶端是可以對redis服務器直接進行操控。這種情況下redis服務器本身是暴露在外的,哪怕客戶端封裝的再好也不行,只要研究下通信協議規范,就可以自己寫個客戶端連接(參見C#實現redis客戶端(一))。 這個通信期間無法管控,無法做攔截,同樣隊列等其他也是同樣情況。

ServiceApi:

我們在中間加了一層,在緩存系統里面做管控,同樣依賴抽象,Redis可替換。緩存系統以服務的形式發布給其他系統使用。 避免不了的就是性能有損耗,當然這個損耗可以通過一些手段減小。

聚合服務

服務的顆粒度一直是SOA設計的頭疼事情。太粗了就很難復用,太細了需要多次往返交互,其性能、事務處理都是個問題。 比如下訂單服務,這個過程中包含創建用戶資料,生成預訂單、支付訂單,更新賬務關系,更新庫存等一系列的操作。這是個粗粒度服務,里面包含若干子系統的提供的細粒度服務。 粗粒度服務下,多個子系統避免不了互相交互,長久下去會讓系統過于沉重,變得職責混亂。

服務設計準則就是讓服務高內聚,服務之間松耦合、邊界清晰。所以我們抽離一個聚合服務系統,它專門負責把各系統提供的細粒度服務進行整合,提供給前端使用。而其他各個系統只做自己職責之內的事情。 在聚合服務系統中,方便我們更合理的把控服務的顆粒度,提高服務復用。

服務分級

多個研發團隊協作時,很難每個人都對全部業務熟悉。所以為了避免服務調用混亂,甚至循環依賴調用,增加了對服務的分級。

按圖中所示,1級服務不能調2級服務,即低級不能調高級,高級可調低級,同級互相可調。

這個級別針對單個服務而分的。比如有個更新庫存服務,它沒有外部依賴的服務,只是更新自己的DB,這樣我們就可以把它劃分為1級服務。 而我們的聚合服務系統中有個下訂單粗粒度服務,它內部調用更新庫存服務,那么它就是2級服務。很明顯這里的1級不應該調用2級,對服務分級也是這個目的。

總結心得

  • 好架構是不斷進化來的
  • 盡可能考慮到每個細節
  • 注重整體平衡性,而非局部最優
  • 依賴抽象,而不是具體哪個框架技術
  • 先考慮人、資源,在考慮用哪個技術
  • 跟妹紙相處時不要想程序那點事
8
0
 
標簽:SOA
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()