Java下的stream程创build过程如何?

在24核的服务器上,我有一个单一的大堆(最多240GB,尽pipe在这个阶段的大部分时间里,在20-40GB的范围内)运行在Linux [2]下的JVM [1]。 我们有成千上万个必须由外部可执行文件处理的对象,然后将由这些可执行文件创build的数据加载回JVM。 每个可执行文件产生约半兆字节的数据(在磁盘上),当读取正确时,在该过程结束之后,当然是更大的。

我们的第一个实现是让每个可执行文件只处理一个对象。 这涉及到产生两倍的可执行文件,因为我们有对象(因为我们调用了一个叫做可执行文件的shell脚本)。 我们的CPU利用率将从高开始,但不一定是100%,并且会慢慢恶化。 当我们开始测量以查看发生了什么事情时,我们注意到过程创build时间[3]不断减慢。 在亚秒时间开始时,最终会花费一分钟或更长的时间。 可执行文件所做的实际处理通常不到10秒钟。

接下来,我们更改可执行文件以获取要处理的对象列表,以减less创build的进程数量。 批量大小为数百(约为我们现有样本量的1%),stream程创build时间约为2秒,增长到5至6秒。

基本上,为什么创build这些stream程需要很长时间才能继续执行?

[1] Oracle JDK 1.6.0_22
[2]红帽企业Linux高级平台5.3,Linux内核2.6.18-194.26.1.el5#1 SMP
[3]创buildProcessBuilder对象,redirect错误stream并启动它。

Solutions Collecting From Web of "Java下的stream程创build过程如何?"

我的猜测是,如果Java使用fork / exec系统调用来产生子进程,你可能会遇到fork / exec的问题。

通常fork / exec是相当高效的,因为fork()做的很少 – 所有页面都是写入时拷贝。 这对于非常大的进程(即映射有千兆字节的那些进程)来说是非常正确的,因为当你立即调用exec的时候,页表本身需要花费相当长的时间来创建 – 当然也会被销毁。

当你使用了大量的堆,这可能会影响你。 您映射的页面越多,可能会变得越糟,这可能是导致渐进式减速的原因。

考虑:

  • 使用posix_spawn,如果这不是由fork / exec在libc中实现的
  • 使用一个负责创建/收割他人的子过程; 产卵一次,并使用一些IPC(管道等)告诉它该怎么做。

注:这是所有的猜测。 你应该做一些实验来看看是否是这样。

很有可能你正在耗尽资源。 当您创建这些进程时,您的磁盘变得越来越忙? 你确保你有更少的进程比你有核心? (为了最小化上下文切换)您的平均负载是否低于24?

如果您的CPU消耗正在下降,您很可能会遇到IO(磁盘/网络)争用,即进程无法快速获取/写入数据以保持繁忙。 如果你有24个核心,你有多少个磁盘?

我建议你每个CPU有一个进程(在你的情况我想象4)给每个JVM六个任务并发运行使用所有的核心,而不会超载系统。

使用一系列长寿命进程将您的数据从队列中取出并发送回去,不断地为每个事件分派新的进程,尤其是从具有巨大堆的主机JVM中获取更好。

分叉240GB的图像不是免费的,即使只有一秒钟,也会消耗大量的虚拟资源。 操作系统并不知道新进程需要多长时间才能知道,因此它必须为整个进程做好准备,这样就可以设置所有240GB的虚拟克隆,然后用exec调用来清除它。

相反,如果你有一个很长的进程,你可以通过一些队列机制来结束对象(Java和C等都有很多),这样可以减轻分叉进程的一些压力。

我不知道如何将数据从JVM传输到外部程序。 但是如果你的外部程序可以使用stdin / stdout,那么(假设你使用的是unix),你可以利用inetd。 在这里,您在进程的inetd配置文件中输入一个简单条目,并为其分配一个端口。 然后你打开一个套接字,把数据倒入它,然后从套接字读回来。 Inetd为你和你的程序处理网络细节,就像使用stdin和stdout一样简单。 请注意,您将在网络上拥有一个开放的套接字,这在您的部署中可能安全也可能不安全。 但是设置甚至遗留代码以通过网络服务运行也是微不足道的。

你可以使用这样一个简单的包装:

#!/bin/sh infile=/tmp/$$.in outfile=/tmp/$$.out cat > $infile /usr/local/bin/process -input $infile -output $outfile cat $outfile rm $infile $outfile 

这不是地球上性能最高的服务器,为数以万计的交易而设计,但肯定要比反复分派240GB更快。

我最赞同彼得。 你最有可能遭受IO瓶颈。 一旦你有可能处理操作系统也必须努力工作,因为琐碎的任务,因此具有指数性能的惩罚。

所以“解决方案”可能是创造“消费者”过程,只是初始化一些“消费者”过程; 因为彼得建议每个CPU或更多。 然后使用某种形式的IPC将这些对象“转移”给消费者流程。

您的“消费者”流程应该管理子流程创建; 我假定你没有任何访问权限的处理可执行文件,这样你就不会使用太多的可执行文件来混淆操作系统,“作业”将会“最终”完成。