Apache CXF负载平衡和故障转移
生活随笔
收集整理的這篇文章主要介紹了
Apache CXF负载平衡和故障转移
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前一段時間,我們已經面臨基于Apache CXF的負載平衡Web服務客戶端的需求。 此外,當某些服務器關閉時,客戶端應自動進行故障轉移。 更糟糕的是,服務器目標地址列表要從外部服務獲取并在運行時更新。
最終,我們最終獲得了自己開發的負載平衡微庫(ESB / UDDI / WS-Addressing似乎是一個有趣的替代方案,但在我們的情況下這是一個過大的選擇)。 如果我們只知道Apache CXF已經(幾乎)開箱即用地支持所有這些功能?
但是,不要怪我們,僅提及此功能會指向非常糟糕的文檔頁面(如果您將404稱為“差”)。 如果不在正式文檔中,我希望可以在Apache CXF Web服務開發書中找到它-不幸的是,那里也很不幸。 但是,嘿,您自己探索這些功能不是更有趣嗎? 這是我們開始的客戶端配置: <beans xmlns="http://www.springframework.org/schema/beans"xmlns:jaxws="http://cxf.apache.org/jaxws"xmlns:clustering="http://cxf.apache.org/clustering"xmlns:util="http://www.springframework.org/schema/util"><jaxws:client id="testServiceClient"serviceClass="com.blogspot.nurkiewicz.cxfcluster.SimpleService"address="http://serverA/simple"></jaxws:client></beans> 端點接口在這里并不重要,足以知道將testServiceClient注入到其他一些服務中,并且負載平衡和故障轉移功能不應影響現有代碼。 請注意,服務地址是固定的且經過硬編碼的(當然可以將其外部化并在啟動時讀取)。 令人驚訝的是,僅啟用故障轉移是非常簡單,直接和不言自明的(盡管是XML): <jaxws:client id="testServiceClient"serviceClass="com.blogspot.nurkiewicz.cxfcluster.SimpleService"address="http://serverA/simple"><jaxws:features><clustering:failover><clustering:strategy><bean class="org.apache.cxf.clustering.RandomStrategy"><property name="alternateAddresses"><util:list><value>http://serverB/simple</value><value>http://serverC/simple</value><value>http://serverD/simple</value></util:list></property></bean></clustering:strategy></clustering:failover></jaxws:features></jaxws:client> serverA地址用作主要端點,但是當它失敗時, 將以隨機順序檢查所有故障轉移端點( serverB , serverC和serverD )。 為了發揮這種配置的作用,我建議您打開Apache CXF請求和響應日志記錄 : <cxf:bus><cxf:features><cxf:logging/></cxf:features> </cxf:bus> 再次(!),官方文檔中沒有提到非常方便的配置參數prettyLogging ,該參數可以應用于日志記錄功能,以便在進行記錄之前對XML請求和響應進行正確的格式化( 換行和縮進)。 我不建議在生產設置中使用它,但是在開發和測試過程中,格式化SOAP消息是非常寶貴的: <bean id="abstractLoggingInterceptor" abstract="true"><property name="prettyLogging" value="true"/> </bean> <bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" parent="abstractLoggingInterceptor"/> <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor" parent="abstractLoggingInterceptor"/><cxf:bus><cxf:inInterceptors><ref bean="loggingInInterceptor"/></cxf:inInterceptors><cxf:outInterceptors><ref bean="loggingOutInterceptor"/></cxf:outInterceptors><cxf:outFaultInterceptors><ref bean="loggingOutInterceptor"/></cxf:outFaultInterceptors><cxf:inFaultInterceptors><ref bean="loggingInInterceptor"/></cxf:inFaultInterceptors> </cxf:bus> 因此,如果主要端點不可用,我們的服務很好地故障轉移到備份端點。 但是我們有四個等效的服務器,我們希望我們的客戶以相同的概率(輪循,隨機?)平等地對待它們。 這是負載均衡進入階段的時候: <jaxws:client id="testServiceClient" serviceClass="com.blogspot.nurkiewicz.cxfcluster.SimpleService"><jaxws:features><clustering:loadDistributor><clustering:strategy><bean class="org.apache.cxf.clustering.SequentialStrategy"><property name="alternateAddresses"><util:list><value>http://serverA/simple</value><value>http://serverB/simple</value><value>http://serverC/simple</value><value>http://serverD/simple</value></util:list></property></bean></clustering:strategy></clustering:loadDistributor></jaxws:features></jaxws:client> 請注意,客戶端本身不再定義地址屬性。 這表明, alternateAddresses列表僅在所有調用中使用,并且不存在主地址-實際上是這種情況。 SequentialStrategy將使用一個端點接另一個端點,以提供良好的循環實現(也提供RandomStrategy )。 同樣,在此配置中,您將免費獲得故障轉移–如果任何端點發生故障,將從第一個端點開始的所有端點都將受到檢查(顯然,剛剛發生故障的端點除外)。 大! 現在,CXF客戶端更加嚴格和容錯。 但是,在我們追求更高可用性并最大程度地減少停機時間的過程中,僅在應用程序啟動時才加載備用節點(換句話說,添加新服務器需要重新啟動所有客戶端)實在太過局限了。 幸運的是,我們可以通過兩個簡單的步驟使負載均衡更加動態。 <jaxws:client id="testServiceClient" serviceClass="com.blogspot.nurkiewicz.cxfcluster.SimpleService"><jaxws:features><clustering:loadDistributor><clustering:strategy><bean class="org.apache.cxf.clustering.SequentialStrategy"><property name="alternateAddresses" ref="alternateAddresses"/></bean></clustering:strategy></clustering:loadDistributor></jaxws:features></jaxws:client><util:list id="alternateAddresses" list-class="java.util.concurrent.CopyOnWriteArrayList"><value>http://serverA/simple</value><value>http://serverB/simple</value><value>http://serverC/simple</value><value>http://serverD/simple</value> </util:list> 沒什么,提取嵌套的匿名bean。 但是可以訪問此列表(請注意,我使用了java.util.concurrent.CopyOnWriteArrayList )使我們可以將其注入任何其他服務,從而可能改變其狀態。 我怎么知道這會起作用? 好吧,我花了幾天的時間調試Apache CXF,以最終發現負載平衡算法:第一次調用時,CXF要求策略提供可能節點的列表。 然后它會將這個列表返回策略要求到(在這里小編WTF ......)挑選一個戰略決定哪些地址,使用和刪除列表中挑選地址(另一個小一個在這里...)當CXF發現列表是空的,故事重復本身。 因此,如果我們在運行時替換備用地址列表,則一輪新列表將返回到核心CXF基礎結構。 因為我是JMX的擁護者,所以這是我們修改地址列表的方法(您可以使用任何喜歡的機制): @Service @ManagedResource public class AlternateAddressesManager {@Resourceprivate List alternateAddresses;@ManagedOperationpublic void addAlternateAddress(String address) {alternateAddresses.add(address);}@ManagedOperationpublic boolean removeAlternateAddress(String address) {return alternateAddresses.remove(address);}@ManagedAttributepublic List getAlternateAddresses() {return Collections.unmodifiableList(alternateAddresses);}} 是的,這是SequentialStrategy使用的非常相同的alternateAddresses列表,因此,只需對其進行修改,就可以更改CXF尋址行為。 可以說,我們可以擴展CopyOnWriteArrayList,添加一些額外的啟用JMX的方法(或者,探索Springs的靈活性,直接通過JMX公開List方法!),但這會降低可維護性,我認為這是較差的設計。 最后,我們可以按照下面的屏幕快照啟動jconsole或JVisualVM,并享受我們的負載平衡基礎架構: 快樂? 并不是的。 在研究CXF源代碼時,我遇到了有關LoadDistributorFeature和FailoverTargetSelector類的可怕的JavaDoc注釋,它們在負載平衡過程中起著重要的作用: / ** * […] *請注意,此功能會即時更改導管,從而使 * 客戶端不是線程安全的。 * / 重點放在粗體的文本上(好的,老實說,我不理解其余內容)。 如果您已經使用Spring一段時間,您就會知道testServiceClient bean是多個線程同時使用的共享單例(否,使其原型作用域無濟于事;為什么?),這與默認的EJB無狀態會話bean相反,被匯集。 幸運的是,Spring也有一個內置的解決方案。 但是,在我最終提出正確的解決方案之前,出現了一些障礙。 首先,來自CXF名稱空間的jaxws:client標記不允許定義bean范圍,默認情況下為單例,而我們要合并客戶端。 因此,我不得不使用org.apache.cxf.jaxws.JaxWsProxyFactoryBean恢復到良好的舊bean定義。 沒問題,稍微冗長些,盡管如果您不希望使用自定義Spring名稱空間,則可能從一開始就使用它。 現在最好的部分是:我可以將具有原型范圍的任何bean封裝在特殊的代理中,Spring會自動創建一個對象池(基于commons-pool庫),并根據需要創建盡可能多的bean實例,以使每個bean僅由一個使用。線。 配置如下: <bean id="testServiceClientFactoryBean" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"><property name="serviceClass" value="com.blogspot.nurkiewicz.cxfcluster.SimpleService"/><property name="features"><util:list><bean class="org.apache.cxf.clustering.LoadDistributorFeature"><property name="strategy"><bean class="org.apache.cxf.clustering.SequentialStrategy"><property name="alternateAddresses" ref="alternateAddresses"/></bean></property></bean></util:list></property> </bean><bean id="testServiceClientTarget" factory-bean="testServiceClientFactoryBean" factory-method="create" scope="prototype" lazy-init="true"/><bean id="testServiceClient" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="targetSource"><bean class="org.springframework.aop.target.CommonsPoolTargetSource"><property name="targetClass" value="com.blogspot.nurkiewicz.cxfcluster.SimpleService"/><property name="targetBeanName" value="testServiceClientTarget"/><property name="maxSize" value="10"/><property name="maxWait" value="5000"/></bean></property> </bean> 您是否注意到maxSize和maxWait池屬性? 他們真是太酷了 ! 您可以告訴Spring在池中創建的客戶端不要超過10個,并且如果池為空(當前正在使用所有Bean),則我們應該等待不超過5000毫秒(此后可以配置!)實際上是非常簡單但功能強大的限制機制,比JMS或顯式線程池簡單得多,我們絕對免費! 例如,不想服務超過20個并發Web服務客戶端? 使服務器端點訪問服務Bean的大小限制為20。超過此限制的客戶端將被拒絕,因為沒有可用的服務Bean。 當然,在成人世界中,沒有任何效果可以預期。 我很快發現JaxWsProxyFactoryBean.create不是線程安全的, 并報告了CXF-3558 。 作為解決方法,我必須通過將其 子類化 來同步 CommonsPoolTargetSource 使用的客戶端工廠 : import org.apache.commons.pool.ObjectPool; import org.apache.commons.pool.PoolUtils; import org.springframework.aop.target.CommonsPoolTargetSource;public class SynchCommonsPoolTargetSource extends CommonsPoolTargetSource {@Overrideprotected ObjectPool createObjectPool() {return PoolUtils.synchronizedPool(super.createObjectPool());}} 似乎需要同步工廠,因此我創建了SPR-8382-也許它將找到正式發行的方式。 順便說一句,在撰寫本文時,我還報告了IDEA-70365 – 報告了List類型bean的 虛假 “無法自動裝配”錯誤 。 最后! 我們的負載平衡和故障轉移就像一個魅力。 下一步將是暫時丟棄掉了幾秒鐘的節點,如果此后端點仍然掉線,則增加此時間。 但是Apache CXF在這一領域的API如此糟糕,以至于我不得不離開這個話題一段時間。 也許您可以幫忙?參考: NoBlogDefFound博客上的 JCG合作伙伴 Tomasz 在Apache CXF中啟用負載平衡和故障轉移 。
相關文章 :- 帶有Spring和Maven教程的JAX–WS
- Spring3 RESTful Web服務
- Tomcat 7上具有RESTeasy JAX-RS的RESTful Web服務-Eclipse和Maven項目
翻譯自: https://www.javacodegeeks.com/2011/06/apache-cxf-load-balancing-failover.html
總結
以上是生活随笔為你收集整理的Apache CXF负载平衡和故障转移的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 雷神 MIX 迷你游戏主机开启预约:i9
- 下一篇: 博世本周完成收购 TSI Semicon