为什么我在 WSO2 ESB 应用程序中执行大量 HTTP POST 请求(针对 Web 服务)时会遇到这些问题?

Why I am incurring in these problems performing a lot of HTTP POST request (toward a web service) in a WSO2 ESB application?

我是 WSO2 的新手,遇到以下问题。

我正在开发一个实现以下任务的 ESB 应用程序:

  1. 在本地数据库上执行一些 DSS 查询。
  2. 使用检索到的数据构建一些 XML 文档。
  3. 将所有这些文档发送到远程 Web 服务(在 PHP 中实现)。
  4. 获取 Web 服务响应(针对所有请求的特定响应,其中包含其中一个生成的 XML 文档)并使用其内容在先前的本地数据库中存储一个值。

Web 服务接收上一个包含 XML 文档的请求,将文档内容存储在另一个数据库中。

我已经实现了这个 ESB 应用程序,它似乎可以使用以下逻辑工作(但我发现了一些我稍后会解释的问题):

我创建了一个 API,其中包含一个 in sequence 来执行查询,构建 XML文档,将这些文档发送到 Web 服务,像这样(我不能 post 整个代码,因为 XML 创建逻辑相当大):

<?xml version="1.0" encoding="UTF-8"?>
<api context="/glisTest2" name="glisTest2" xmlns="http://ws.apache.org/ns/synapse">
    <resource methods="GET" outSequence="glisOutSequence">
        <inSequence>
            <payloadFactory media-type="xml">
                <format>
                    <body/>
                </format>
                <args/>
            </payloadFactory>
            <header name="Action" scope="default" value="urn:FindNotProcessed"/>
            <log level="full"/>
            <callout endpointKey="prgfasEndpoint">
                <source xmlns:ns="http://org.apache.synapse/xsd" xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s12="http://www.w3.org/2003/05/soap-envelope" xpath="s11:Body/child::*[fn:position()=1] | s12:Body/child::*[fn:position()=1]"/>
                <target xmlns:ns="http://org.apache.synapse/xsd" xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s12="http://www.w3.org/2003/05/soap-envelope" xpath="s11:Body/child::*[fn:position()=1] | s12:Body/child::*[fn:position()=1]"/>
            </callout>
            <log level="full"/>
            <property expression="count(//ds:Sample)" name="total_samples" scope="default" type="STRING" xmlns:ds="http://ws.wso2.org/dataservice"/>
            <log level="custom">
                <property expression="$ctx:total_samples" name="total samples: "/>
            </log>
            <!-- Iterate throug samples -->
            <iterate expression="$body//ds:Sample" id="ITR_AGG" sequential="true" xmlns:ds="http://ws.wso2.org/dataservice">
                <target sequence="sampleDataSequence"/>
                <!-- This is my main sequence. It will call some other sequece in cascade: -->
            </iterate>
        </inSequence>
        <faultSequence/>
    </resource>
</api>

callout调解器用于调用DSS服务进行查询获取数据

现在这段代码:

<!-- Iterate throug samples -->
<iterate expression="$body//ds:Sample" id="ITR_AGG" xmlns:ds="http://ws.wso2.org/dataservice">
    <target sequence="sampleDataSequence"/>
</iterate>

我正在对每个检索到的元素进行迭代,对于每个元素,我基本上都会构建一个 XML 并将其发送到远程 Web 服务。所有这些逻辑(相当大,因为 XML 文档包含许多字段)都包含在 sampleDataSequence 序列中(这个序列将在每次迭代中执行以构建和发送一个 XML 文件).

我没有附上整个代码,在 sampleDataSequence 序列的末尾我执行了网络服务调用(POST request) 将当前 XML 文档(在当前迭代中生成)传递给它,以这种方式(之前我将当前 XML 文档放在正文请求中):

<property name="messageType" scope="axis2" type="STRING" value="application/xml"/>
<property name="HTTP_METHOD" scope="axis2" type="STRING" value="post"/>
<send>
    <endpoint key="glisEndpoint"/>
</send>

因此,对于每次迭代,我都会构建一个全新的 XML 文档并将其发送到我的 Web 服务(这有效,Web 服务会接收它)。

所以 in sequence 结束,然后是 out sequence 接收和收集所有 web 服务响应,然后它可以一个一个解析这些响应并在我的本地数据库上将记录写入 result table。

我是这样做的:

<?xml version="1.0" encoding="UTF-8"?>
<sequence name="glisOutSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
    <aggregate id="ITR_AGG">
        <completeCondition>
            <messageCount max="-1" min="-1"/>
        </completeCondition>
        <onComplete expression="s11:Body/child::*[position()=1] | s12:Body/child::*[position()=1]" xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s12="http://www.w3.org/2003/05/soap-envelope">
            <property name="it_count" scope="operation" type="STRING" value="0"/>
            <!-- Iterate over responses. For correct count calculations they should 
                be sequential -->
            <iterate expression="$body//response" id="ITR_RES" sequential="true">
    </aggregate>
    <log level="custom">
        <property expression="$body" name="AT THE END"/>
    </log>
    <send/>
</sequence>

所以基本上我使用的是 WSO2 ESB 提供的 2 Enterprise Integration PatternSplitterAggregator来完成这个任务。在我看来,这应该是此类任务的标准解决方案(当您必须向外部 Web 服务发送 n 条消息,然后收集并操作来自该 Web 服务的 n 条响应时)。我的架构是此类任务的标准架构吗?

我问这个是因为现在我发现了以下问题:

我已经在测试环境中部署了这个应用程序,我们遇到了以下问题。

测试环境将这​​个WSO2 ESB应用程序和联系的网络服务安装在同一台笔记本电脑上(但在生产环境中,这些系统将在不同的计算机上,因为有将有许多 WSO2 ESB 应用程序和一个中央 Web 服务,它将从这些 ESB 应用程序接收消息。

问题是 WSO2 应用程序生成了大量 XML 文档(大约 1000 个)。因此它将对 Web 服务执行 1000 个连续的 POST 请求。 Web 服务接收所有这些请求(包含必须插入另一个数据库的 1000 XML 文档)但在插入一定数量的数据库后,数据库 (Postgree)给一个太多客户异常

所以此异常可能与:连接未关闭、结果集未关闭或类似情况有关。

我个人的看法(可能是错误的)是,这应该是与 Web 服务后端相关的问题,而不是与我的 WSO2 ESB 应用程序相关的问题。但是测试它的人对我说,也许 WSO2 应用程序没有关闭连接。

我觉得很奇怪,因为它是 DB 上的错误而不是 Web 服务上的错误,但我真的不知道。

另一件事是我解决了这个问题,在将 POST 请求发送到 Web 服务之前延迟了几毫秒,这样:

<!-- Inserted a short delay to prevent flooding the GLIS server -->
<script language="js">java.lang.Thread.sleep(200);</script>

<property name="messageType" scope="axis2" type="STRING" value="application/xml"/>
<property name="HTTP_METHOD" scope="axis2" type="STRING" value="post"/>
<property name="ClientApiNonBlocking" value="true" scope="axis2" action="remove"/>
<send>
    <endpoint key="glisEndpoint"/>
</send

在发送请求之前进行短暂的延迟似乎工作正常。我的想法是,也许问题是在这个测试环境中 ESB 应用程序和 web 服务应用程序 安装在同一台笔记本电脑上,所以通信非常非常快(中间没有网络)所以 ESB 应用程序很快发出 1000 个请求,Web 服务可以接收它但不能写入数据库。

可能是问题所在?

另一个疑问是:测试应用程序的人对我说,也许我使用了错误的企业集成模式来实现此任务,我应该执行 Web 服务调用并逐一详细说明响应(对于每个XML 文档)。在我个人看来,使用 ESB 逻辑这应该是不可能的,因为如果我向 Web 服务发送一个 XML,当它给我一个响应时,ESB 在 out 序列 中输入并且因此 ESB 应用程序将在处理单个文档后结束(因为我认为在完成输出序列后我无法返回到输入序列)。我的推理对吗?

因此,最后:可能是测试环境的问题(同一台PC上的两个应用程序),或者PHP web服务后端应用程序的问题(结果集未关闭或其他像这样,这看起来很奇怪,因为使用延迟它有效)或者可能与我的 ESB 应用程序有关?

我个人的意见 - 我没有看到 "not closing connections" 从 WSO2 方面如何(作为 PHP-服务的客户端) PHP 和数据库之间可能会出现产品问题。

我没有看到集成模式有任何问题,您在您的解决方案中使用了 - 一切看起来都很好。

所以,我认为 PHP 网络服务中的问题或者它在本地测试笔记本电脑上的特定配置。

例如java-应用程序总是使用连接池来获取数据库连接- 这个连接池的设置可以控制到数据库的连接数。 不确定 - 但可能 PHP 也有某种连接池。

此外,数据库通常有很多关于同时可能的连接数的选项。

所以 - 可能一切都在生产系统中正确配置,但在测试笔记本电脑中配置 "by default", 所以 - 结果我们遇到了这种问题。

无论如何 - 我们遇到的情况是调用的服务有一些特定的 SLA - 例如它可以同时接受的连接数。 此外,它看起来可能会发生此服务可能不可用或 return 错误(例如由于数据库连接问题)。

你的 JS 延迟是非常肮脏的解决方案 - WSO2 ESB(与任何其他 ESB 一样)有更好的解决方案 - 称为“Guaranteed Delivery”。

在WSO2中,它可以通过以下方式实现:而不是将消息发送到glisEndpoint,你应该将它放入 Message Store。 然后你需要配置 Message Processor : 它将从消息存储中获取消息并发送到端点。 如果调用端点失败(由于某种原因) - 它会将消息放回消息存储。 消息处理器中有许多配置选项 - 因此,您可以配置例如每秒仅发送 1 条消息,或任何其他模式。

请记住 - 消息存储有多种类型:从最简单的内存消息存储开始,到使用 ActiveMQ 或 RabbitMQ 结束。 您应该根据您的要求选择合适的消息存储类型。