我對SOA的認識以及心得

作者: lovecherry  來源: 博客園  發布時間: 2008-12-03 16:41  閱讀: 1816 次  推薦: 0   原文鏈接   [收藏]  

注:本文來源于我給公司內部發的郵件中,所以背景都是基于我們現在的應用,而且思路也很混亂,請大家見諒。

05年開始接觸到分布式架構,06年在原先的基礎上從頭開始設計了一套分布式架構,當時SOA這個概念也沒這么火。整個大平臺的開發、性能和可擴展性都得到了考驗,覺得有一些東西想和大家一起分享。

我不知道我所說的這些算不算真正的SOA,我也沒讀過什么SOA的書籍,我覺得SOA這個概念非常抽象,任何概念的產生都是由原因的。因此,我也不會說一些抽象的原則,只是想說一些在過去幾年實施“SOA”過程中的一些心得和一些細節,希望對大家有用。

       不說什么是SOA,先來說說我們現有架構遇到的一些問題:

  • 同樣一個邏輯,A系統(ASP)使用COM實現一份(我們現在的JAVA庫),B系統(.NET)在開發的時候覺得調用JAVA也是很麻煩的,索性自己實現一份邏輯,可能是存儲過程,也可能是在代碼中硬編碼SQL,C系統(由系統部門開發的.NET程序)也用到了相同的邏輯,由于和產品部門缺乏必要的溝通,也實現了一份邏輯。最后,如果這個相同的邏輯需要修改,則需要修改A、B、C三個系統,一份邏輯在三個地方實施有幾個缺點,一來是因為如果需要修改要改三個地方,二來是增加了工作量,三來是占用了不必要的資源(因為大家可能都實現了自己的緩存)。
  • 所有網站全部部署在一個WEB服務器上,直接實現負載均衡。這樣的方案有幾個缺點,一是幾乎沒一個網站程序都有自己的緩存,每臺服務器的緩存是冗余的,而且甚至每個網站中的緩存都有重復,二是如果一個網站有問題會影響到其它網站(比如進程回收,應用程序池不能100%解決這個問題,而且我們現在并沒有注重應用程序池的劃分,又比如某些應用是長請求、過長時間占用線程),三是不能有效利用服務器資源,這是因為不是每一個網站都具有相同的訪問量,不是每一個網站都需要相同的資源(有些需要特別多IO、有些需要特別多CPU、有些甚至是內存)。

雖然說我們現在是使用了三層架構,但并沒有什么重用,而且所有的層還是部署在相同的服務器上的。為了解決前面的2大問題,我們首先想到了:

  •  是不是有什么方法可以讓相同的邏輯被其它系統重用?
  •  是不是考慮把邏輯以服務的形式對外部(其他模塊)公開?

由此引入面向服務架構的概念,我們通過這些公開的服務進行邏輯的重用,提高系統性能也降低了模塊之間的耦合性。架構圖見我以前寫的文章http://www.cnblogs.com/lovecherry/archive/2008/06/18/1224496.html

如果確實采用這種架構,我們的開發方式會有什么改變呢?

  •  在一般情況下,我們一般認為A系統對應A數據庫,B系統對應B數據庫,每一個系統都有自己的數據庫。傳統的方式是A系統和B系統在數據庫端直接使用JOIN進行交叉耦合。如果實施SOA的話,最佳實踐應該是對于大多數系統來說,禁止A系統直接訪問B系統的數據庫,反之亦然。我要你的數據,就必須調用你公開的服務。而且這個服務或者說接口或者說契約,盡量是粗粒度的。比如一個邏輯包括XYZ三個過程,如果獨立提供三個方法的話,每一次方法調用都是網絡調用的過程,性能比較低,而且更重要的原因,這個模塊提供了這么細粒度的三個方法,如果這三個構成了一定邏輯的話,很有可能這個邏輯就在調用方和提供方兩個模塊都實現了相同的邏輯。雖然說確實是提供了服務,但是沒有達到封裝邏輯這個重要的目的,而且也產生了性能的下降,這種服務就顯得很不值得。
  • 一個大系統有許多模塊或者說子系統,每一個都有自己的復雜邏輯和存儲結構。開發人員可能只熟悉自己的那一部分,如果我的系統確實要用到其它系統的數據,按道理是應該想到調用它提供的程序集。很多時候我們并沒有這么做,是因為我們并不知道對方有沒有提供我需要的功能,即使知道提供了也不知道怎么去使用,如果要去用的話可能熟悉對方系統的時間會比直接在數據庫中進行JOIN需要的時間還要長。這是一種惡性循環,因為這樣又導致了一個邏輯在多處出現,一份數據在多處取得、保存和緩存。有了SOA,我們應該能在SHAREPOINTWIKI上看到一份清單,在哪個HTTPTCP端點上具有什么服務,服務中有哪些方法,這些方法是干什么的,返回什么,傳入什么,使用的注意事項,如果我開發的系統需要用到外部的數據,我第一時間想到的不應該是去看數據庫中我需要的數據在哪里,而是應該是去看看是否對方系統提供了這樣的服務,如果沒有提供的話則和服務的提供者進行一些溝通。你可能會問,我作為系統的開發者,我也不知道要對外提供哪些服務,我也不知道別人需要用到什么,確實是,但是至少我們現在可以做的是把內部使用到的一些邏輯以服務形式對外公開,一般來說自己系統的這些函數如果能滿足自己要求的話從功能上來說可以滿足別人要求,只不過別人可能需要的并不是這么多罷了。
  • 我們現在做TECH SPEC的時候可能關注內部的實現,如果是SOA的話,我們就需要關注現在在做的這個系統會用到別人的哪些接口,別人可能會用到我什么接口,我需要公開出來。可能還會考慮,我用了ABC三個系統的接口,是否需要把這個邏輯以粗粒度服務公開出來。每一個公開接口的參數、返回都需要仔細考慮,把這些都列入到架構設計中,和架構師一起完成服務的定義。開發人員可能只對自己系統的接口和邏輯比較熟悉,架構師的作用是給開發人員建議,哪些接口你可能需要,哪些接口你可能需要對外提供,是否需要做緩存。
  • 我們現在的部署是非常簡單的,如果實施了SOA,很有可能一個系統需要調用十幾個外部子系統的接口,每一個接口都需要制定地址、調用策略以及契約。地址和調用策略需要是可配置的,一般定義在配置文件中或者數據庫中,這樣一個系統的部署可能非常復雜,打個比方就像芯片的引腳一樣,有很多,一個引腳沒有接到合適的地方,系統就不能工作。雖然部署負責了,但是系統之間的耦合非常小的,大家只是依賴于某個網絡環境中的地址,依賴于某個契約。這樣的話,系統的伸縮性就很強,有些服務需要很高的資源,就給獨立的服務器,有些服務占用資源很小,可以合并在一起。當然,也可以根據服務的性質,比如特別需要IO、特別需要CPU來分配到合適的服務器上。服務器并不一定是一樣的,有的服務器內存特別大,有的服務器CPU特別好。
  • 還會遇到一個問題,就是開發人員不太愿意調用其它的接口。一是對別人的東西往往默認會覺得是實現糟糕的,性能很差的,二是覺得不放心,會不會到時候你沒給我正確的數據,影響我的開發,產生相互推卸責任的問題。其實,這種想法不對,一個人不可能開發系統的全部,作為使用者來說要使用別人的接口信任別人的接口,作為接口提供者來說需要積極對自己的接口負責,進行完善的單元測試,如果調用者有特別的需求在討論后進行改進。這也就是說引入SOA的話,我們需要更多的溝通。

    說的有點亂,接下來想說說我在實施過程中遇到的一些細節問題,很多時候SOA實施的失敗都是因為一些細節。
  • SOA的接口設計必須基于業務的。架構師應該是一個總導演,對所有系統的業務都有一個認識,理解業務之間的關系,和開發人員一起定義合理的接口。這包括,接口是否代表了業務、是否是合適的粒度、是否會有性能問題,別小看接口設計,一旦確定以后很難修改,接口的好壞決定成敗,我列為第一要素。
  • 在實施中,管理很關鍵,有許多要點是需要有強制的。比如除非特殊需要不能直接引用其它數據庫,即使是本系統也應該引用本系統的服務,也就是說網站項目里面沒有連接字符串、沒有數據訪問邏輯,只有端點的配置。還比如是A系統的開發人員有這個責任為A系統對外的所有接口進行后續的維護和功能擴展,不是說A系統結束了,我的數據我也不管,不行,別人如果需要的數據確實是我的數據的話,我就要管。
  • 從性能角度考慮,一般內網中的服務通訊采用TCP(二進制序列化),公網的走HTTP。還有一種方式是IPC方式,進程間通訊,我們以前也用的挺多的,雖然說緩存應該在一個地方建立。但很多時候,某個方法的調用是每次訪問頁面都需要進行一次或多次的,如果再進行網絡調用的話性能很成問題,比如論壇上的臟話過濾,如果某個臟話服務提供了臟話過濾的接口,如果這個這個接口需要TCP調用的話性能不高,這個時候我們會考慮把這個服務部署在WEB服務器上,而不是APP服務器上,IPC方式進行進程間通訊。
  •  到最后我們會發現我們有20個子系統,也就至少有20個服務(一般是以Windows服務部署在APP服務器上)。而且如果服務部署多份做負載均衡的話,可能就有上百個網絡地址。一個網站如果引用了5個服務,就需要一個一個IP地址(或者說端點)進行配置,如果將來服務遷移,那么這些網站的配置文件修改是一個大問題。雖然說我們會有一個拓撲圖來描述網站之間服務的依賴情況,但是配置文件的修改工作量不小而且容易出錯。推薦的做法是有一個數據庫來存放所有服務的端點定義、描述,使用一個單獨的服務來提供所有服務的端點信息,在網站中只需要配置這個服務的端點信息,然后引用各種服務的契約就可以了。考慮到效率關系,在每一個WEB服務器上都安裝有這個配置服務,以IPC方式提供所有網站進行調用,當然,其中的端點信息都會做緩存。
  • 前面說的是網站引用服務的端點信息配置問題,還有一個問題就是服務的健康監視問題,服務是以Windows服務形式運行的,我們需要檢測Windows服務的狀態,占用的CPU和內存信息。我們在每一個APP服務器上又裝有一個AGENT服務,專門用于監視這些服務進程的情況,一旦發現問題會第一時間通知網絡部門甚至是開發人員,當然服務無響應的情況比較少,一般常見的情況是服務沒有正確部署(缺少DLL不能啟動),或者是占用了過多的內存。這個AGENT的另外一個作用就是收集服務器上的錯誤日志,并且負責更新和重啟服務。也就是說所有服務的更新是自動化的更新,我們發布的時候發布到指定的RELEASE服務器,由專門的管理工具進行服務的自動更新,服務如果做負載均衡的話手動更新很麻煩。而且很多情況下相同的服務需要在多個服務器部署,比如IPC服務
  •  服務的實例管理問題,一般有SINGLETONSINGLECALL等方式。推薦采用SINGLECALL方式,如果服務具有狀態的話會大大增加服務的開發難度,一是需要考慮線程同步問題,二是需要考慮生命周期。其實,我一直覺得有狀態的服務配合ORM數據訪問層的使用是很好的,但做起來可能會遇到很多問題。
  • 在存儲過程中做事務還是很簡單的,SOA如果要做分布式事務的話,實現不是打大問題,但性能是很大的問題,很容易引起數據庫對象的死鎖。大多數情況下我們對分布式事務的替代方式是采用隊列,放到隊列中的東西就認為是一定可以成功的,對于不使用隊列的情況,如果調用失敗了則記錄日志,不會進行回滾。除非涉及到錢的地方才做分布式事務。
  • 版本問題也是需要考慮的。傳統的實現方式是,如果新增接口的話以前的程序是沒有影響的,如果萬不得已需要修改接口的話就大吼一聲,我這個接口要改了,然后給大家發一份,請調用者按照我的要求修改一下,連同我的服務一起重新發布。對于WCF的話,有MEX元數據交換,這樣就不用手動引用新的契約,只需要從HTTP地址上更新新的服務即可。但有一個不得不考慮的問題就是萬一在調用其它服務的時候發生錯誤了,我們怎么知道是哪個服務的版本出現問題了呢。我們是這樣做的,調用服務的代理有一層封裝,如果網絡調用發生錯誤的話,會記錄詳細的錯誤信息,哪個服務(服務的版本)、哪個方法在哪個端點上的調用、傳入的參數是什么,返回的是什么。這樣,在部署的過程中發生錯誤或是版本問題,我們就很容易知道錯誤的原因了。那么怎么知道服務的版本呢?沒一個服務都約定有一個GetVersion方法,這個方法兩個作用,一是給管理工具測試這個服務是不是還有效,二是給配置服務獲取服務的版本號。
  • 如果引入SOA的話,不可避免的是大大增加了整個系統的部署復雜性。想一下,在LIVE上,我們可能有20WEB服務器,10APP服務器(我們以前是21這樣進行配置的,服務按照類型和資源不同放在不同的APP服務器,WEB服務器CPU特別強,APP服務器是廉價服務器,有足夠大的內存,對于WEB程序來說確實沒什么大的CPU計算,服務也就是緩存比較厲害)。10APP服務器上放100個服務,就產生了100個端點地址。開發人員其實不用考慮服務在LIVE上怎么部署的,需要架構師在部署的時候協調部署團隊一起完成部署工作,架構師知道哪個服務部署在哪個服務器最合理,以哪種信道進行部署最合適。部署團隊需要對各個服務器的結構很清楚,也要學會使用健康監控工具(我前面提到的監控服務運行狀態的工具和異常管理工具來發現部署上的問題),這就對部署團隊的要求更高了。實在不行的話可以要求開發人員參與,開發人員應該沒權限直接進行服務的部署,但是有權使用兩個工具的,一來用于排查問題,二來也會有很大的成就感。
  •  服務監控工具以一個拓撲圖形式展現整個網絡上WEB服務器、APP服務器的IP地址、CPU內存使用,以及服務的引用情況和每一個服務對CPU和內存的占用,以及服務的健康情況。監控人員24小時值班負責監控,出問題的時候及時重新啟動相關服務。異常管理工具每天收集各個系統的異常,開發人員每天上班和下班的時候查看一次這個工具,知道自己負責的模塊產生了哪個異常(異常有幾種,一種是程序有BUG,一種是外部有人在攻擊造成的,還有一種是前面說的服務的版本和運行問題產生的異常)。當然,架構師也應該時刻關注這2個工具,知道整個系統的健康情況。
  • 從網絡上來說,APP服務器應該跨2個網段,DB服務器應該外部不能直接訪問,所有數據庫操作都是通過APP服務器提供的服務訪問DB的,網站不具有任何連接字符串不能直接訪問DB服務器(不在同一網段)。WEB服務器和APP服務器之間應該走TCP,如果是跨國的話應該有VPN鏈路。
  •  從軟件架構上來說,我們以前使用的是.NET Remoting對內,Web服務對外的方式,中間層以Windows服務作為載體。對于.NET 3.5時代,可以采用WCF+Windows服務承載的方式。WCF支持元數據交換是一個優點,另一個優點是方便TCP/HTTP各種綁定的切換,當然也可以同時提供多份綁定。如果是細粒度服務的話,可以使用ADO.NET DATA SERVICE+ADO.NET EF的方式直接進行提供。表現層可以直接使用ADO.NET DATA SERVICE也可以使用自定義的JSON/XML數據,不屬于SOA的范疇就不擴展了。

總結一下:

  • 對于ETOWN的應用,SOA架構是絕對適合的。
  • 實施SOA,技術不是問題,最大的問題還是管理和溝通(協作)。
  • 實施SOA的話,我們需要重新構建一套基礎架構,提供統一的端點配置管理、異常管理、健康監控、契約協作平臺等。不然到最后的配置和管理將會很混亂。
  •  我們不需要更多的服務器,但我們需要更合理的分配服務器。而且整個系統的部署架構可能隨著時間的遷移不斷調整的,合并壓力小的服務,拆散壓力大的服務。怎么做負載均衡,這都是一直調整的。
  • 實施SOA需要開發人員有更好的意識,包括協作意識,包括架構意識。當然,也需要架構師能夠參與到每個項目中去,心中對業務有大局觀。
  •  配置可能是復雜的,需要有工具來確保這個復雜的過程。服務和網站怎么配置是很重要的事情,需要架構師和開發人員討論決定,不是說隨便放上去能用就可以。
  • 在做架構的時候要站在較高的角度來看,眼光要長遠,暫時的性能問題不一定是問題。按照網絡/磁盤/內存/CPU的層次來考慮。很多時候SOA和性能是有沖突的,就像不能一味覺得ORM性能不好就不去使用。考慮80/20原則,任何東西滿足了80的應用就達到了目的,剩下的20進行特殊處理。

暫時就寫這些,大家拍磚。

 

補充幾點:

  • 從服務契約設計上來說,應該讓這個契約盡可能獨立,不依賴于其它的契約。服務的調用過程不能依賴于服務本身的狀態,應該在任何情況下服務的作用不會由環境所變。
  • 雖然說是內部實施,但最好數據契約的類型是標準類型,通用類型,原生類型,方便以后做開放API的時候真正實現對外的服務。其實SOA強調松耦合性,因異構平臺協作的需求產生,強調一切基于消息,無關服務平臺。
  • SOA的實現包括業務分析、契約規劃、服務管理、消費者管理、文檔管理、配置管理、迭代整合等重要步驟,不是說我要建立A契約就建立,我要消費A契約就消費,要體現在管理中。我一直覺得SOA不是組件升級到服務這么簡單,軟件開發流程、管理流程、設計分析方法、配置管理都會有巨大的改變,前期準備要充分。
  • 在建立前期需要制作完成一個基礎的架構供開發人員使用。比如說是不是需要擴展VS內建的WEB引用,使得生成的客戶端代理包括異常處理、端點配置(從配置服務中獲取)等內容。非業務相關異常的收集和發送等工作應該是自動的,無需編碼。由于調用的復雜性,服務可能還會調用服務,在部署的時候配置問題很難察覺,所以其中的異常處理非常重要。
  • 項目完成后的代碼審閱需要對項目中用到的服務進行逐一檢查,如果有改變需要在拓撲圖(推薦有專門管理軟件來維護這個拓撲圖,并且還能檢查各個節點的健康狀態)中進行修改。必要的話還可以為每一個節點實現信任機制,得不到信任的消費者將不能消費。甚至這個工具可以和SHAREPOINT結合,也提供文檔的管理。
  • 最理想的方式是實現服務的自動部署,全部依靠管理工具來完成,因為在服務器上安裝Windows服務,需要復制文件、卸載原來的服務、安裝新的服務、服務運行賬戶的配置,如果服務達到上百個的話,部署的壓力也比較大。

最后,什么是SOA?個人覺得SOA是提供了系統級的松散組合和重用的基于消息的整合方案。

0
0
 
標簽:SOA
 
 

文章列表

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

    IT工程師數位筆記本

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