java cxf 安全_CXF client在并发下的线程安全问题

article/2025/9/13 20:36:10

这个是发生在上周周末的真实案例,因为cxf client 端线程安全导致的错误,总结出来希望其他使用cxf的兄弟注意。

首先描述一下背景,简单的说就是使用cxf作为web service的客户端,运行在weblogic上,连接外部的服务器。为了测试需要,开发了一个简单的模拟器模拟服务器端,准备在release之前跑稳定性测试。

结果出问题了,在排除掉一些干扰和诸如网络环境,设置等之后问题依旧,由于系统负责,包括ws的模拟器也是出了一个之前没有试过的方法,因此费了不少时间来查找问题。过程很枯燥,应该很多人经历过,在一个大的系统中找到一个小错误的出处,可以说是一门学问,技术耐心和运气都是需要的.....跳出这个过程,由于问题表现在web service的网络连接在这个异常上,在服务器端模拟器的日志中有大量的这种异常信息:

2009-07-2419:23:22,898DEBUG (                    :  ) (tomcat-exec-56) [Http11NioProcessor]-Error parsing HTTP request header

java.io.EOFException: Unexpected EOF read on the socket

at org.apache.coyote.http11.InternalNioInputBuffer.readSocket(InternalNioInputBuffer.java:589)

at org.apache.coyote.http11.InternalNioInputBuffer.parseRequestLine(InternalNioInputBuffer.java:425)

at org.apache.coyote.http11.Http11NioProcessor.process(Http11NioProcessor.java:825)

at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:719)

at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:2080)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)

at java.lang.Thread.run(Thread.java:619)2009-07-2419:23:22,898DEBUG (                    :  ) (tomcat-exec-56) [Http11NioProcessor]-Error parsing HTTP request header

java.io.EOFException: Unexpected EOF read on the socket

at org.apache.coyote.http11.InternalNioInputBuffer.readSocket(InternalNioInputBuffer.java:589)

at org.apache.coyote.http11.InternalNioInputBuffer.parseRequestLine(InternalNioInputBuffer.java:425)

at org.apache.coyote.http11.Http11NioProcessor.process(Http11NioProcessor.java:825)

at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:719)

at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:2080)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)

at java.lang.Thread.run(Thread.java:619)

而服务器端模拟器这次是我们第一次使用tomcat和coyote,因此怀疑是tomcat的问题,在再三追查代码无果的情况下,决定换一个服务器端模拟器来确认问题所在:到底是cxf的客户端的问题,还是服务器端模拟器。一个简单的模拟器写出来了,一个跳过所有业务逻辑直接调用cxf客户端实现代码的测试小程序写出来了,测试之后发现,问题依旧。于是将目光集中到cxf的客户端上。

在测试中发现这样一个规律,在上述服务器端的异常发生前,在客户端中总是会有规律的出现下面这个异常:

Jul24,200910:36:18PM org.apache.cxf.phase.PhaseInterceptorChain doIntercept

INFO: Interceptor has thrown exception, unwinding nownulltps=25Exception in thread"Thread-41"2009-07-2422:36:19,925149585[Thread-41] (********Impl.java:459) ERROR junit.framework.Test-Got an exception when invoking****service:javax.xml.ws.WebServiceException: java.lang.NullPointerException

9b8a8a44dd1c74ae49c20a7cd451974e.png

9b8a8a44dd1c74ae49c20a7cd451974e.png(这里的信息是和业务相关的,不方便打出,总之和我们讨论的问题无关)

at test.TestMci.execute(TestMci.java:84)

at test.TestMci.access$1(TestMci.java:81)

at test.TestMci$TestThread.run(TestMci.java:90)

at java.lang.Thread.run(Thread.java:595)

Caused by: javax.xml.ws.WebServiceException: java.lang.NullPointerException

at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:142)

at $Proxy40.authorizeAndPurchase(Unknown Source)

    at*********************9b8a8a44dd1c74ae49c20a7cd451974e.png6more

Caused by: java.lang.NullPointerException

at org.apache.cxf.transport.http.HTTPConduit.prepare(HTTPConduit.java:483)

at org.apache.cxf.interceptor.MessageSenderInterceptor.handleMessage(MessageSenderInterceptor.java:46)

at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:226)

at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:469)

at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:299)

at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:251)

at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)

at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:124)

9b8a8a44dd1c74ae49c20a7cd451974e.png8more

看来问题是出现在这里了。

进一步的测试发现,低压力下比如2-3个工作线程,基本不会有任何问题,因此可以解释为什么功能测试时不出现问题。工作线程加到10个,基本上还算问题,只有极其偶然的会出现一次两次这个异常。进一步加大工作线程,由于受到测试机器的性能限制,10个工作线程和100个工作线程的tps基本相同,都大体在300TPS左右(客户端在笔记本上跑的,cpu已经90%+了)。测试的结果是上面的异常开始变的有规律,恩,非常搞笑的规律,大概每10000次左右的请求就发生一次上述异常,非常的稳定而执着的重现。服了,这么有规律而重现性极好的错误,还真是难得一见........

分析一下问题,在tps基本保持不变的情况下,客户端线程从10增加到100问题就变得明显。因此问题的焦点直指线程安全这个老大难问题,重新审视我们使用cxf的代码,发现有个地方

/*** the server service*/MessagingChannelServiceImplService mcsis=null;/*** the sever service port*/MessagingChannelService mcs=null;

mcsis=newMessagingChannelServiceImplService(serviceWsdlUrl);

mcs=mcsis.getMessagingChannelServiceImplPort();

MessagingChannelService是cxf自动生成的,这个是@WebService,其他的业务代码都是调用它上面的业务方法来实现。由于serviceWsdlUrl不变,因此我们重用了一些东西,避免每次都初始化一次。看来问题出现在这里,试着将代码修改为threadlocal,让每个线程都初始化一次然后保存给自己使用。

修改后的客户端代码在之后的测试中,非常稳定,没有再出现上面的异常,问题算是解决了。

我对cxf不是很熟悉,找了一下也没有找到到底是那里造成的线程不安全,google了一下找到几个地方,但是似乎还不能完全说明问题。先列出来慢慢研究:

1) Are JAX-WS client proxies thread safe?

装载自这里:http://cxf.apache.org/faq.html#FAQ-AreJAXWSclientproxiesthreadsafe%253F

Official JAX-WS answer: No. According to the JAX-WS spec, the client proxies are NOT thread safe. To write portable code, you should treat them as non-thread safe and synchronize access or use a pool of instances or similar.

CXF answer: CXF proxies are thread safe for MANY use cases. The exceptions are:

* Use of ((BindingProvider)proxy).getRequestContext() - per JAX-WS spec, the request context is PER INSTANCE. Thus, anything set there will affect requests on other threads. With CXF, you can do:

((BindingProvider)proxy).getRequestContext().put("thread.local.request.context", "true");

((BindingProvider)proxy).getRequestContext().put("thread.local.request.context", "true");

and future calls to getRequestContext() will use a thread local request context. That allows the request context to be threadsafe. (Note: the response context is always thread local in CXF)

* Settings on the conduit - if you use code or configuration to directly manipulate the conduit (like to set TLS settings or similar), those are not thread safe. The conduit is per-instance and thus those settings would be shared.

* Session support - if you turn on sessions support (see jaxws spec), the session cookie is stored in the conduit. Thus, it would fall into the above rules on conduit settings and thus be shared across threads.

For the conduit issues, you COULD install a new ConduitSelector that uses a thread local or similar. That's a bit complex though.

For most "simple" use cases, you can use CXF proxies on multiple threads. The above outlines the workarounds for the others.

2) cxf的wiki中谈到Client API中的Proxy-based API

wiki 地址: http://cwiki.apache.org/CXF20DOC/jax-rs.html

Limitations

Proxy methods can not have @Context method parameters and subresource methods returning Objects can not be invoked - perhaps it is actually not too bad at all - please inject contexts as field or bean properties and have subresource methods returning typed classes : interfaces, abstract classes or concrete implementations.

Proxies are currently not thread-safe.

3) thread safe issue caused by XMLOutputFactoryImpl

找到的一个cxf的bug,https://issues.apache.org/jira/browse/CXF-2229

Description

Currently CXF calls StaxUtils.getXMLOutputFactory() to get the cached instance of XMLOutputFactoryImpl. But XMLOutputFactoryImpl.createXMLStreamWriter is not thread-safe. See below.

javax.xml.stream.XMLStreamWriter createXMLStreamWriter(javax.xml.transform.stream.StreamResult sr, String encoding)throwsjavax.xml.stream.XMLStreamException {try{if(fReuseInstance&&fStreamWriter!=null&&fStreamWriter.canReuse()&&!fPropertyChanged){

fStreamWriter.reset();

fStreamWriter.setOutput(sr, encoding);if(DEBUG)System.out.println("reusing instance, object id :"+fStreamWriter);returnfStreamWriter;

}returnfStreamWriter=newXMLStreamWriterImpl(sr, encoding,newPropertyManager(fPropertyManager));--thisis not thread safe, since thenewinstance is assigned to the field fStreamWriter first, then it is possible that different threads get the same XMLStreamWriterImpl when they callthismethod at the same time.

}catch(java.io.IOException io){thrownewXMLStreamException(io);

}

}

The solution might be, StaxUtils.getXMLOutputFactory() method creates anewinstance of XMLOutputFactory every time, don't cache it.

posted on 2009-07-27 11:56 sky ao 阅读(6190) 评论(2)  编辑  收藏 所属分类: web service


http://chatgpt.dhexx.cn/article/NdtNSKOS.shtml

相关文章

linux cxf服务端,Apache CXF 框架应用实战

一、概述 Apache CXF提供了用于方便地构建和开发WebService的可靠基础架构。它允许创建高性能和可扩展的服务,可以部署在Tomcat和基于Spring的轻量级容器中,也可以部署在更高级的服务器上,例如Jboss、WebSphere或WebLogic。 CXF提供了以下功能…

使用CXF调用WSDL

简介 时隔多年,再次遇到需要调用WebService的业务,对方给予的wsdl说明文档还是内网的链接,并且设有基础访问权限,即在浏览器打开wsdl链接时需要输入【用户名密码】登录后方可查看wsdl文档,这需要设置代理(我…

spring5.x cxf3.4.x 服务端和客户端 非maven版本

文章目录 一、资料准备1. 官网链接2. 解压3. 依赖梳理 二、spring集成cxf2.1.创建spring项目2.2. 创建接口2.3. impl2.4. spring-cxf.xml2.5. 客户端2.6. 开源项目 一、资料准备 1. 官网链接 http://cxf.apache.org/download.html 下载apache-cxf-3.4.5.zip 2. 解压 3. 依赖…

CXF实现WebService

一、CXF简介 Apache CXF Celtix XFire,开始叫 Apache CeltiXfire,后来更名为 Apache CXF 了,以下简称为 CXF。CXF 继承了 Celtix 和 XFire 两大开源项目的精华,提供了对 JAX-WS 全面的支持,并且提供了多种 Binding …

SpringBoot2 整合 CXF 服务端和客户端

文章目录 一、CXF服务端1. 导入依赖2. 创建service接口3. 接口实现类4. cxf配置类5. 查看wsdl结果 二、CXF客户端2.1. 客户端2.2. 断点调试2.3. 发起调用服务开源源码. 一、CXF服务端 1. 导入依赖 <properties><cxf.version>3.3.1</cxf.version></proper…

CXF客户端乱码

CXF客户端乱码 解决办法一&#xff0c;设置服务端代码&#xff1a; 在使用CXF与其他系统对接时&#xff0c;发现对方系统响应的汉字乱码&#xff0c;使用soapui调用测试就没有问题&#xff0c;但是程序里面调用就乱码&#xff0c;很奇怪&#xff0c;乱码如下&#xff1a; 由…

SpringBoot集成CXF

CXF入门篇https://blog.csdn.net/tongxin_tongmeng/article/details/126482362Server端项目结构 Server端pom.xml <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"…

走进cxf

一、什么是cxf 有很多人认为cxf就是webservice&#xff0c;其实cxf只是发布调用webservice的工具而已 Apache CXF Celtix Xfire&#xff0c;开始叫 Apache CeltiXfire&#xff0c;后来更名为 Apache CXF 了&#xff0c;以下简称为 CXF。Apache CXF 是一个开源的 web Service…

NewSQL ---- Mysql.8.0 与 MemSQL 7.0 大数据量查询性能对比

目录 1测试环境以及测试用例设计 1.1测试环境 1.2测试用例设计 2 千万级数据量性能测试对比 2.1 MemSQL时间范围分页查询 2.1.1 性能测试数据 2.2任务信息查询 2.2.1 性能测试数据 2.3 执行批次范围查询 2.3.1 性能测试数据 2.4 批次任务查询 2.4.1 性能测试数据 …

memsql架构2

接上次的MemSQL分布式架构介绍(一)&#xff0c;原文在这里&#xff1a;http://docs.memsql.com/latest/concepts/distributed_architecture/ 首先上张图&#xff0c;是我根据自己的理解画的&#xff0c;如有错误还请大家指出 几个概念 1、MemSQL有两种类型的表&#xff1a; ref…

MemSQL性能测试结果

1.查询的SQL select count(subie.user_id) as count from sum_user_basic_info_exp subie join sum_user_lend_info_exp sulie on sulie.user_idsubie.user_id where subie.curr_user_role_cd1 and subie.reg_dt >2016-08-29 and subie.reg_dt <2016-08-29 结…

【MySQL】SQL优化

SQL优化 1 插入数据 1.1 insert优化 如果我们需要一次性往数据库表中插入多条记录&#xff0c;可以从以下三个方面进行优化。 insert into tb_test values(1,tom); insert into tb_test values(2,cat); insert into tb_test values(3,jerry); .....1.批量插入数据 Insert…

MySQL慢SQL探究

文章目录 前言1、慢SQL捕获慢查询追踪配置方式 2、情况分析为什么查询会慢&#xff1f; 2.1 SQL执行计划分析explain执行计划分析PROFILE分析OPTIMIZER_TRACE分析 3、引擎参数配置分析I/O性能分析MySQL I/O参数 其他原因分析网络抖动单表数据量过大 总结 前言 我们在日常开发中…

【Mysql】SQL性能分析

【Mysql】SQL性能分析 文章目录 【Mysql】SQL性能分析1. SQL执行频率2. 慢查询日志3. profile详情4. explain 1. SQL执行频率 在控制台中通过命令 show [session|global] status 命令可以提供服务器状态信息。通过如下指令&#xff0c;可以查看当前数据库的 insert,update,del…

MemSQL可以为时间序列应用做些什么

版权声明&#xff1a;本文由腾讯云数据库产品团队整理&#xff0c;页面原始内容来自于db weekly英文官网&#xff0c;若转载请注明出处。翻译目的在于传递更多全球最新数据库领域相关信息&#xff0c;并不意味着腾讯云数据库产品团队赞同其观点或证实其内容的真实性。如果其他媒…

MySQL-SQL优化

文章目录 一、插入数据1、insert2、大批量插入数据 二、主键优化&#xff08;1&#xff09;数据组织方式&#xff08;2&#xff09;页分裂&#xff08;3&#xff09;页合并&#xff08;4&#xff09;索引设计原则 三、order by优化四、group by优化五、limit优化六、count优化1…

每秒1.28万亿行,最快的分布式关系数据库MemSQL又破记录了!

众所周知&#xff0c;如果交互式响应时间小于四分之一秒&#xff0c;那么人们会获得令人难以置信的满意度。当你提供的响应时间下降到大约四分之一秒时&#xff0c;交互对用户而言是即时的。 但是&#xff0c;由于大数据集和并发需求&#xff0c;给所有客户提供的速度水平似乎…

速度最快的数据库---MEMSQL的安装与部署

1. 什么是MEMSQL 前Facebook工程师创办的MemSQL公司获500万美元投资。号称世界上最快的分布式关系型数据库&#xff0c;兼容MySQL但快30倍&#xff0c;能实现每秒150万次事务。原理是仅用内存并将SQL预编译为C。2012年12月14&#xff0c;MemSQL 1.8 发布&#xff0c;号称最快的…

memsql-官宣世界最快的内存关系型数据库安装部署

官网地址&#xff1a;https://www.memsql.com/ 获取到的license:BGNhZmY4YjViM2Y1OTRhOTdiOTNlNTE0NmU3MGJhN2NlAAAAAAAAAAAEAAAAAAAAAAwwNAIYJLLETZcXn8NHKfJAS/Iai5hUjzaCMQ5PAhht2vDZAS1q1a49DPsq5gMGKY9AI0wmaSkAAA 1&#xff0c;memsql官网介绍 MemSQL 是一个分布式关系数…

memSQL简介

前言 由前Facebook工程师创办的MemSQL&#xff0c;号称世界上最快的分布式关系型数据库&#xff0c;兼容MySQL但快30倍&#xff0c;能实现每秒150万次事务。原理是仅用内存并将SQL预编译为C。 MemSQL 提供免费的开发者版本&#xff08;数据限制32G&#xff09;和全功能试用版…