前一段时间,我们已经面临基于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负载平衡和故障转移相关推荐

  1. apache cxf_Apache CXF负载平衡和故障转移

    apache cxf 不久前,我们已经面临了基于Apache CXF的负载平衡Web服务客户端的需求. 此外,当某些服务器关闭时,客户端应自动进行故障转移. 更糟糕的是,服务器目标地址列表要从外部服务 ...

  2. linux 双网卡绑定(bonding)实现负载均衡或故障转移

    linux 双网卡绑定(bonding)实现负载均衡或故障转移 我们在这介绍的Linux双网卡绑定实现就是使用两块网卡虚拟成为一块网卡,这个聚合起来的设备看起来是一个单独的以太网接口设备,通俗点讲就是 ...

  3. 负载均衡和故障转移的使用案例

    负载均衡和故障转移 文章目录 1)需求 2)需求分析 3)前期准备 4)配置文件 5)启动相关命令 6)检验 7)补充 1)需求 ​ 使用 Flume1 监控一个端口,其 sink 组中的 sink ...

  4. 高并发应用场景下的负载均衡与故障转移实践,AgileEAS.NET SOA 负载均衡介绍与实践...

    一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...

  5. oracle查询报错clb,Oracle RAC 负载均衡与故障转移(三)

    Server Service TAF https://www.cndba.cn/Breath/article/2324 服务端 service TAF 1.服务器端透明故障转移,通过配置service ...

  6. was连接oracle rac集群,Oracle 学习之RAC(九) 集群负载均衡及故障转移

    查看监听,使用grid用户 11grac1:11grac1-> lsnrctl status LSNRCTL for Linux: Version 11.2.0.3.0 - Production ...

  7. 故障转移集群仲裁盘_MongoDB负载均衡、故障转移及海量数据应对方案

    概述 下面是mongo的三种集群实施方案 主从复制 主节点对外提供读写服务,从节点定期轮询主节点获取读写操作,并在自己的数据副本执行,保持和主节点的一致性,并对外提供读服务. 优点:有一定负载均衡能力 ...

  8. apache-cxf 使用_使用Apache CXF进行Web服务学习

    apache-cxf 使用 在我的最后几个项目中,我使用了Web服务,在某些地方创建它们并在其他地方使用它们. 我认为标准任务(例如创建客户端,创建Web服务等)非常简单,如果遇到问题,有足够的资源. ...

  9. 使用Apache CXF进行Web服务学习

    在我的最后几个项目中,我使用了Web服务,在某些地方创建它们并在其他地方使用它们. 我觉得创建客户端,创建Web服务等标准任务非常简单,如果遇到问题,有足够的资源. 但是对于Web服务,这是一项琐碎的 ...

最新文章

  1. servlet工作原理_Servlet 生命周期、工作原理
  2. Delphi中文件名函数-路径、名称、子目录、驱动器、扩展名
  3. xshell登录VMware虚拟机的初始设置
  4. python 画三维函数图-Python画三维图-----插值平滑数据
  5. Ubuntu18.04安装百度网盘
  6. 引物的设计及修饰最全教程
  7. 类加载器-双亲委派-源码分析2
  8. when is completed field filled in the backend
  9. pygame里面物体闪烁运动_利用自闪烁发光二极管探究小车在倾斜轨道上的运动规律...
  10. python 水仙花_python 水仙花
  11. Python画等高线以及标注
  12. Asp.net Request方法获取客户端的信息
  13. 谷歌浏览器安装Postman插件 亲测有效!!!
  14. Windows XP 下安装Perl cpan模块
  15. windos读写ext3工具_Windows读写Ext3文件系统
  16. linux桌面监控软件,Ubuntu安装Conky系统监控桌面插件
  17. 支付宝支付验证签名失败
  18. 都说DBA 是越老越值钱, 那你是没干过DBA
  19. pandas爬虫爬取网页表格
  20. 节点表征学习与节点预测和边预测

热门文章

  1. 海域动态监视监测管理系统_监视和管理备份系统
  2. jpa执行sql脚本_JPA persistence.xml SQL脚本定义
  3. lombok 简化代码_如何编写更少,更好的代码,或Project Lombok
  4. 琥珀ai_琥珀项目:Java的未来暴露
  5. twitter自定义api_为Twitter4j创建自定义SpringBoot Starter
  6. 哈希策略_优化哈希策略的简介
  7. ginkgo spi 错误_开发SPI时不要犯这个错误
  8. orm java_Java 8 Friday:不再需要ORM
  9. JAX-RS和OpenAPI对Hypermedia API的支持:任重而道远
  10. q7goodies事例_Java 8 Friday Goodies:java.io终于成功了!