亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

使用分布式緩存來群集Spring遠程服務

2019-11-18 12:58:29
字體:
來源:轉載
供稿:網友

  當企業級計算進入新的SOA世界時,在尋找描述/發布/和發現服務的方面中開始變得越來越重要?;诰W絡服務的方案不提供自動服務發現而且通常都太繁雜了。現在新的輕量級的開發框架提供了新的輕量級的服務發布方案。

  在過去幾年中,SPRing框架已經成為開發簡單、靈活而且輕易配置的J2EE應用的事實標準。Spring的核心是IoC法則。根據IoC,應用必須以一個簡單javaBean的集合來開發,然后用一個輕量級的IoC容器來綁定他們并設置相關的依靠關系。
  在Spring中,容器通過一系列bean定義也配置,典型的是用xml文件方式:
<bean id="MyServiceBean" class="mypackage.MyServiceImpl">
   <property name="otherService" ref="OtherServiceBean"/>
</bean>
  當客戶端代碼需要請求時MyService,你只要如下編碼:
MyServiceInterface service = (MyServiceInterface)context.getBean("MyServiceBean");
service.doSomething();
  除了IoC之外,Spring提供了幾百種其他服務,代碼約定,而且通過回調標準API來簡化開發典型的服務端應用。無論應用使用重量級的J2EE API如EJB/JMS/JMX或者使用流行的MVC框架來構建網絡接口,Spring都提供了簡化的效果。
  隨著Spring框架的成熟,越來越多的人使用他作為大型企業級項目的基礎。Spring已經通過了伸縮性開發的測試而且可以作為組件粘合劑來聯結復雜的分布式系統。

  任何企業級應用都由各種組件組成:如聯結以前的系統和ERP系統,第三方系統,網面/表示層/持久導等等。通常一個電子商務站點都是由簡單的網頁應用逐漸深化成包含上百個子應用和子系統的大項目,而且要面對其中的復雜性會阻礙以后的發展。通常的解決方案是將集成電路般的應用分解成一些粗紋理的服務并將其發布到網絡中。

  不管應用是被設計成作為分散服務的集成點或者已經集成為一體,治理所有分布式組件和其配置的任務通常都是耗時和代價高的。但假如你使用了Spring作為應用組件的開發平臺,那么你就可以使用Spring的遠程服務通過一系列的協議來將組件暴露給遠程的客戶端。通過Spring,可以使你的分布式應用就如修改一些配置文件那么簡單。

  在Spring中最簡單的java-to-java的遠程通訊方案是使用HTTP遠程服務。例如,在web.xml中注冊了Spring的分發服務件后,下面的上下文片斷就可以將MyService作為公共接口使用了:
<bean name="/MyRemoteService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceEXPorter">
  <property name="service" ref="MyServiceBean"/>
  <property name="serviceInterface" value="mypackage.MyServiceInterface"/>
</bean>
  如你所見,實際的服務被注入到bean的定義中因此可以被遠程調用:
  在客戶端,上下文定義如下:
<bean id="MyServiceBean"
      class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
      <property name="serviceUrl"
         value="http://somehost:8080/webapp-context/some-mapping-for-spring-servlet/MyRemoteService" />
      <property name="serviceInterface"
         value="mypackage.MyServiceInterface" />
   </bean>
  通過Spring的魔法,客戶端代碼不需要改變,而遠程方法的激活就像以前的本地調用一樣。
除了HTTP遠程服務外,Spring還支持其他的遠程協議,如基于HTTP的解決方案(Web services, Hessian, and Burlap)和重量級的如RMI。

配置和部署基于URL的遠程服務

  通過基于HTTP遠程服務來部署應用服務有幾個明顯的優點,其中一個是相對于RMI或EJB方案,你不需要擔心更多的配置問題。任何嘗試過使用JNDI配置(來自不同廠家的J2EE容器或者同一廠家容器的不同版本的負載均衡及群集)的人都這樣認為。

  URL是無格式的文本串,而這是最方便的。但同時,通過URL定義服務使得定義有些脆弱。在前面章節列舉的URL的不同部分都會按照自己的方式進行變化。網絡拓樸變化,負載均衡服務器代替普通服務器,應用被布署到不同機器的不同容器中,網絡防火墻間的商品被打開或關閉等等。

  此外,這些不穩定的URL必須被存儲在每一個可能訪問服務的客戶端的Spring上下文文件中。當變化發生時,所有的客戶端必須更新。還有從開發階段到產品階段的服務進程,指向服務的URL必須反映服務所在的環境。
  最后我們到達了問題的要害:Spring的暴露各部分受治理的bean作為遠程訪問服務的能力是非常棒的。甚至在我們需要定義一個服務為服務名時,對客戶端隱藏所有有關服務定位的問題。

自動發現和容錯的緩存服務

  這個問題最簡單解決方法是使用某些命名服務來動態實時的轉換服務名與服務位置。實際上,我只需要構建一次這樣的系統通過使用 JmDNS類庫注冊Spring遠程服務在Zeroconf命名空間中。

  基于DNS方案的問題在于更新服務定義是不可能做到實時或事務的。一個失敗的服務器在各類超時前還是出現在服務列表中。而我們需要的是快速發布并更新URL列表來實現服務并在整個網絡中同步的表現所有變化。

  滿足這些需求的系統才是可用的。這包含各種分布式緩存的實現。對Java開發人員來說最簡單的想像緩存的方式是認為緩存是一個java.util.Map接口的實現。你可以通過鍵值來放入一引起對象,然后你可以用同一鍵值取得這個對象。一個分布式緩存系統需要確保相同的鍵/值映射會存在于每一個參與這個緩存的服務器中的相同Map中并且步伐一致的更新緩存。

  一個好的分布式緩存可以解決我們的問題。我們在實現了服務的網絡中關聯一個服務名和一個或多個URL。然后,我們在分布式緩存中存儲name=(URL列表)關聯并隨著網絡狀態的變化(服務器的加入/移除/當機等)而相應更新??蛻舳嗽L問參與分布式緩存的服務就像訪問私有的服務一樣。

  作為附加的獎勵,我們會在這里介紹一個簡單的負載均衡/容錯的解決方案。假如客戶端知道一個服務與幾個服務URL關聯,他可以隨機地使用其中的一個并且通過為這些URL服務的幾個服務來提供自然的但也有效的負載均衡。而且,在一個遠程調用失敗時,客戶端簡單地標識那個URL不可用并且使用下一個。因為服務URL列表存儲在分布式緩存中,服務器A不可用的情況也會馬上通知給別的客戶端。

  分布式緩存在常規的J2EE應用中非常有用,是群集服務的基礎。例如,假如你有一個分布式的群集應用,分布式緩存可以在你的群集成員中提供會話復制。雖然這種方式提供了高可用性,但也存在嚴重的瓶頸。會話數據變化的很快,更新所有群集成員和容錯的代價非常高。帶有會話復制的群集應用效率通常比基于負載均衡的非會話復制的方案低很多。

  在我們的案例中使用分布式緩存是因為緩存的數據很少。相對于通常有上千會話對象的分布式系統來說,我們只有少量的服務列表和對應其實現的URL。此外,我們的列表更新并不頻繁。使用這樣一個小列表的分布式緩存可以服務于大量的服務器和客戶端。
  在本文的剩余部分,我們來看一下“服務描述緩存算法”的實際實現

使用Spring和Jboss緩存來實現服務描述緩存

  Jboss應用服務器可能是今天最成功的開源J2EE項目了。不管是愛是恨,Jboss應用服務器在布署服務器排行榜上占據應得的位置,而且他的模塊天性使得布署更加友好。

  JBoss發布包包含了很服務。其中一個是JBoss緩存。他實現的緩存提供了無論本地或遠程的Java對象的高性能緩存。JBoss緩存有許多配置選項和特性,我希望你更深入的研究使得他更好的適合你的下一個項目。

  對我們最有吸引的特性如下:
1、提供了高質量的Java對象的事務復制。
2、可以獨立運行或者作為Jboss的一部分。
3、已經是Jboss的一部分
4、可以使用UDP多播的方式和TCP連接的方式。

  JBoss緩存的網絡基礎是JGroups類庫。JGroups提供了群體成員間的網絡通訊并且可以工作于UDP或TCP方式。
  在本文中,我會演示如何使用JBoss緩存來存儲服務的定義和提供動態的自動服務發現。

  剛開始,我們先引入一個自定義類,AutoDiscoveredServiceExporter擴展Spring的標準HttpInvokerServiceExporter類來暴露我們的TestService給遠程調用:

<bean name="/TestService" class="app.service.AutoDiscoveredServiceExporter">
  <property name="service" ref="TestService"/>
  <property name="serviceInterface" value="app.service.TestServiceInterface"/>
</bean>
  這個在沒有什么可說的。我們主要是使用他來標識Spring遠程服務作為我們自己的方式來暴露。
接下來是服務端的緩存配置。Jboss包含了緩存實現,我們可以用Spring內建的JMX代理將緩存引入Spring上下文:
<bean id="CustomTreeCacheMBean" class="org.springframework.jmx.access.MBeanProxyFactoryBean">
    <property name="objectName">
      <value>jboss.cache:service=CustomTreeCache</value>
    </property>
    <property name="proxyInterface">
      <value>org.jboss.cache.TreeCacheMBean</value>
    </property>
</bean>
  這創建一個CustomTreeCacheMBean在服務端的Spring上下文中。通過自動代理的特性,這個bean實現了org.jboss.cache.TreeCacheMBean接口的方法。在這里,布署到Jboss服務器只需要將已經提供的custom-cache-service.xml放到服務器的布署目錄下。

  為了簡化代碼,我們引入簡單的CacheServiceInterface接口:
   public void put(String path, Object key, Object value) throws Exception;
   public Object get(String path, Object key) throws Exception;
JBoss Cache是一種樹狀結構,這也是為什么我們需要path參數。
這個接口的服務端實現如下引用緩存Mbean:
<bean id="CacheService" class="app.service.JBossCacheServiceImpl">
   <property name="cacheMBean" ref="CustomTreeCacheMBean"/>
</bean>
  在最后,我們需要ServicePublisher來觀察Spring容器的生命周期,并且在我們的緩存中發布或移除服務定義:
<bean id="ServicePublisher" class="app.service.ServicePublisher">
   <property name="cache" ref="CacheService"/>
</bean>
這段代碼顯示ServicePublisher在Spring上下文刷新時(如應用補布署時)如何處理:
   private void contextRefreshed() throws Exception {
      logger.info("context refreshed");

      String[] names = context
            .getBeanNamesForType(AutoDiscoveredServiceExporter.class);
      logger.info("exporting services:" + names.length);
      for (int i = 0; i < names.length; i++) {
         String serviceUrl = makeUrl(names[i]);
         try {
            Set services = (Set) cache.get(SERVICE_PREFIX + names[i],
                  SERVICE_KEY);
            if (services == null)
               services = new HashSet();
            services.add(serviceUrl);
            cache.put(SERVICE_PREFIX + names[i], SERVICE_KEY, services);
            logger.info("added:" + serviceUrl);
         } catch (Exception ex) {
            logger.error("exception adding service:", ex);
         }
      }
  如你所見,發布器簡單的遍歷通過緩存服務描述導出的服務列表并增加定義到緩存中。我們的緩存設計成路徑包含服務名,他的URL列表存儲在一個Set對象中。將服務名作為路徑的一部分對JBoss Cache實現來說是重要的因為他是基于路徑來創建和釋放事務鎖。這種方式下,對服務A的更新不會干擾對服務B的更新因為他們被映射到不同的路徑:/some/prefix/serviceA/key=(list of URLs) and /some/prefix/serviceB/key=(list of URLs)。
移除服務定義的代碼是類似的。

  現在我們轉到客戶端。我們需要一個緩存實現來與服務端共享:
<bean id="LocalCacheService" class="app.auto.LocalJBossCacheServiceImpl">
</bean>
LocalJBossCacheServiceImpl保存著來自與服務端相同的custom-cache-service.xml配置的JBoss Cache引用:
   public LocalJBossCacheServiceImpl() throws Exception {
      super();
      cache = new TreeCache();
      PropertyConfigurator config = new PropertyConfigurator();
      config.configure(cache, "app/context/custom-cache-service.xml");
   }
  這個緩存定義文件包含了Jgroups層的配置,答應所有緩存成員通過UDP多播來定位彼此。
LocalJBossCacheServiceImpl還實現了接口并且為我們的AutoDiscoveredService提供了緩存服務。這個bean擴展了標準的HttpInvokerProxyFactoryBean類但配置上有些不同:
   <bean id="TestService"
      class="app.auto.AutoDiscoveredService">
      <property name="serviceInterface"
         value="app.service.TestServiceInterface" />
      <property name="cache" ref="LocalCacheService"/>
   </bean>
  最初,沒有URL存在。自動在網絡上尋找在TestService名字上暴露的Spring遠程服務。當服務發現時,他就獲得了來自分布式緩存的URL列表:
   private List getServiceUrls() throws Exception {
      Set services = (Set) cache.get(ServicePublisher.SERVICE_PREFIX
            + beanName, ServicePublisher.SERVICE_KEY);
      if (services == null)
         return null;
      ArrayList results = new ArrayList(services);
      Collections.shuffle(results);
      logger.info("shuffled:" + results);
      return results;
   }
  Collections.shuffle隨機地重排與服務關聯的URL列表因此客戶端的方法調用在他們之間是負載均衡的。實際的遠程調用如下:
   public Object invoke(MethodInvocation arg0) throws Throwable {

      List urls = getServiceUrls();
      if (urls != null)
         for (Iterator allUrls = urls.iterator(); allUrls.hasNext();) {
            String serviceUrl = null;
            try {
               serviceUrl = (String) allUrls.next();
               super.setServiceUrl(serviceUrl);
               logger.info("going to:" + serviceUrl);
               return super.invoke(arg0);
            } catch (Throwable problem) {
               if (problem instanceof IOException
                     problem instanceof RemoteAccessException) {
                  logger.warn("got error accessing:"
                        + super.getServiceUrl(), problem);
                  removeFailedService(serviceUrl);
               } else {
                  throw problem;
               }
            }
         }
      throw new IllegalStateException("No services configured for name:"
            + beanName);
   }
  如你所見,假如遠程調用拋出異常,客戶端代碼可以處理這個問題而且可以從列表中取下一個URL,因此也就提供了透明的容錯性。假如調用因為某些異常失敗了,他為重新拋出異常給客戶端處理。
  下面的removeFailedService()方法簡單的從列表中移除了失敗的URL并更新分布式緩存,使這個信息同步地通知所有其他客戶端:
   private void removeFailedService(String url) {
      try {
         logger.info("removing failed service:" + url);
         Set services = (Set) cache.get(ServicePublisher.SERVICE_PREFIX
               + beanName, ServicePublisher.SERVICE_KEY);
         if (services != null) {
            services.remove(url);
            cache.put(ServicePublisher.SERVICE_PREFIX + beanName, ServicePublisher.SERVICE_KEY,
                  services);
            logger.info("removed failed service at:" + url);
         }
      } catch (Exception e) {
         logger.warn("failed to remove failed service:" + url, e);
      }
   }
  假如你構建并布署一個樣例應用在多個Jboss服務器上而且運行提供的LoopingAutoDiscoveredRemoteServiceTest,你可以看到請求是如何在Spring群集中負載均衡的。你也可以停止和重啟任何的服務器,而調用會動態地路由到其他的服務器上。假如你當掉一臺服務器,你會看到一個異常被輸出到客戶端的控制臺上,但所有的請求依舊無停頓的傳遞給其他服務器。

小結

  在本文中,我們了解了如何通過Spring的遠程服務來群集網絡服務。此外,你可以學到如何通過只使用名字來定義私有的服務及依靠自動發現來綁定服務到相應的URL,從而簡化布署一個復雜的多層應用



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品成人免费| 亚洲天堂av在线播放| 中文字幕最新精品| 国产精品欧美激情在线播放| 国产精品美女久久久久av超清| 黄色一区二区三区| 亚洲欧美日韩精品久久| 久久精品国产96久久久香蕉| 国产午夜精品美女视频明星a级| 久久精品91久久香蕉加勒比| 91成人在线视频| 亚洲综合中文字幕在线| 中日韩美女免费视频网站在线观看| 在线午夜精品自拍| 欧美性猛交99久久久久99按摩| 欧美成人午夜激情视频| 欧美在线视频导航| 国产精品美腿一区在线看| 一区二区欧美日韩视频| 亚洲国产另类久久精品| 在线观看精品自拍私拍| 久久久久久久一区二区三区| 精品视频在线观看日韩| 亚洲free性xxxx护士hd| 91av免费观看91av精品在线| 一区二区三区视频观看| 亚洲欧美制服中文字幕| 欧美极品少妇xxxxⅹ裸体艺术| 性日韩欧美在线视频| 久久在线观看视频| 亚洲成人精品久久| 亚洲国产福利在线| 欧美高清无遮挡| 午夜精品一区二区三区av| 亚洲国产精品成人精品| 91免费国产网站| 亚洲性线免费观看视频成熟| 日韩中文字幕在线视频播放| 亚洲日韩中文字幕在线播放| 啪一啪鲁一鲁2019在线视频| www.久久撸.com| 欧美精品在线视频观看| 欧美午夜片欧美片在线观看| 欧洲精品毛片网站| 欧美性做爰毛片| 57pao成人永久免费视频| 日韩中文娱乐网| 欧美精品在线免费| 超碰精品一区二区三区乱码| 91av在线视频观看| 精品中文字幕在线观看| 成人免费自拍视频| 97超碰蝌蚪网人人做人人爽| 一区二区三区国产在线观看| 中文字幕日本欧美| 亚洲国产又黄又爽女人高潮的| 亚洲影院在线看| 久久久久国产精品免费网站| 国产日本欧美在线观看| 性欧美在线看片a免费观看| www.欧美免费| 丝袜一区二区三区| 一本一道久久a久久精品逆3p| 久久综合色88| 日韩av快播网址| 国产精品视频白浆免费视频| 亚洲片国产一区一级在线观看| 最近中文字幕日韩精品| 亚洲性猛交xxxxwww| 久久人人爽人人爽爽久久| 日韩欧美综合在线视频| 久久91超碰青草是什么| 亚洲欧美另类中文字幕| 亚洲欧美日韩国产中文| 亚洲欧美福利视频| 国产欧美最新羞羞视频在线观看| 久久久久久久久亚洲| 中文字幕久热精品在线视频| 日韩精品欧美国产精品忘忧草| 亚洲成人黄色在线| 亚洲国产美女久久久久| 日韩精品免费在线| 欧美成人三级视频网站| 国产精品久久国产精品99gif| 亚洲欧洲偷拍精品| 欧美性感美女h网站在线观看免费| 精品高清一区二区三区| 日韩av电影在线免费播放| 91久久国产综合久久91精品网站| 日本一欧美一欧美一亚洲视频| 岛国精品视频在线播放| 久久久久久国产| 国产日韩欧美中文在线播放| 欧美最猛性xxxx| 久久精品一区中文字幕| 久久久久www| 欧美激情乱人伦一区| 中文字幕精品久久| 亚洲第一av在线| 日韩成人中文字幕| 久久成人av网站| 国产欧洲精品视频| 国内精品久久久久久中文字幕| 亚洲欧美另类人妖| 日韩激情av在线免费观看| 91午夜理伦私人影院| 欧美性一区二区三区| 欧美高清在线播放| 日韩精品极品在线观看播放免费视频| 欧美亚洲视频在线观看| 91亚洲精品在线观看| 欧美日韩国产精品一区二区不卡中文| 爽爽爽爽爽爽爽成人免费观看| 欧美又大又粗又长| 国产一区二区三区免费视频| 91精品久久久久久久久| 中文字幕精品av| 久久久久久久久亚洲| 日日狠狠久久偷偷四色综合免费| 亚洲色图欧美制服丝袜另类第一页| 国产精品男女猛烈高潮激情| 日韩精品久久久久| 久久久国产视频91| 久久综合免费视频| 国产成人高清激情视频在线观看| 亚洲成人网久久久| 欧美国产日韩一区二区| 日韩欧美999| 日韩美女视频免费在线观看| 97久久精品在线| 国产在线视频一区| 91麻豆国产精品| 久久影院免费观看| 国产精品久久一区主播| 欧美亚洲免费电影| 中日韩午夜理伦电影免费| 欧美高清视频在线观看| 欧日韩不卡在线视频| 久久精品视频中文字幕| 欧美精品精品精品精品免费| 亚洲欧美视频在线| 国产成人在线一区| 色婷婷亚洲mv天堂mv在影片| 久久影院免费观看| 91久久精品美女高潮| 97精品欧美一区二区三区| 国产精品久久av| 98精品国产自产在线观看| 红桃视频成人在线观看| 日韩视频―中文字幕| www.欧美免费| 91爱爱小视频k| 97视频在线观看免费高清完整版在线观看| 国产美女久久精品| 日韩精品中文字| 韩日欧美一区二区| 91色视频在线观看| 欧美一级在线亚洲天堂| 免费av在线一区| 2019精品视频| 欧美久久久精品| 亚洲国产高清福利视频| 国产激情久久久| 成人黄色影片在线|