gpt4 book ai didi

java - 无响应的actor系统: ThreadPoolExecutor dispatcher only creates core thread pool,显然会忽略最大线程池大小

转载 作者:搜寻专家 更新时间:2023-10-31 20:01:25 27 4
gpt4 key购买 nike

更新:我发现如果我将ThreadPoolExecutor's核心池大小设置为与最大池大小相同(29个线程),则程序将保持响应状态。但是,如果我将核心池大小设置为11,最大池大小设置为29,则actor系统将仅创建11个线程。如何配置ActorSystem/ThreadPoolExecutor继续创建线程以超过核心线程数并保持在最大线程数之内?我宁愿不要将核心线程数设置为最大线程数,因为我只需要多余的线程来取消作业(这应该是一个罕见的事件)。

我有一个针对Oracle数据库运行的批处理程序,该程序使用Java/Akka类型的actor和以下actor实现:

  • BatchManager负责与REST Controller 进行对话。它管理未初始化的批处理作业的Queue;当从队列中轮询未初始化的批处理作业时,它将变成JobManager actor并执行。
  • JobManager维护一个存储过程队列和一个Workers池;它使用存储过程初始化每个Worker,当Worker完成后,它将过程的结果发送到JobManager,然后JobManager将另一个存储过程发送到Worker。当作业队列为空且所有Workers都空闲时,该批处理终止,此时JobManager将其结果报告给BatchManager,关闭其工作程序(通过TypedActor.context().stop()),然后关闭自身。 JobManagerPromise<Status> completion在作业成功完成时或在由于取消或致命异常而终止作业时完成。
  • Worker执行存储过程。它创建用于执行存储过程的OracleConnectionCallableStatement,并使用onFailure注册JobManager.completion回调以对连接进行abort并对该语句进行cancel。该回调不使用actor系统的执行上下文,而是使用从在BatchManager中创建的缓存执行器服务创建的执行上下文。

  • 我的配置是
    {"akka" : { "actor" : { "default-dispatcher" : {
    "type" : "Dispatcher",
    "executor" : "default-executor",
    "throughput" : "1",
    "default-executor" : { "fallback" : "thread-pool-executor" }
    "thread-pool-executor" : {
    "keep-alive-time" : "60s",
    "core-pool-size-min" : coreActorCount,
    "core-pool-size-max" : coreActorCount,
    "max-pool-size-min" : maxActorCount,
    "max-pool-size-max" : maxActorCount,
    "task-queue-size" : "-1",
    "task-queue-type" : "linked",
    "allow-core-timeout" : "on"
    }}}}}

    worker 数量在其他位置配置,当前为 workerCount = 8coreActorCountworkerCount + 3,而 maxActorCountworkerCount * 3 + 5。我正在具有两个内核和8GB内存的Macbook Pro 10上对此进行测试;生产服务器要大得多。我正在交谈的数据库位于极慢的VPN后面。我正在使用Oracle的JavaSE 1.8 JVM运行所有这些程序。本地服务器是Tomcat7。OracleJDBC驱动程序是10.2版(我也许可以说服使用较新版本的能力)。所有方法都返回 voidFuture<>,并且应该是非阻塞的。

    当一批成功终止时,就没有问题了-下一批立即开始并有完整的工作人员。但是,如果我通过 JobManager#completion.tryFailure(new CancellationException("Batch cancelled"))终止当前批次,则会触发 onFailure注册的 Workers回调,然后系统将变得无响应。调试printlns表示新批处理从八个正常工作的工作器中的三个开始,并且 BatchManager变得完全无响应(我添加了一个 Future<String> ping命令,该命令仅返回 Futures.successful("ping"),并且也超时)。 onFailure回调在一个单独的线程池上执行,即使它们在actor系统的线程池上,我也应该有足够高的 max-pool-size来容纳原始的 JobManager,其 Workers,其 onFailure回调以及第二个 JobManager,即 Workers。相反,我似乎要容纳原始的 JobManager及其 Workers,新的 JobManager及其不到一半的 Workers,而 BatchManager.则一无所有我正在运行该计算机的计算机上资源不足,但似乎应该能够运行十几个线程。

    这是配置问题吗?这是由于JVM施加的限制和/或Tomcat施加的限制吗?这是因为我处理阻塞IO的方式有问题吗?我可能做错了其他几件事,这些都是我想到的。

    Gist of CancellableStatement,其中 CallableStatementOracleConnection被取消

    Gist of Immutable在其中创建 CancellableStatements
    Gist of JobManager's cleanup code

    通过 System.out.println(mergedConfig.toString());获得的 Config dump

    编辑:我相信我已将问题缩小到参与者系统(它的配置或它与阻止数据库调用的交互)。我消除了 Worker参与者,并将其工作量转移到在固定大小的 Runnables上执行的 ThreadPoolExecutor中,其中每个 JobManager创建自己的 ThreadPoolExecutor并在批处理完成时将其关闭(正常终止时为 shutDown,异常终止时为 shutDownNow)。取消在 BatchManager中实例化的缓存线程池上运行。 actor系统的调度程序仍然是 ThreadPoolExecutor,但仅分配了六个线程。使用此备用设置,取消将按预期执行- worker 在其数据库连接中止时终止,并且新的 JobManager会立即以完全补充的 worker 线程执行。这向我表明这不是硬件/JVM/Tomcat问题。

    更新:我使用 Eclipse's Memory Analyzer进行了线程转储。我发现取消线程卡在 CallableStatement.close()上,因此我对取消进行了重新排序,以便 OracleConnection.abort()CallableStatement.cancel()之前,从而解决了问题-所有取消操作(显然)都正确执行。但是, Worker线程继续卡在语句上-我怀疑我的VPN可能部分或全部归咎于此。
    PerformanceAsync-akka.actor.default-dispatcher-19
    at java.net.SocketInputStream.socketRead0(Ljava/io/FileDescriptor;[BIII)I (Native Method)
    at java.net.SocketInputStream.read([BIII)I (SocketInputStream.java:150)
    at java.net.SocketInputStream.read([BII)I (SocketInputStream.java:121)
    at oracle.net.ns.Packet.receive()V (Unknown Source)
    at oracle.net.ns.DataPacket.receive()V (Unknown Source)
    at oracle.net.ns.NetInputStream.getNextPacket()V (Unknown Source)
    at oracle.net.ns.NetInputStream.read([BII)I (Unknown Source)
    at oracle.net.ns.NetInputStream.read([B)I (Unknown Source)
    at oracle.net.ns.NetInputStream.read()I (Unknown Source)
    at oracle.jdbc.driver.T4CMAREngine.unmarshalUB1()S (T4CMAREngine.java:1109)
    at oracle.jdbc.driver.T4CMAREngine.unmarshalSB1()B (T4CMAREngine.java:1080)
    at oracle.jdbc.driver.T4C8Oall.receive()V (T4C8Oall.java:485)
    at oracle.jdbc.driver.T4CCallableStatement.doOall8(ZZZZ)V (T4CCallableStatement.java:218)
    at oracle.jdbc.driver.T4CCallableStatement.executeForRows(Z)V (T4CCallableStatement.java:971)
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout()V (OracleStatement.java:1192)
    at oracle.jdbc.driver.OraclePreparedStatement.executeInternal()I (OraclePreparedStatement.java:3415)
    at oracle.jdbc.driver.OraclePreparedStatement.execute()Z (OraclePreparedStatement.java:3521)
    at oracle.jdbc.driver.OracleCallableStatement.execute()Z (OracleCallableStatement.java:4612)
    at com.util.CPProcExecutor.execute(Loracle/jdbc/OracleConnection;Ljava/sql/CallableStatement;Lcom/controller/BaseJobRequest;)V (CPProcExecutor.java:57)

    但是,即使在确定了取消订单之后,我仍然遇到问题,即actor系统无法创建足够的线程:在新批次中,我仍然只有八分之三的 worker ,而随着被取消的 worker 的加入,新的 worker 被添加进来了。他们的网络连接超时。总的来说,我有11个线程-我的核心池大小,而29个线程中-我的最大池大小。显然actor系统正在忽略我的最大池大小参数,或者我没有正确配置最大池大小。

    最佳答案

    (免责声明:我不知道Akka)

    通过您的queue-size = -1的以下配置,我想任务队列是不受限制的。

      "task-queue-size": "-1",
    "task-queue-type": "linked"

    除非工作队列已满并且无法排队,否则 ThreadPoolExecutor不会生成超出核心池大小的文件。仅当任务队列已满时,它才会开始生成最大线程数。

    If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing. If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread. If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.



    请检查是否可以解决有限的队列大小,并查看线程是否增加到最大线程数。谢谢。

    关于java - 无响应的actor系统: ThreadPoolExecutor dispatcher only creates core thread pool,显然会忽略最大线程池大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31304603/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com