我有一个最初在 Axis 1 中设计的 Java SOAP Web 服务,但它不能满足我的性能要求。
我最关心的请求是用于向数据库添加大量(数百万行)数据的请求。在客户端,我将循环遍历文件,并将这些数据推送到我的 Web 服务。每行包含三个元素,因此请求类似于:
<SOAP Envelope/Header/Body>
<AddData>
<Data>
<FirstName>John</FirstName>
<LastName>Smith</LastName>
<Age>42</Age>
</Data>
</AddData>
</SOAP Envelope/Body>
我发现以下性能趋势:
- 当我为每个请求执行一行时,每分钟可以获得大约 720 行。
- 当我将多行封装到单个请求中时,每分钟最多可以获得 2,400 行(每个请求 100 行)。
不幸的是,这种性能无法满足我们的要求,因为我们有数亿行要插入(以每分钟 2,500 行的速度,加载所有数据大约需要 2 个月)。
所以我一直在研究应用程序以了解我们的瓶颈在哪里。每个 100 行请求大约需要 2.5 秒(我尝试了几个不同的服务器并得到类似的结果)。我发现了以下内容:
- 客户端开销可以忽略不计(通过监控我自己的客户端性能和使用 SOAP UI)
- 数据库 Activity 仅占总时间的 10%(0.2 秒)左右,因此 Hibernate 缓存等不会有太大帮助。
- 网络开销可以忽略不计(从客户端到服务器的 ping 时间 <1 毫秒,每个请求发送 <20KB 时获得 >10MB/s 的吞吐量)。
所以这留下了大约 2 秒的时间。我可以指出的这个难题的唯一另一部分是在服务器端反序列化传入请求的开销。我注意到 Axis 2 声称在这方面提高了速度,因此我通过 Axis 2 Web 服务移植了此功能,但没有获得我想要的加速(每个请求的总体时间提高了约 10%)。
我是否低估了反序列化上述 100 个元素所需的时间?我无法想象反序列化可能需要大约 2 秒。
我可以采取什么措施来优化此 Web 应用程序的性能并减少 2 秒的开销?
提前致谢!
========= 第二天.... =========== 情节变得更加复杂......
根据 @millhouse 的建议,我对生产服务器的单行请求进行了更多研究。我发现它们在良好的硬件上可以相当快。因此,我尝试使用 1(1,000 个单独请求)到 1,000(单个请求)之间的增量添加 1,000 行。
- 1 行/请求 - 14.5 秒
- 3/请求 - 5.8 秒
- 5/请求 - 4.5 秒
- 6/请求 - 4.2 秒
- 7/请求 - 287 秒
- 25/请求 - 83 秒
- 100/请求 - 22.4 秒
- 1000/请求 - 4.4 秒
如您所见,每个请求 7 行会增加 2 秒的延迟(与每个请求 6 行相比,每个请求大约会额外增加 2 秒)。我可以一致地重现这一点。较大数量的请求都具有类似的开销,但当每个请求插入 1,000 行时,这种开销变得不那么明显。数据库时间呈线性增长,但与总体请求时间相比仍然可以忽略不计。
因此,我发现使用每个请求 6 行或每个请求数千行可以获得最佳性能。
每个请求 7 行的性能比 6 行低有什么原因吗?该机器有 8 个核心, session 池中有 10 个连接(即我不知道 6 的阈值从何而来)。
最佳答案
大约 5 年前,我使用 Axis2 完成了类似的工作,但恐怕我无法提供任何真正的“ Elixir ”来让它变得更好。我记得我们的服务执行速度是每秒数百,而不是每秒每秒。
我建议要么分析你的请求处理,要么简单地添加大量的日志记录(可能使用周围的许多秒表实现之一来提供详细的计时)并查看什么在使用时间。请求真的需要 2 秒才能通过 Axis 层到达您的代码,还是只是通过许多较小的事情累积?
如果单独单个请求的处理速度很快,但一旦开始加载服务就会陷入困境,请调查应用服务器的线程设置。我似乎记得必须将我的处理分为同步和异步部分(即同步部分执行最低限度的操作以向客户端提供适当的响应,并且在池中的线程中完成繁重的工作),但这可能不适合您的情况。
还要确保构建新的 User
对象(或其他任何对象)不会执行任何过于昂贵的操作(例如从包装 DAO 的服务中获取新 ID,该 ID 会访问速度较慢的数据库服务器,该服务器会运行编写错误的存储过程,从而锁定整个表;-) )
关于java - Axis2 Web 服务延迟的原因,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8796821/