from:http://www.infoq.com/cn/articles/micro-soa-2

          上一篇文章中,我說到SOA是一個特別大的話題,不但沒有絕對統一的原則,而且很多原則本身的內容也具備相當模糊性和寬泛性。雖然我們可以說SOA ≈ 模塊化開發 + 分布式計算,但由于其原則的模糊性,我們仍然很難說什么應用是絕對符合SOA的,只能識別出哪些是不符合SOA的。

          本篇將對8種可操作的服務設計原則進行細化的分析,作為SOA實踐的參考。

          服務設計原則1:優化遠程調用

          這里的遠程調用特指RPC(Remote Procedure Call)。當然更面向對象的說法應該是遠程方法調用或者遠程服務調用等等。

          由于SO接口通常要被遠程訪問,而網絡傳輸,對象序列化/反序列化等開銷都遠遠超過本地Object訪問幾個數量級,所以要加快系統的響應速度、減少帶寬占用和提高吞吐量,選擇高性能的遠程調用方式經常是很重要的。

          但是遠程調用方式往往又要受限于具體的業務和部署環境,比如內網、外網、同構平臺、異構平臺等等。有時還要考慮它對諸如分布式事務,消息級別簽名/加密,可靠異步傳輸等方面的支持程度(這些方面通常被稱為SLA:service level agreement),甚至還包括開發者的熟悉和接受程度等等。

          因此,遠程調用方式往往需要根據具體情況做出選擇和權衡。

          以Java遠程Service為例分析不同場景下,傳輸方式的某些可能較好選擇:

          • 內網 + 同框架Java客戶端 + 大并發:多路復用的TCP長連接 + kryo (二進制序列化) (kryo也可以用Protostuff,FST等代替)
          • 內網 + 不同框架Java客戶端:TCP + Kryo
          • 內網 + Java客戶端 + 2PC分布式事務:RMI/IIOP (TCP + 二進制)
          • 內網 + Java客戶端 + 可靠異步調用:JMS + Kryo (TCP + 二進制)
          • 內網 + 不同語言客戶端:thrift(TCP + 二進制序列化)
          • 外網 + 不同語言客戶端 + 企業級特性:HTTP + WSDL + SOAP (文本)
          • 外網 + 兼顧瀏覽器、手機等客戶端:HTTP + JSON (文本)
          • 外網 + 不同語言客戶端 + 高性能:HTTP + ProtocolBuffer (二進制)

          簡單來說,從性能上講,tcp協議 + 二進制序列化更適合內網應用。從兼容性、簡單性上來說,http協議 + 文本序列化更適合外網應用。當然這并不是絕對的。另外,tcp協議在這里并不是限定遠程調用協議一定只能是位于OSI網絡模型的第四層的原始tcp,它可以包含tcp之上的任何非http協議。

          所以,回答上面提到的問題,WebServices (經典的WSDL+SOAP+HTTP)雖然是最符合前述SOA設計原則的技術,但并不等同于SOA,我認為它只是滿足了SOA的底線,而未必是某個具體場景下的最佳選擇。這正如一個十項全能選手在每個單項上是很難和單項冠軍去競爭的。更理想的SOA Service最好能在可以支持WebServices的同時,支持多種遠程調用方式,適應不同場景,這也是Spring Remoting,SCA,Dubbo,Finagle等分布式服務框架的設計原則。

          遠程調用技術解釋:HTTP + JSON適合SOA嗎?

          JSON簡單易讀,通用性極佳,甚至能很好支持瀏覽器客戶端,同時也常被手機APP使用,大有取代XML之勢。

          但JSON本身缺乏像XML那樣被廣泛接受的標準schema,而一般的HTTP + JSON的遠程調用方式也缺乏像Thrift,CORBA,WebServices等等那樣標準IDL(接口定義語言),導致服務端和客戶端之間不能形成強的服務契約,也就不能做比如自動代碼生成。所以HTTP + JSON在降低了學習門檻的同時,可能顯著的增加復雜應用的開發工作量和出錯可能性。

          例如,新浪微博提供了基于HTTP + JSON的Open API,但由于業務操作比較復雜,又在JSON上封裝實現了各種語言的客戶端類庫,來減少用戶的工作量。

          為了解決這方面的問題,業界有很多不同方案來為HTTP + JSON補充添加IDL,如RSDL、JSON-WSP、WADL、WSDL 2.0等等,但事實上它們的接受度都不太理想。

          另外值得一提的是,JSON格式和XML一樣有冗余,即使做GZIP壓縮之類的優化,傳輸效率通常也不如很多二進制格式,同時壓縮、解壓還會引入額外的性能開銷。

          遠程調用技術解釋:Apache Thrift多語言服務框架

          Thrift是最初來自facebook的一套跨語言的service開發框架,支持C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, JavaScript, Node.js, Smalltalk, Delphi等幾乎所有主流編程語言,具有極好的通用性。

          Thrift被facebook,twitter等巨頭以及開源社區都廣泛使用,是非常成熟的技術。

          Thrift的服務契約通過類似如下形式的IDL定義:

          struct User {     1: i32 id,     2: string name,     3: string password }  service UserService {     void store(1: User user),     UserProfile retrieve(1: i32 id) } 

          非常類似于C語言,易讀易寫,比WSDL簡單明了得多。比用java之類的編程語言也更方便,有時候可以把所有相關的接口和數據結構定義放到同一個文件,發布出去的時候不用再打一個壓縮包之類,甚至可以直接粘貼到文檔中

          Thrift還提供工具,可以基于IDL自動生成各種語言對應的服務端和客戶端代碼:

          [lishen@dangdang thrift]thrift --gen java user.thrift [lishen@dangdang thrift]$ thrift --gen cpp user.thrift [lishen@dangdang thrift]$ thrift --gen php user.thrift [lishen@dangdang thrift]$ thrift --gen csharp user.thrift 

          我認為thrift是比WebServices更簡單高效的技術,是在SOA中對WebServices最具有替代性的技術之一。

          遠程調用技術解釋:多路復用的TCP長連接

          這是一種追求極致高性能高伸縮的方式,這里只做簡要介紹。

          比較典型的是twitter的Mux RPC協議以及google的SPDY協議,在其中多個請求同時共用同一個長連接,即一個連接交替傳輸不同請求的字節塊。它既避免了反復建立連接開銷,也避免了連接的等待閑置從而減少了系統連接總數,同時還避免了TCP順序傳輸中的線頭阻塞(head-of-line blocking)問題。

          另外,國內比較著名的開源dubbo框架的默認RPC協議,以及業界許多小型開源RPC框架也都是類似的思路。

          采用多路復用機制后,一般就要求服務器端和客戶端都支持額外的類似于會話層(即OSI網絡模型第六層)的語義,導致它們必須要依賴于同一套RPC框架。

          其他很多RPC機制都是使用TCP短連接。即使有些RPC使用了長連接,但一個連接同一時間只能發送一個請求,然后連接就處于閑置狀態,來等待接收該請求的響應,待響應完畢,該連接才能被釋放或者復用。

          HTTP 1.1也支持一種基于pipeline模式的長連接,其中多個HTTP請求也可共用一個連接,但它要求響應(response)也必須按照請求(request)的順序傳輸返回,即FIFO先進先出。而在完全多路復用的連接中,哪個的響應先ready就可以先傳輸哪個,不用排隊。

          當然,短連接、長連接和多路復用長連接之間不存在絕對的好壞,需要取決于具體業務和技術場景,在此不詳細展開了。

          遠程調用技術解釋:Java高效序列化

          最近幾年,各種新的Java高效序列化方式層出不窮,不斷刷新序列化性能的上限,例如Kryo,FST等開源框架。它們提供了非常高效的Java對象的序列化和反序列化實現,相比JDK標準的序列化方式(即基于Serializable接口的標準序列化,暫不考慮用諸如Externalizable接口的定制序列化),在典型場景中,其序列化時間開銷可能縮短20倍以上,生成二進制字節碼的大小可能縮減4倍以上。

          另外,這些高效Java序列化方式的開銷也顯著少于跨語言的序列化方式如thrift的二進制序列化,或者JSON等等

          遠程調用技術解釋:RMI/IIOP和分布式事務

          RMI/IIOP是Java EE中標準的遠程調用方式,IIOP是CORBA的協議,只有IIOP上的RMI才支持兩階段提交的分布式事務,同時提供和CORBA的互操作。

          當然,嚴格的兩階段提交事務并不高效,還可能嚴重影響系統伸縮性甚至可用性等等,一般只應用在非常關鍵的業務中。

          遠程調用技術解釋:Google ProtocolBuffer跨語言序列化

          ProtocolBuffer是google開發的跨語言的高效二進制序列化方式,其序列化性能和thrift比較類似。事實上thrift最初就是ProtocolBuffer的仿制品。但它和thrift最大的不同是他沒有自帶的RPC實現(因為google沒有將RPC部分開源,但有大量第三方實現)。

          由于不和RPC方式耦合,反而使得ProtocolBuffer能被方便的集成進大量已有的系統和框架中。在國內它也被百度、淘寶等廣泛的應用在Open API中,和HTTP搭配作為一種高效的跨平臺跨組織的集成方式。

          服務設計原則2:消除冗余數據

          同樣由于service的遠程調用開銷很高,所以在它的輸入參數和返回結果中,還要盡量避免攜帶當前業務用例不需要的冗余的字段,來減少序列化和傳輸的開銷。同時,去掉冗余字段也可以簡化接口,避免給外部用戶帶來不必要的業務困惑。

          比如article service中有個返回article list的方法

          List<Article> getArticles(...)

          如果業務需求僅僅是要列出文章的標題,那么在返回的article中就要避免攜帶它的contents等等字段。

          這里經典解決方案就是引入OO中常用的Data Transfer Object (DTO)模式,專門針對特定service的用例來定制要傳輸的數據字段。這里就是添加一個AriticleSummary的額外數據傳輸對象:

          List<ArticleSummary> getArticleSummaries(...)

          額外的DTO確實是個麻煩,而一般OO程序通常則可直接返回自己的包含冗余的業務模型。

          服務設計原則3:粗粒度契約

          同樣由于遠程調用開銷高,同時service的外部使用者對特定業務流程的了解也比不上組織內部的人,所以service的契約(接口)通常需要是粗粒度的,其中的一個操作就可能對應到一個完整的業務用例或者業務流程,這樣既能減少遠程調用次數,同時又降低學習成本和耦合度。

          而OO接口通??梢允欠浅<毩6鹊?,提供最好的靈活性和重用性。

          例如,article service支持批量刪除文章,OO接口中可以提供

          deleteArticle(long id)

          供用戶自己做循環調用(暫不考慮后端SQL之類優化),但SO接口中,則最好提供

          deleteArticles(Set<Long> ids)

          供客戶端調用,將可能的N次遠程調用減少為一次。

          例如,下訂單的用例,要有一系列操作

          addItem -> addTax -> calculateTotalPrice -> placeOrder 

          OO中我們完全可以讓用戶自己來靈活選擇,分別調用這些細粒度的可復用的方法。但在SO中,我們需要將他們封裝到一個粗粒度的方法供用戶做一次性遠程調用,同時也隱藏了內部業務的很多復雜性。另外,客戶端也從依賴4個方法變成了依賴1個方法,從而大大降低了程序耦合度。

          順便值得一提的是,如果上面訂單用例中每個操作本身也是遠程的service(通常在內網之中),這種粗粒度封裝就變成了經典的service composition(服務組合)甚至service orchestration(服務編排)了。這種情況下粗粒度service同樣可能提高了性能,因為對外網客戶來說,多次跨網的遠程調用變成了一次跨網調用 + 多次內網調用。

          對這種粗粒度service封裝和組合,經典解決方案就是引入OO中常用的Facade模式,將原來的對象屏蔽到專門的“外觀”接口之后。同時,這里也很可能要求我們引入新的service參數/返回值的數據結構來組合原來多個操作的對象模型,這就同樣用到前述的DTO模式。

          一個簡單Facade示例(FooService和BarService是兩個假想的本地OO service,façade將它們的結果值組合返回):

          class FooBarFacadeImpl implements FooBarFacade {     private FooService fooService;     private BarService barService;      public FooBarDto getFooBar() {         FooBarDto fb = new FooBarDto();         fb.setFoo(fooService.getFoo());         fb.setBar(barService.getBar());         return fb;     } }   

          當然,有的時候也可以不用facade和DTO,而在是FooService和BarService之外添加另一個本地service和domain model,這要和具體業務場景有關。

          服務設計原則4:通用契約

          由于service不假設用戶的范圍,所以一般要支持不同語言和平臺的客戶端。但各種語言和平臺在功能豐富性上有很大差異,這就決定了服務契約必須取常見語言、平臺以及序列化方式的最大公約數,才能保證service廣泛兼容性。由此,服務契約中不能有某些語言才具備的高級特性,參數和返回值也必須是被廣泛支持的較簡單的數據類型(比如不能有對象循環引用)。

          如果原有的OO接口不能滿足以上要求,則在此我們同樣需要上述的Facade和DTO,將OO接口轉換為通用的SO契約。

          例如原有對象模型

          class Foo {    private Pattern regex; }

          Pattern是Java特有的預編譯好的,可序列化的正則表達式(可提高性能),但在沒有特定框架支持下,可能不好直接被其他語言識別,所以可添加DTO:

          class FooDto {    private String regex; }

          服務設計原則5:隔離變化

          雖然OO和SO都追求低耦合,但SO由于使用者范圍極廣,就要求了更高程度的低耦合性。

          比如前述的article service,OO中可以直接返回article對象,而這個article對象在OO程序內部可能做為核心的建模的domain model,甚至作為O/R mapping等等。而在SO如果還直接返回這個article,即使沒有前面所說的冗余字段,復雜類型等問題,也可能讓外部用戶與內部系統的核心對象模型,甚至O/R mapping機制,數據表結構等等產生了一定關聯度,這樣一來,內部的重構經常都會可能影響到外部的用戶。

          所以,這里再次對Facade和DTO產生了需求,用它們作為中介者和緩沖帶,隔離內外系統,把內部系統變化對外部的沖擊減少到最小程度。

          服務設計原則6:契約先行

          Service是往往涉及不同組織之間的合作,而按照正常邏輯,兩個組織之間合作的首要任務,就是先簽訂明確的契約,詳細規定雙方合作的內容,合作的形式等等,這樣才能對雙方形成強有力的約束和保障,同時大家的工作也能夠并行不悖,不用相互等待。因此SOA中,最佳的實踐方式也是契約先行,即先做契約的設計,可以有商務,管理和技術等不同方面的人員共同參與,并定義出相應的WSDL或者IDL,然后在開發的時候再通過工具自動生成目標語言的對應代碼。

          對于WSDL來說,做契約先行的門檻略高,如果沒有好的XML工具很難手工編制。但對于Thrift IDL或者ProtocolBuffer等來說,由于它們和普通編程語言類似,所以契約設計相對是比較容易的。另外,對于簡單的HTTP + JSON來說(假設不補充使用其他描述語言),由于JSON沒有標準的schema,所以是沒法設計具有強約束力的契約的,只能用另外的文檔做描述或者用JSON做輸入輸出的舉例。

          但是,契約先行,然后再生成服務提供端的代碼,畢竟給service開發工作帶來了較大的不便,特別是修改契約的時候導致代碼需要重寫。因此,這里同樣可能需要引入Facade和DTO,即用契約產生的都是Facade和DTO代碼,它們負責將請求適配和轉發到其他內部程序,而內部程序則可以保持自己的主導性和穩定性。

          另外,契約先行可能會給前面提到的多遠程調用支持帶來一些麻煩。

          當然契約先行也許并不是能被廣泛接受的實踐方式,就像敏捷開發中“測試先行”(也就是測試驅動開發)通常都是最佳實踐,但真正施行的團隊卻非常之少,這方面還需要不斷摸索和總結。但我們至少可以認為Echo中Java2WSDL并不被認為是SOA的最佳實踐。

          服務設計原則7:穩定和兼容的契約

          由于用戶范圍的廣泛性,所以SO的服務契約和Java標準API類似,在公開發布之后就要保證相當的穩定性,不能隨便被重構,即使升級也要考慮盡可能的向下兼容性。同時,如果用契約先行的方式,以后頻繁更改契約也導致開發人員要不斷重做契約到目標語言映射,非常麻煩。

          這就是說SO對契約的質量要求可能大大高于一般的OO接口,理想的情況下,甚至可能需要專人(包括商務人員)來設計和評估SO契約(不管是否用契約先行的方式),而把內部的程序實現交給不同的人,而兩者用Facade和DTO做橋梁。

          服務設計原則8:契約包裝

          前述原則基本都是針對service提供端來講的,而對service消費端而言,通過契約生成對應的客戶端代碼,經常就可以直接使用了。當然,如果契約本身就是Java接口之類(比如在Dubbo,Spring Remoting等框架中),可以略過代碼生成的步驟。

          但是,service的返回值(DTO)和service接口(Facade),可能被消費端的程序到處引用到。

          這樣消費端程序就較強的耦合在服務契約上了,如果服務契約不是消費端定義的,消費端就等于把自己程序的部分主導權完全讓渡給了別人。

          一旦契約做更改,或者消費端要選擇完全不同的service提供方(有不同的契約),甚至改由本地程序自己來實現相關功能,修改工作量就可能非常大了。

          另外,通過契約生成的客戶端代碼,經常和特定傳輸方式是相關的(比如webservices stub),這樣給切換遠程調用方式也會帶來障礙。

          因此,就像在通常應用中,我們要包裝數據訪問邏輯(OO中的DAO或者Repository模式),或者包裝基礎服務訪問邏輯(OO中的Gateway模式)一樣,在較理想的SOA設計中,我們也可以考慮包裝遠程service訪問邏輯,由于沒有恰當的名稱,暫時稱之為Delegate Service模式,它由消費端自己主導定義接口和參數類型,并將調用轉發給真正的service客戶端生成代碼,從而對它的使用者完全屏蔽了服務契約,這些使用者甚至不知道這個服務到底是遠程提供的的還是本地提供的。

          此外,即使我們在消費端是采用某些手工調用機制(如直接構建和解析json等內容,直接收發JMS消息等等),我們同樣可以用delegate service來包裝相應的邏輯。

          delegate service示例1:

          // ArticlesService是消費端自定義的接口 class ArticleServiceDelegate implements ArticlesService {     // 假設是某種自動生成的service客戶端stub類     private ArticleFacadeStub stub;      public void deleteArticles(List<Long> ids) {         stub.deleteArticles(ids);     } }   

          delegate service示例2:

          // ArticlesService是消費端自定義的接口 class ArticleServiceDelegate implements ArticlesService {      public void deleteArticles(List<Long> ids) {         // 用JMS和FastJson手工調用遠程service         messageClient.sendMessage(queue, JSON.toJSONString(ids));     } }   

          從面向對象到面向服務,再從面向服務到面向對象

          總結上面的幾個原則,雖然只是談及有限的幾個方面,但大致也可看出OO和SO在實際的設計開發中還是有不少顯著的不同之處,而且我們沒有打算用SO的原則來取代過去的OO設計,而是引入額外的層次、對象和OO設計模式,來補充傳統的OO設計。

          其實就是形成了這種調用流程:

          • service提供端:OO程序 <- SOA層(Facade和DTO)<- 遠程消費端

          • service消費端:OO程序 -> Delegate Service -> SOA層(Facade和DTO 或者 其他動態調用機制)-> 遠程提供端

          Facade、DTO和Delegate Service負責做OO到SO和SO到OO的中間轉換。

          現在,可以回答Echo示例中的問題:通過“透明的”配置方式,將OO程序發布為遠程Service,雖然可能較好的完成了從本地對象到遠程對象的跨越,但通常并不能較好的完成OO到SO的真正跨越。

          同時,透明配置方式也通常無法直接幫助遺留應用(如ERP等)轉向SOA。

          當然,在較為簡單和使用范圍確定很有限應用(比如傳統和局部的RPC)中,透明式遠程service發布會帶來極大的便利。

          另外,上面對SO的所有討論都集中在RPC的方式,其實SO中也用message的方式做集成,它也是個大話題,暫時不在此詳論了。

          為什么不能放棄面向對象?

          SO是有它的特定場景的,比如遠程的,范圍不定的客戶端。所以它的那些設計原則并不能被借用來指導一般性的程序開發,比如很多OO程序和SO原則完全相反,經常都要提供細粒度接口和復雜參數類型以追求使用的使用靈活性和功能的強大性。

          就具體架構而言,我認為SOA層應該是一個很薄的層次(thin layer),將OO應用或者其他遺留性應用加以包裝和適配以幫助它們面向服務。其實在通常的web開發中,我們也是用一個薄的展現層(或者叫Web UI層之類)來包裝OO應用,以幫助它們面向瀏覽器用戶。因此,Façade、DTO等不會取代OO應用中核心的Domain Model、Service等等 (這里的service是OO中service,未必是SO的)。

          綜合起來,形成類似下面的體系結構:

          理想和現實

          需要特別指出的是,上面提到的諸多SO設計原則是在追求一種相對理想化的設計,以達到架構的優雅性,高效性,可重用性,可維護性,可擴展性等等。

          而在現實中任何理論和原則都可能是需要作出適當妥協的,因為現實是千差萬別的,其情況遠比理論復雜,很難存在放之四海而皆準的真理。

          而且很多方面似乎本來也沒有必要追求完美和極致,比如如果有足夠能力擴充硬件基礎設施,就可以考慮傳輸一些冗余數據,選擇最簡單傳輸方式,并多來幾次遠程調用等等,以減輕設計開發的工作量。

          那么理想化的原則就沒有意義了嗎?比如領域驅動設計(Domain-Driven Design)被廣泛認為是最理想的OO設計方式,但極少有項目能完全采用它;測試驅動開發也被認為是最佳的敏捷開發方式,但同樣極少有團隊能徹底采用它。但是,恐怕沒有多少人在了解它們之后會否認它們巨大的意義。

          理想化的原則可以更好的幫助人們理解某類問題的本質,并做為好的出發點或者標桿,幫助那些可以靈活運用,恰當取舍的人取得更大的成績,應付關鍵的挑戰。這正如孔子說的“取乎其上,得乎其中;取乎其中,得乎其下;取乎其下,則無所得矣”。

          另外,值得一提的是,SOA從它的理念本身來說,就帶有一些的理想主義的傾向,比如向“全世界”開放,不限定客戶端等等。如果真愿意按SOA的路徑走,即使你是個土豪,偷個懶比浪費網絡帶寬重要,但說不定你的很多用戶是土鱉公司,浪費幾倍的帶寬就大大的影響他們的利潤率。

          延伸討論:SOA和敏捷軟件開發矛盾嗎?

          SOA的服務契約要求相當的穩定性,一旦公開發布(或者雙方合同商定)就不應該有經常的變更,它需要對很多方面有極高的預判。而敏捷軟件開發則是擁抱變化,持續重構的。軟件設計大師Martin Fowler把它們歸結為計劃式設計和演進式設計的不同。

          計劃理論(或者叫建構理論)和演進理論是近代哲學的兩股思潮,影響深遠,派生出了比如計劃經濟和市場經濟,社會主義和自由主義等等各種理論。

          但是,計劃式設計和演進式設計并不絕對矛盾,就像計劃經濟和市場經濟也不絕對矛盾,非此即彼,這方面需要在實踐中不斷摸索。前面我們討論的設計原則和架構體系,就是將SOA層和OO應用相對隔離,分而治之,在SOA層需要更多計劃式設計,而OO應用可以相對獨立的演進,從而在一定程度緩解SOA和敏捷開發的矛盾。

          延伸討論:SOA和REST是一回事嗎?

          從最本質的意義上講,REST(Representational State Transfer)實際是一種面向資源架構(ROA),和面向服務架構(SOA)是有根本區別的。

          例如,REST是基于HTTP協議,對特定資源做增(HTTP POST)、刪(HTTP DELETE)、改(HTTP PUT)、查(HTTP GET)等操作,類似于SQL中針對數據表的INSERT、DELETE、UPDATE、SELECT操作,故REST是以資源(資源可以類比為數據)為中心的。而SOA中的service通常不包含這種針對資源(數據)的細粒度操作,而是面向業務用例、業務流程的粗粒度操作,所以SOA是以業務邏輯為中心的。

          但是在實際使用中,隨著許多REST基本原則被不斷突破,REST的概念被大大的泛化了,它往往成為很多基于HTTP的輕量級遠程調用的代名詞(例如前面提到過的HTTP + JSON)。比如,即使是著名的Twitter REST API也違反不少原始REST的基本原則。

          在這個泛化的意義上講,REST也可以說是有助于實現SOA的一種輕量級遠程調用方式。

          SOA架構的進化

          前面討論的SOA的所有問題,基本都集中在service本身的設計開發。但SOA要真正發揮最大作用,還需要不斷演進成更大的架構(也就是從微觀SOA過渡到宏觀SOA),在此略作說明:

          • 第一個層次是service架構:開發各種獨立的service并滿足前面的一些設計原則,我們前面基本都集中在討論這種架構。這些獨立的service有點類似于小孩的積木。

          • 第二個層次是service composition(組合)架構:獨立的service通過不同組合來構成新的業務或者新的service。在理想情況下,可以用一種類似小孩搭積木的方式,充分發揮想象力,將獨立的積木(service)靈活的拼裝組合成新的形態,還能夠自由的替換其中的某個構件。這體現出SOA高度便捷的重用性,大大提高企業的業務敏捷度。

          • 第三個層次是service inventory(清單)架構:通過標準化企業服務清單(或者叫注冊中心)統一的組織和規劃service的復用和組合。當積木越來越多了,如果還滿地亂放而沒有良好的歸類整理,顯然就玩不轉了。

          • 第四個層次是service-oriented enterprise架構……

          總結

          至此,我們只是簡要的探討了微觀層面的SOA,特別是一些基本設計原則及其實踐方式,以期能夠略微展示SOA在實踐中的本質,以有助于SOA更好的落地,進入日常操作層面。

          最后,打個比方:SOA不分貴賤(不分語言、平臺、組織),不遠萬里(通過遠程調用)的提供服務(service),這要求的就是一種全心全意為人民服務的精神……

          作者簡介

          沈理,當當網架構師和技術委員會成員,主要負責當當網的SOA實施(即服務化)以及分布式服務框架的開發。以前也有在BEA、Oracle、Redhat等外企的長期工作經歷,從事過多個不同SOA相關框架和容器的開發。他的郵箱:shenli@dangdang.com


          感謝馬國耀對本文的審校。

          給InfoQ中文站投稿或者參與內容翻譯工作,請郵件至editors@cn.infoq.com。也歡迎大家通過新浪微博(@InfoQ)或者騰訊微博(@InfoQ)關注我們,并與我們的編輯和其他讀者朋友交流。

          posted @ 2014-10-16 14:06 小馬歌 閱讀(238) | 評論 (0)編輯 收藏
           
          from:http://www.infoq.com/cn/articles/micro-soa-1

          大量互聯網公司都在擁抱SOA和服務化,但業界對SOA的很多討論都比較偏向高大上。本文試圖從稍微不同的角度,以相對接地氣的方式來討論SOA,集中討論SOA在微觀實踐層面中的緣起、本質和具體操作方式,另外也用相當篇幅介紹了當今互聯網行業中各種流行的遠程調用技術等等,比較適合從事實際工作的架構師和程序員來閱讀。

          為了方便閱讀,本話題將分為兩篇展現。本文是上篇,著眼于微觀SOA的定義,并簡單分析其核心原則。

          亞馬遜CEO杰夫•貝佐斯:鮮為人知的SOA大師

          由于SOA有相當的難度和門檻,不妨先從一個小故事說起,從中可以管窺一點SOA的大意和作用。

          按照亞馬遜前著名員工Steve Yegge著名的“酒后吐槽”,2002年左右,CEO貝佐斯就在亞馬遜強制推行了以下六個原則(摘自酷殼):

          1. 所有團隊的程序模塊都要以通過Service Interface 方式將其數據與功能開放出來。
          2. 團隊間的程序模塊的信息通信,都要通過這些接口。
          3. 除此之外沒有其它的通信方式。其他形式一概不允許:不能使用直接鏈結程序、不能直接讀取其他團隊的數據庫、不能使用共享內存模式、不能使用別人模塊的后門、等等,等等,唯一允許的通信方式只能是能過調用 Service Interface。
          4. 任何技術都可以使用。比如:HTTP、Corba、Pubsub、自定義的網絡協議、等等,都可以,貝佐斯不管這些。
          5. 所有的Service Interface,毫無例外,都必須從骨子里到表面上設計成能對外界開放的。也就是說,團隊必須做好規劃與設計,以便未來把接口開放給全世界的程序員,沒有任何例外。
          6. 不這樣的做的人會被炒魷魚。

          據說,亞馬遜網站展示一個產品明細的頁面,可能要調用200-300個Service,以便生成高度個性化的內容。

          Steve還提到:

          Amazon已經把文化轉變成了“一切以Service第一”為系統架構的公司,今天,這已經成為他們進行所有設計時的基礎,包括那些絕不會被外界所知的僅在內部使用的功能。

          那時,如果沒有被解雇的的恐懼他們一定不會去做。我是說,他們今天仍然怕被解雇,因為這基本上是那兒每天的生活,為那恐怖的海盜頭子貝佐斯工作。不過,他們這么做的確是因為他們已經相信Service這就是正確的方向。他們對于SOA的優點和缺點沒有疑問,某些缺點還很大,也不疑問。但總的來說,這是正確的,因為,SOA驅動出來的設計會產生出平臺(Platform)。

          今天,我們都知道亞馬遜從世界上最大圖書賣場進化為了世界上最成功的云平臺……

          貝佐斯的六原則展示出高度的遠見和超強的信念,即使放到十幾年后的今天,依然覺得振聾發聵……想起一句老話:“不謀萬世者,不足以謀一時;不謀全局者,不足以謀一隅。”

          當然,像貝佐斯這種將神性與魔性集于一身的專橫人物,既可能創造劃時代的進步,也可能制造前所未有的災難。

          SOA漫談:宏觀與微觀

          SOA即面向服務架構,是一個特別大的話題。

          為了方便討論,我在此先草率的將SOA分為兩個層面(大概模仿宏觀和微觀經濟學,但這里的劃分沒有絕對界限):

          • 宏觀SOA:面向高層次的部門級別、公司級別甚至行業級別;涉及商業、管理、技術等方面的綜合的、全局的考慮;架構體系上包括服務治理(governance,如服務注冊,服務監控),服務編排(orchestration,如BPM,ESB),服務協同(choreography,更多面向跨企業集成)等等。我認為SOA本身最主要是面向宏觀層面的架構,其帶來益處也最能在宏觀高層次上體現出來,同時大部分SOA的業界討論也集中在這方面。
          • 微觀SOA:面向有限的、局部的團隊和個人;涉及獨立的、具體的服務在業務、架構、開發上的考慮。

          很多業界專家都認為SOA概念過于抽象,不接地氣,我認為主要是宏觀SOA涉及面太廣,經常需要做通盤考慮,而其中很多方面距離一般人又比較遠。而在微觀層面的SOA更容易達到濤哥過去提出的“三貼近”:貼近實際、貼近生活、貼近群眾。

          同時,宏觀SOA要取得成功,通常的前提也是SOA在微觀層面的落地與落實,正如宏觀經濟學一般要有堅實的微觀基礎(比如大名鼎鼎的凱恩斯主義曾廣受詬病的一點就是缺乏微觀基礎)

          因此,我們著眼于SOA落地的目的,著重來分析微觀SOA,也算是對業界主流探討的一個小小的補充。

          SOA定義

          按照英文維基百科定義:SOA是一種“軟件”和“軟件架構”的設計模式(或者叫設計原則)。它是基于相互獨立的軟件片段要將自身的功能通過“服務”提供給其他應用。

          什么是“服務”?按照OASIS的定義:Service是一種按照既定“接口“來訪問一個或多個軟件功能的機制(另外這種訪問要符合“服務描述”中策略和限制)

          Service示例(代碼通常以java示例)

          public interface Echo {     String echo(String text); }  public class EchoImpl implements Echo {     public String echo(String text) {         return text;     } }

          可能每個開發人員每天都在寫類似的面向對象的Service,難道這就是在實施SOA嗎?

          SOA設計原則

          既然SOA是設計原則(模式),那么它包含哪些內容呢?事實上,這方面并沒有最標準的答案,多數是遵從著名SOA專家Thomas Erl的歸納:

          標準化的服務契約 Standardized service contract 服務的松耦合 Service loose coupling 服務的抽象 Service abstraction 服務的可重用性 Service reusability 服務的自治性 Service autonomy 服務的無狀態性 Service statelessness 服務的可發現性 Service discoverability 服務的可組合性 Service composability ....

          這些原則總的來說要達到的目的是:提高軟件的重用性,減少開發和維護的成本,最終增加一個公司業務的敏捷度。

          但是,業界著名專家如Don Box,David Orchard等人對SOA又有各自不同的總結和側重。

          SOA不但沒有絕對統一的原則,而且很多原則本身的內容也具備相當模糊性和寬泛性:例如,所謂松耦合原則需要松散到什么程度才算是符合標準的呢?這就好比一個人要帥到什么程度才算是帥哥呢?一棟樓要高到多少米才算是高樓呢?可能不同人心中都有自己的一桿秤……部分由于這些理論上的不確定因素,不同的人理解或者實施的SOA事實上也可能有比較大的差別。

          淺析松耦合原則

          SOA原則比較多,真正的理解往往需要逐步的積累和體會,所以在此不詳細展開。這里僅以服務的松耦合為例,從不同維度來簡單剖析一下這個原則,以說明SOA原則內涵的豐富性:

          • 實現的松耦合:這是最基本的松耦合,即服務消費端不需要依賴服務契約的某個特定實現,這樣服務提供端的內部變更就不會影響到消費端,而且消費端未來還可以自由切換到該契約的其他提供方。

          • 時間的松耦合:典型就是異步消息隊列系統,由于有中介者(broker),所以生產者和消費者不必在同一時間都保持可用性以及相同的吞吐量,而且生產者也不需要馬上等到回復。

          • 位置的松耦合:典型就是服務注冊中心和企業服務總線(ESB),消費端完全不需要直接知道提供端的具體位置,而都通過注冊中心來查找或者服務總線來路由。

          • 版本的松耦合:消費端不需要依賴服務契約的某個特定版本來工作,這就要求服務的契約在升級時要盡可能的提供向下兼容性。

          SOA與傳統軟件設計

          我們可以認為:SOA ≈ 模塊化開發 + 分布式計算

          將兩者傳統上的最佳實踐結合在一起,基本上可以推導出SOA的多數設計原則。SOA從軟件設計(暫不考慮業務架構之類)上來講,自身的新東西其實不算很多。

          SOA原則的應用

          基于SOA的原則,也許我們很難說什么應用是絕對符合SOA的,但是卻能剔除明顯不符合SOA的應用。

          用上述標準化契約,松耦合和可重用這幾個原則來嘗試分析一下上面Echo示例:

          • Echo的服務契約是用Java接口定義,而不是一種與平臺和語言無關的標準化協議,如WSDL,CORBA IDL。當然可以抬杠,Java也是行業標準,甚至全國牙防組一致認定的東西也是行業標準。

          • Java接口大大加重了與Service客戶端的耦合度,即要求客戶端必須也是Java,或者JVM上的動態語言(如Groovy、Jython)等等……

          • 同時,Echo是一個Java的本地接口,就要求調用者最好在同一個JVM進程之內……

          • Echo的業務邏輯雖然簡單獨立,但以上技術方面的局限就導致它無法以后在其他場合被輕易重用,比如分布式環境,異構平臺等等。

          因此,我們可以認為Echo并不太符合SOA的基本設計原則。

          透明化的轉向SOA?

          修改一下上面的Echo,添加Java EE的@WebServices注解(annotation)

          @WebServices public class EchoImpl implements Echo {     public String echo(String text) {         return text;     } }

          現在將Echo發布為Java WebServices,并由底層框架自動生成WSDL來作為標準化的服務契約,這樣就能與遠程的各種語言和平臺互操作了,較好的解決了上面提到的松耦合和可重用的問題。按照一般的理解,Echo似乎就成為比較理想的SOA service了。

          但是……即使這個極端簡化的例子,也會引出不少很關鍵的問題,它們決定SOA設計開發的某些難度:

          • 將一個普通的Java對象通過添加注解“透明的”變成WebServices就完成了從面向對象到面向服務的跨越?
          • 通過Java接口生成WSDL服務契約是好的方式嗎?
          • WebServices是最合適遠程訪問技術嗎?

          面向對象和面向服務的對比

          面向對象(OO)和面向服務(SO)在基礎理念上有大量共通之處,比如都盡可能追求抽象、封裝和低耦合。

          但SO相對于OO,又有非常不同的典型應用場景,比如:

          • 多數OO接口(interface)都只被有限的人使用(比如團隊和部門內),而SO接口(或者叫契約)一般來說都不應該對使用者的范圍作出太多的限定和假設(可以是不同部門,不同企業,不同國家)。還記得貝佐斯原則嗎?“團隊必須做好規劃與設計,以便未來把接口開放給全世界的程序員,沒有任何例外”。

          • 多數OO接口都只在進程內被訪問,而SO接口通常都是被遠程調用。

          簡單講,就是SO接口使用范圍比一般OO接口可能廣泛得多。我們用網站打個比方:一個大型網站的web界面就是它整個系統入口點和邊界,可能要面對全世界的訪問者(所以經常會做國際化之類的工作),而系統內部傳統的OO接口和程序則被隱藏在web界面之后,只被內部較小范圍使用。而理想的SO接口和web界面一樣,也是變成系統入口和邊界,可能要對全世界開發者開放,因此SO在設計開發之中與OO相比其實會有很多不同。

          小結

          在前述比較抽象的SOA大原則的基礎上,我們可嘗試推導一些較細化和可操作的原則,在具體實踐中體現SO的獨特之處。請關注本系列文章的下篇!

          作者簡介

          沈理,當當網架構師和技術委員會成員,主要負責當當網的SOA實施(即服務化)以及分布式服務框架的開發。以前也有在BEA、Oracle、Redhat等外企的長期工作經歷,從事過多個不同SOA相關框架和容器的開發。他的郵箱:shenli@dangdang.com


          感謝馬國耀對本文的審校。

          posted @ 2014-10-16 14:05 小馬歌 閱讀(200) | 評論 (0)編輯 收藏
           

          在《直接拿來用!最火的Android開源項目(一)》中,我們詳細地介紹了GitHub上最受歡迎的TOP20 Android開源項目,引起了許多讀者的熱議,作為開發者,你最常用的是哪些開源項目?使用起來是否能讓你得心應手?今天,我們將介紹另外20個Android開源項目,在這些項目中,你又用到了哪些呢?

          21. drag-sort-listview

          DragSortListView(DSLV)是Android ListView的一個擴展,支持拖拽排序和左右滑動刪除功能。重寫了TouchInterceptor(TI)類來提供更加優美的拖拽動畫效果。

           

          DSLV主要特性:

           

          • 完美的拖拽支持;
          • 在拖動時提供更平滑的滾動列表滾動;
          • 支持每個ListItem高度的多樣性
          • 公開startDrag()和stopDrag()方法;
          • 有公開的接口可以自定義拖動的View。

           

          DragSortListView適用于帶有任何優先級的列表:收藏夾、播放列表及清單等,算得上是目前Android開源實現拖動排序操作最完美的方案。

          22. c-geo-opensource

          c:geo是Android設備上一個簡單而又強大的非官方地理尋寶客戶端。與其他類似應用不同的是,c:geo不需要Web瀏覽器,也不需要文件輸出。你可以在毫無準備的情況下,毫無后顧之憂地帶上你的智能手機去進行地理尋寶。當然,你也不需要付錢,因為它是免費的。

          c-geo-opensource包含了c:geo所有開源代碼。

          詳情請參考:c:geo

          23. NineOldAndroids

          自Android 3.0以上的版本,SDK新增了一個android.animation包,里面的類都是跟動畫效果實現相關的,通過Honeycomb API,能夠實現非常復雜的動畫效果。但如果開發者想在3.0以下的版本中也能使用到這套API,那么Nine Old Androids就會是你最好的選擇,該API和Honeycomb API完全一樣,只是改變了你使用com.nineoldandroids.XXX的入口。

          該項目包含兩個工程,一個是Library,即為動畫效果的實現庫,另一個則是Sample,是對如何使用該API的演示。開發者可以直接登陸Google Play下載安裝Nine Old Androids Sample,查看演示。

          詳情請參考:Nine Old Androids

          24. ppsspp

          PPSSPP是由GC/Wii模擬器Dolphin聯合創始人之一Henrik Rydgård開發的一款免費的跨平臺開源模擬器,支持Windows、Linux、Mac、Android、iOS、BlackBerry 10等主流計算機與移動操作系統,可直接工作在x86、x64、ARM等CPU平臺上,以GNU GPLv2許可協議發布,主要使用C++編寫以提高效率和可移植性。

          只要支持OpenGL ES 2.0,PPSSPP就可以在相當低規格的硬件設備上運行,包括基于ARM的手機及平板電腦。

          詳情請參考:PPSSPP

          25. androidquery

          Android-Query(AQuery)是一個輕量級的開發包,用于實現Android上的異步任務和操作UI元素,可讓Android應用開發更簡單、更容易,也更有趣。

          26. droid-fu

          Droid-Fu是一個開源的通用Android應用庫,其主要目的是為了讓Android開發更容易,包含有許多工具類,還有非常易用的Android組件。

          Droid-Fu提供支持的領域包括:

           

          • Android應用的生命周期幫助
          • 支持處理Intents和diagnostics類
          • 后臺任務支持
          • HTTP消息處理
          • 對象、HTTP響應及遠程圖像高速緩存
          • 定制各種Adapter及View

           

          Droid-Fu最大的優勢在于它的應用生命周期幫助類,如果你正在開發一款Android應用,而它的主要任務是運行后臺任務,比如從Web上抓取數據,那么,你一定會使用到Droid-Fu,不過,目前該項目在GitHub上已經停止更新維護。

          詳情請參考:droid-fu

          27. TextSecure

          TextSecure是Whisper Systems團隊開發的一個Android上的加密信息客戶端,旨在增強用戶和企業通信的安全性,其源代碼于2011年被Twitter發布在GitHub開源數據庫中。

          該軟件允許用戶將在Android設備上所有發送和接收的短信內容進行加密,還可以將加密信息發送給另一個TextSecure用戶。

          28. XobotOS

          XobotOS是Xamarin的一個研究項目,用于將Android 4.0從Java/Dalvik移植到C#,并對移植后的性能及內存占用情況進行檢測。

          29. ignition

          在編寫Android應用時,通過提供即用組件和包含許多樣板文件的實用類,ignition可以讓你的Android應用快速起步。ignition涵蓋的區域包括:

           

          • Widget、Adapter、Dialog等UI組件;
          • 允許編寫簡單卻強大的網絡代碼的HTTP Wrapper庫;
          • 加載遠程Web圖像并進行緩存的類;
          • 簡單但有效的緩存框架(將對所有對象樹做出響應的HTTP緩存到內存或硬盤中);
          • Intents、diagnostics等幾個能讓API級別更容易向后兼容的幫助類;
          • 更友好、更強大的AsyncTask實現。

           

          ignition包括三個子項目:

           

          • ignition-core——是一個可以直接編譯到App中的Android庫項目。
          • ignition-support——一個標準的Java庫項目,被部署為一個普通的JAR,包含了大部分實用工具類。開發者可以獨立使用該工程的核心模塊。
          • ignition-location——一個可以直接編譯到應用程序中的Android AspectJ庫項目。能夠讓定位應用在不需要Activity位置更新處理的情況下獲取到最新的位置信息。

           

          詳情請參考:ignition Sample applications

          30. android_page_curl

          android_page_curl是一個在Android上使用OpenGL ES實現類似書本翻頁效果的示例程序。(點擊鏈接查看視頻演示

          31. asmack

          說到aSmack,自然要先提提Smack。Smack API是一個完整的實現了XMPP協議的開源API庫,而aSmack則是Smack在Android上的構建版本,于2013年2月初遷移到GitHub上,該資源庫并不包含太多的代碼,只是一個構建環境。開發者可以利用該API進行基于XMPP協議的即時消息應用程序開發。

          詳情請參考:asmack

          32. AndroidBillingLibrary

          In-app Billing是一項Google Play服務,能夠讓你在應用內進行數字內容銷售,可銷售的數字內容范圍非常廣,包括媒體文件、照片等下載內容,還包括游戲級別、藥劑、增值服務和功能等虛擬內容。Android Billing Library可以實現In-app Billing的所有規范,并提供更高級的類來進行使用。

          Google于2012年底正式發布了v3版Android In-app Billing,但截至目前,GitHub上的Android Billing Library還只能支持到v2版,據悉Google將于2013年初對它進行更新。

          詳情請參考:Google Play In-app Billing

          33. Crouton

          Crouton是Android上的一個可以讓開發者對環境中的Toast進行替換的類,以一個應用程序窗口的方式顯示,而其顯示位置則由開發者自己決定。

          開發者可以直接登陸Google Play下載安裝Crouton Demo,查看應用演示。

          34. cwac-endless

          CommonsWare Android Components(CWAC)是一個開源的Android組件庫,用來解決Android開發中各個方面的常見問題,每個 CWAC組件打包成一個獨立的jar文件,其中就包含cwac-endless。

          cwac-endless提供一個EndlessAdapter,這是一個自動分頁的List,當用戶瀏覽到List最后一行時自動請求新的數據。

          詳情請參考:Commons Ware

          35. DiskLruCache

          在Android應用開發中,為了提高UI的流暢性、響應速度,提供更高的用戶體驗,開發者常常會絞盡腦汁地思考如何實現高效加載圖片,而DiskLruCache實現正是開發者常用的圖片緩存技術之一。Disk LRU Cache,顧名思義,硬件緩存,就是一個在文件系統中使用有限空間進行高速緩存。每個緩存項都有一個字符串鍵和一個固定大小的值。

          點擊鏈接下載該庫項目。

          36. Android-SlideExpandableListView

          如果你對Android提供的Android ExpandableListView并不滿意,一心想要實現諸如Spotify應用那般的效果,那么SlideExpandableListView絕對是你最好的選擇。該庫允許你自定義每個列表項目中的ListView,一旦用戶點擊某個按鈕,即可實現該列表項目區域滑動。

          37. gauges-android

          Gaug.es for Android是由gaug.es推出的一款在Android設備上對網站流量數據進行實時統計的應用。gauges-android包含了該應用的源代碼,開發者可以直接登陸Google Play下載安裝該應用。

          38. acra

          ACRA是一個能夠讓Android應用自動將崩潰報告以谷歌文檔電子表的形式進行發送的庫,旨在當應用發生崩潰或出現錯誤行為時,開發者可以獲取到相關數據。

          39. roboguice

          RoboGuice是Android平臺上基于Google Guice開發的一個庫,可以大大簡化Android應用開發的代碼及一些繁瑣重復的代碼。給Android帶來了簡單、易用的依賴注入,如果你使用過Spring或Guice的話,你就會知道這種編程方式是多么的便捷。

          40. otto

          Otto是由Square發布的一個著重于Android支持的基于Guava的強大的事件總線,在對應用程序不同部分進行解耦之后,仍然允許它們進行有效的溝通。

          詳情請參考:Otto

           

          轉自:http://www.csdn.net/article/2013-05-06/2815145-Android-open-source-projects-two

          分類: android
          posted @ 2014-09-26 17:15 小馬歌 閱讀(245) | 評論 (0)編輯 收藏
           
               摘要: GitHub在中國的火爆程度無需多言,越來越多的開源項目遷移到GitHub平臺上。更何況,基于不要重復造輪子的原則,了解當下比較流行的Android與iOS開源項目很是必要。利用這些項目,有時能夠讓你達到事半功倍的效果。為此,CSDN特整理了在GitHub平臺上最受歡迎的Android及iOS開源項目,以饗開發者。下面,就讓我們一起來看看,在GitHub平臺上,究竟有哪些Android開源項目最火...  閱讀全文
          posted @ 2014-09-26 17:14 小馬歌 閱讀(218) | 評論 (0)編輯 收藏
           
          mysql高可用方案MHA介紹
           
          概述
           
          MHA是一位日本MySQL大牛用Perl寫的一套MySQL故障切換方案,來保證數據庫系統的高可用.在宕機的時間內(通常10—30秒內),完成故障切換,部署MHA,可避免主從一致性問題,節約購買新服務器的費用,不影響服務器性能,易安裝,不改變現有部署。
           
             還支持在線切換,從當前運行master切換到一個新的master上面,只需要很短的時間(0.5-2秒內),此時僅僅阻塞寫操作,并不影響讀操作,便于主機硬件維護。
           
          在有高可用,數據一致性要求的系統上,MHA 提供了有用的功能,幾乎無間斷的滿足維護需要。
           
           優點
           
          1        master自動監控和故障轉移
           
            在當前已存在的主從復制環境中,MHA可以監控master主機故障,并且故障自動轉移。
           
          即使有一些slave沒有接受新的relay log events,MHA也會從最新的slave自動識別差異的relay log events,并apply差異的event到其他slaves。因此所有的slave都是一致的。MHA秒級別故障轉移(9-12秒監測到主機故障,任選7秒鐘關閉電源主機避免腦裂,接下來apply差異relay logs,注冊到新的master,通常需要時間10-30秒即total downtime)。另外,在配置文件里可以配置一個slave優先成為master。因為MHA修復了slave之間的一致性,dba就不用去處理一致性問題。
           
               當遷移新的master之后,并行恢復其他slave。即使有成千上萬的slave,也不會影響恢復master時間,slave也很快完成。
           
                DeNA公司在150+主從環境中用MHA。當其中一個master崩潰,MHA4秒完成故障轉移,這是主動/被動集群解決方案無法完成的。
           
          2        互動(手動)master故障轉移
           
           MHA可以用來只做故障轉移,而不監測master,MHA只作為故障轉移的交互。
           
          3        非交互式故障轉移
           
           非交互式的故障轉移也提供(不監控master,自動故障轉移)。這個特性很有用,特別是你已經安裝了其他軟件監控master。比如,用Pacemaker(Heartbeat)監測master故障和vip接管,用MHA故障轉移和slave提升。
           
          4        在線切換master到不同主機
           
           在很多情況下,有必要將master轉移到其他主機上(如替換raid控制器,提升master機器硬件等等)。這并不是master崩潰,但是計劃維護必須去做。計劃維護導致downtime,必須盡可能快的恢復??焖俚膍aster切換和優雅的阻塞寫操作是必需的,MHA提供了這種方式。優雅的master切換, 0.5-2秒內阻塞寫操作。在很多情況下0.5-2秒的downtime是可以接受的,并且即使不在計劃維護窗口。這意味著當需要更換更快機器,升級高版本時,dba可以很容易采取動作。
           
          5        master crash不會導致主從數據不一致性
           
              當master crash后,MHA自動識別slave間relay logevents的不同,然后應用與不同的slave,最終所有slave都同步。結合通過半同步一起使用,幾乎沒有任何數據丟失。
           
          其他高可用方案
           
          6        MHA部署不影響當前環境設置
           
          MHA最重要的一個設計理念就是盡可能使用簡單。使用與5.0+以上主從環境,其他HA方案需要改變mysql部署設置,MHA不會讓dba做這些部署配置,同步和半同步環境都可以用。啟動/停止/升級/降級/安裝/卸載 MHA都不用改變mysql主從(如啟動/停止)。
           
          當你需要升級MHA到新版本時,不需要停止mysql,僅僅更新HMA版本,然后重新啟動MHAmanger即可。
           
             MHA 支持包含5.0/5/1/5.5(應該也支持5.6,翻譯文檔時MHA開發者沒更新對于5.6版本)。有些HA方案要求特定的mysql版本(如mysqlcluster,mysql with global transaction id 等),而且你可能不想僅僅為了MasterHA而遷移應用。很多情況下,公司已經部署了許多傳統的mysql應用,開發或dba不想花太多時間遷移到不同的存儲引擎或新的特性(newer bleeding edge distributions 不知道這個是否該這么翻譯)。
           
          7        不增加服務器費用
           
          MHA 包含MHA Manager和MHA node。MHA node運行在每臺mysql服務器上,Manager可以單獨部署一臺機器,監控100+以上master,總服務器數量不會有太大增加。需要注意的是Manager也可以運行在slaves中的一臺機器上。
           
          8        性能無影響
           
          當監控master,MHA只是幾秒鐘(默認3秒)發送ping包,不發送大的查詢。主從復制性能不受影響
           
          9        適用任何存儲引擎
           
          Mysql不僅僅適用于事務安全的innodb引擎,在主從中適用的引擎,MHA都可以適用。即使用遺留環境的mysiam引擎,不進行遷移,也可以用MHA。
           
           
           
           與其他HA方案比較
           
          Doing everything manually
          Mysql replication 是同步或半同步。當master崩潰時,很有可能一些slave還沒有接受最新的relay log events,這意味著每一個slave都相互處在不同的狀態。人為修復一致性問題顯得不再平凡。沒有一致性問題,主從也可能不會啟動(如duplicate key error)?;ㄙM1個多小時重新啟動主從復制顯得不同尋常。
           
           
           
          Single master and single slave
          在單一主從情況下,一些slave 落后與其他slave的情況將不會發生。其中一個master崩潰,可以輕松的讓應用轉移到一個新的master上面,提供對外服務,故障遷移很簡單。
           
           
           
          Master, one candidate master, and multiple slaves雙主多從
          雙主多從的架構也很常見。主master掛掉,備用master將接替主master提供服務。某些情況配置為多主架構。
           
           
           
          M(RW)-----M2(R)                      M(RW), promoted from M2
           
                 |                                          |
           
            +----+----+          --(master crash)-->   +-x--+--x-+
           
           S(R)     S2(R)                             S(?)      S(?)
           
                                                    (Fromwhich position should S restart replication?)
           
          但是這并不作為master故障轉移方案。當前master掛掉,剩余slave不一定接受全部relay log events,修復數據一致性還是問題。
           
           
           
          這種架構使用廣泛,但是不是所有人都能深刻理解上述問題。當前master掛掉,slave變得不統一或者slave不能從新的master復制數據。
           
          也許雙master,其中一個master只讀,每個master都至少有一個slave也許可能解決問題。
           
                   M(RW)--M2(R)
                    |      |
                  S(R)   S2(R)
           
           
          Pacemaker + DRBD
          Pecemaker(Heartbeat)+DRBD+Mysql是一個通用方案。但是這個方案也有以下問題
           
          1 費用問題,特別是跑大量主從環境。Pecemaker+DRBD是主動/被動的解決方案,因此需要一臺被動服務器對外不提供任何應用服務。基本的需要四臺mysql服務器,one active master,one passive master,two slaves。
           
          2 宕機時間(downtime)。Pacemaker+DRBD是主備集群,主master掛掉,備用master啟用。這可能花費長的時間,特別是沒有用innodb plugin。即使用innodb plugin,花費幾分鐘開始在備用master上接受連接也不尋常。另外,因為備用master上數據/文件緩存是空的,恢復時間,熱身(填充數據到data buffer pool)花費不可忽視的時間。實踐中,需要一臺或更多slave提供足夠的讀服務。在熱身時間內,空緩存導致寫性能降低
           
          3 寫問題下降或一致性問題。為了讓主動/被動集群真正的工作,每次提交(commit)后,必須刷新事務日志(binary log和innodb log),也就是必須設置innodb-flush-log-at-trx-commit=1,sync-binlog=1。設置sync-binlog=1會降低寫性能,因為fsync()函數被序列化(sync-binlog=1,group commit失效)。大部分案例中,不設置sync-binlog=1.如果沒有設置sync-binlog=1,活動master crash,新的master(先前被動服務器)可能會丟失一些已經發送到slave的binary log events。假如 master 掛掉,slave A接受到mysqld-bin.000123,位置1500。binlog data刷新到硬盤的位置在1000,那么新的master數據也只能mysqld-bin.000123的1000處,然后在啟動時創建一個新的binary log mysqld-bin.000124。如果發生這種情況,slave A不能繼續復制,因為新的master 沒有mysqld-bin.000123位置1500.
           
           4 復雜。對多數人來說,安裝/初始化pacemake和DRBD不是容易的事情。相對于其他案例,初始化DRBD需要重新創建系統分區也不容易。要求dba在DRBD和linux內核層有足夠的技能。如果dba執行了一個錯誤命令(如執行drbdadm–overwrite-data-of-peer primary 在被動節點),那么將會損壞活動的數據。重要的是另外一旦硬盤io層出現問題,多數dba處理這種問題不是容易的。
           
          MySQL Cluster
          Mysql cluster是真正的高可用解決方案,但是必須得用NDB存儲引擎。如果你用innodb,將不能發揮mysql cluster集群優勢。
           
          Semi-Synchronous Replication
          半同步復制大大降低了binlog event僅僅存在于崩潰master上的這種風險。這非常有用的能避免數據丟失。但是半同步不能解決所有一致性問題,只能保證一個(不是所有)slave接受到master端的commit的binlog events,其他slave也許還沒有接受全部的binlog events。不能apply不同的binlog events 從新的slave到 其他slave上,也不能保證相互一致性
           
          Global Transaction ID
          GlobalTransaction ID所要達到的目的跟MHA相同,但它覆蓋更多。MHA只是兩級復制,但是global transaction id覆蓋任何級別的復制環境,即使第兩級復制失敗,dba也能覆蓋第三級。Check Google'sglobal transaction id project for details。
          posted @ 2014-08-05 13:45 小馬歌 閱讀(296) | 評論 (0)編輯 收藏
           

          第一種方法:

          RENAME database olddbname TO newdbname

          這個是5.1.7到5.1.23版本可以用的,但是官方不推薦,會有丟失數據的危險

          第二種方法:

          1.創建需要改成新名的數據庫。 
          2.mysqldum 導出要改名的數據庫 
          3.刪除原來的舊庫(確定是否真的需要) 
          當然這種方法雖然安全,但是如果數據量大,會比較耗時,哎,當時連這種方法都沒有想到,真有想死的沖動。

          第三種方法:

          我這里就用一個腳本,很簡單,相信大家都看的懂

          #!/bin/bash # 假設將sakila數據庫名改為new_sakila # MyISAM直接更改數據庫目錄下的文件即可  mysql -uroot -p123456 -e 'create database if not exists new_sakila' list_table=$(mysql -uroot -p123456 -Nse "select table_name from information_schema.TABLES where TABLE_SCHEMA='sakila'")  for table in $list_table do     mysql -uroot -p123456 -e "rename table sakila.$table to new_sakila.$table" done

          這里用到了rename table,改表名的命令,但是如果新表名后面加數據庫名,就會將老數據庫的表移動到新的數據庫,所以,這種方法即安全,又快速。

          posted @ 2014-07-31 10:02 小馬歌 閱讀(58283) | 評論 (1)編輯 收藏
           
          from:http://passover.blog.51cto.com/2431658/732629

          在線上環境中我們是采用了tomcat作為Web服務器,它的處理性能直接關系到用戶體驗,在平時的工作和學習中,歸納出以下七種調優經驗。

          1. 服務器資源

              服務器所能提供CPU、內存、硬盤的性能對處理能力有決定性影響。
              (1) 對于高并發情況下會有大量的運算,那么CPU的速度會直接影響到處理速度。
              (2) 內存在大量數據處理的情況下,將會有較大的內存容量需求,可以用-Xmx -Xms -XX:MaxPermSize等參數對內存不同功能塊進行劃分。我們之前就遇到過內存分配不足,導致虛擬機一直處于full GC,從而導致處理能力嚴重下降。
              (3) 硬盤主要問題就是讀寫性能,當大量文件進行讀寫時,磁盤極容易成為性能瓶頸。最好的辦法還是利用下面提到的緩存。

          2. 利用緩存和壓縮

              對于靜態頁面最好是能夠緩存起來,這樣就不必每次從磁盤上讀。這里我們采用了Nginx作為緩存服務器,將圖片、css、js文件都進行了緩存,有效的減少了后端tomcat的訪問。

              另外,為了能加快網絡傳輸速度,開啟gzip壓縮也是必不可少的。但考慮到tomcat已經需要處理很多東西了,所以把這個壓縮的工作就交給前端的Nginx來完成??梢詤⒖贾皩懙摹?a target="_blank" style="padding: 0px; margin: 0px; color: #4b0002; text-decoration: none;">利用nginx加速web訪問》。

              除了文本可以用gzip壓縮,其實很多圖片也可以用圖像處理工具預先進行壓縮,找到一個平衡點可以讓畫質損失很小而文件可以減小很多。曾經我就見過一個圖片從300多kb壓縮到幾十kb,自己幾乎看不出來區別。

          3. 采用集群

              單個服務器性能總是有限的,最好的辦法自然是實現橫向擴展,那么組建tomcat集群是有效提升性能的手段。我們還是采用了Nginx來作為請求分流的服務器,后端多個tomcat共享session來協同工作。可以參考之前寫的《利用nginx+tomcat+memcached組建web服務器負載均衡》。

          4. 優化tomcat參數

              這里以tomcat7的參數配置為例,需要修改conf/server.xml文件,主要是優化連接配置,關閉客戶端dns查詢。

          1. <Connector port="8080"   
          2.            protocol="org.apache.coyote.http11.Http11NioProtocol"  
          3.            connectionTimeout="20000"  
          4.            redirectPort="8443"   
          5.            maxThreads="500"   
          6.            minSpareThreads="20"  
          7.            acceptCount="100" 
          8.            disableUploadTimeout="true" 
          9.            enableLookups="false"   
          10.            URIEncoding="UTF-8" /> 

          5. 改用APR庫

              tomcat默認采用的BIO模型,在幾百并發下性能會有很嚴重的下降。tomcat自帶還有NIO的模型,另外也可以調用APR的庫來實現操作系統級別控制。

              NIO模型是內置的,調用很方便,只需要將上面配置文件中protocol修改成org.apache.coyote.http11.Http11NioProtocol,重啟即可生效。上面配置我已經改過了,默認的是HTTP/1.1。

              APR則需要安裝第三方庫,在高并發下會讓性能有明顯提升。具體安裝辦法可以參考http://www.cnblogs.com/huangjingzhou/articles/2097241.html。安裝完成后重啟即可生效。如使用默認protocal就是apr,但最好把將protocol修改成org.apache.coyote.http11.Http11AprProtocol,會更加明確。

              在官方找到一個表格詳細說明了這三種方式的區別:

          1.                   Java Blocking Connector   Java Nio Blocking Connector   APR/native Connector 
          2.                              BIO                         NIO                       APR 
          3. Classname                AjpProtocol               AjpNioProtocol           AjpAprProtocol 
          4. Tomcat Version           3.x onwards                 7.x onwards              5.5.x onwards 
          5. Support Polling              NO                          YES                       YES 
          6. Polling Size                 N/A                   maxConnections             maxConnections 
          7. Read Request Headers      Blocking                  Sim Blocking                   Blocking 
          8. Read Request Body         Blocking                  Sim Blocking                   Blocking 
          9. Write Response            Blocking                  Sim Blocking                   Blocking 
          10. Wait for next Request     Blocking                  Non Blocking               Non Blocking 
          11. Max Connections        maxConnections              maxConnections             maxConnections 

          6. 優化網絡

              Joel也明確提出了優化網卡驅動可以有效提升性能,這個對于集群環境工作的時候尤為重要。由于我們采用了linux服務器,所以優化內核參數也是一個非常重要的工作。給一個參考的優化參數:

          1. 1. 修改/etc/sysctl.cnf文件,在最后追加如下內容: 
          2.  
          3. net.core.netdev_max_backlog = 32768 
          4. net.core.somaxconn = 32768 
          5. net.core.wmem_default = 8388608 
          6. net.core.rmem_default = 8388608 
          7. net.core.rmem_max = 16777216 
          8. net.core.wmem_max = 16777216 
          9. net.ipv4.ip_local_port_range = 1024 65000 
          10. net.ipv4.route.gc_timeout = 100 
          11. net.ipv4.tcp_fin_timeout = 30 
          12. net.ipv4.tcp_keepalive_time = 1200 
          13. net.ipv4.tcp_timestamps = 0 
          14. net.ipv4.tcp_synack_retries = 2 
          15. net.ipv4.tcp_syn_retries = 2 
          16. net.ipv4.tcp_tw_recycle = 1 
          17. net.ipv4.tcp_tw_reuse = 1 
          18. net.ipv4.tcp_mem = 94500000 915000000 927000000 
          19. net.ipv4.tcp_max_orphans = 3276800 
          20. net.ipv4.tcp_max_syn_backlog = 65536 
          21.  
          22. 2. 保存退出,執行sysctl -p生效 

          7. 讓測試說話

              優化系統最忌諱的就是只調優不測試,有時不適當的優化反而會讓性能更低。以上所有的優化方法都要在本地進行性能測試過后再不斷調整參數,這樣最終才能達到最佳的優化效果。

           

          補充Bio、Nio、Apr模式的測試結果:

              對于這幾種模式,我用ab命令模擬1000并發測試10000詞,測試結果比較意外,為了確認結果,我每種方式反復測試了10多次,并且在兩個服務器上都測試了一遍。結果發現Bio和Nio性能差別非常微弱,難怪默認居然還是Bio。但是采用apr,連接建立的速度會有50%~100%的提升。直接調用操作系統層果然神速啊,這里強烈推薦apr方式!

           

          參考資料:
          http://16.199.geisvps.com/bbs/2836/24238.html

          posted @ 2014-07-29 10:31 小馬歌 閱讀(1740) | 評論 (0)編輯 收藏
           
               摘要: 1、MySQL錯誤日志里出現:140331 10:08:18 [ERROR] Error reading master configuration140331 10:08:18 [ERROR] Failed to initialize the master info structure140331 10:08:18 [Note] Event Scheduler: Loaded 0 events&n...  閱讀全文
          posted @ 2014-07-25 14:56 小馬歌 閱讀(22059) | 評論 (0)編輯 收藏
           
               摘要: http://www.oschina.net/question/12_90733作為 MySQL 5.5 和 5.6 性能比較的一部分,我研究了下兩個版本默認參數的差異,為了了解差異內容,我使用如下的 SQL 語句分別在 MySQL 5.5 和 5.6 版本進行查詢,得出下表(點擊圖片查看大圖):讓我們來看看這些差異的配置中最重要的也是影響最大的部分:performance_schema...  閱讀全文
          posted @ 2014-07-23 15:41 小馬歌 閱讀(235) | 評論 (0)編輯 收藏
           
               摘要: ZooKeeper是一個分布式開源框架,提供了協調分布式應用的基本服務,它向外部應用暴露一組通用服務——分布式同步(Distributed Synchronization)、命名服務(Naming Service)、集群維護(Group Maintenance)等,簡化分布式應用協調及其管理的難度,提供高性能的分布式服務。ZooKeeper本身可以以Standalone模式...  閱讀全文
          posted @ 2014-07-23 11:57 小馬歌 閱讀(321) | 評論 (0)編輯 收藏
          僅列出標題
          共95頁: First 上一頁 17 18 19 20 21 22 23 24 25 下一頁 Last 
           
          主站蜘蛛池模板: 鄢陵县| 皋兰县| 临邑县| 威海市| 司法| 平顶山市| 固安县| 宕昌县| 牡丹江市| 应城市| 喜德县| 岐山县| 轮台县| 榕江县| 沽源县| 和静县| 彰化县| 疏勒县| 平定县| 大竹县| 揭西县| 安远县| 萝北县| 英超| 翁源县| 吉林市| 琼中| 肇东市| 陇西县| 苏尼特左旗| 昭通市| 淮滨县| 阿瓦提县| 河源市| 永年县| 漳平市| 定安县| 资阳市| 安新县| 阿克苏市| 通榆县|