即使ECS AWS上有许多可用内核,Runtime.getRuntime()。availableProcessors()仍返回1

时间:2019-04-09 15:54:13

标签: java docker amazon-ecs

我正在通过AWS的ECS上的Docker运行任务。该任务执行一些受CPU限制的计算,我想并行运行这些计算。我以Runtime.getRuntime().availableProcessors()中指定的线程数启动线程池,该线程池在PC上本地运行良好。出于某种原因,在AWS ECS上,即使有多个可用核心,该值始终返回1。因此,我的计算是按顺序进行的,并且没有使用多核。

例如,现在,我有一个任务在“ t3.medium”实例上运行,根据docs,该实例应具有2个内核。

当我执行以下代码时:

System.out.println("Java reports " + 
    Runtime.getRuntime().availableProcessors() + " cores");

然后在日志上显示以下内容:

Java reports 1 cores

我没有在ECS的任务定义中指定cpu参数。我在ECS管理控制台中的任务列表中看到它的“ CPU”列显示为0。我还注意到,在实例(= VM)列表中,它将“ CPU可用”列为2048,这大概与VM具有2个内核这一事实有关。

我希望我的Java程序能够看到VM必须提供的所有内核。 (通常,Java程序在没有Docker的计算机上运行时就是这种情况。)

我该怎么做?

1 个答案:

答案 0 :(得分:0)

感谢@stdunbar在评论中指出我的正确方向。

编辑:感谢@Imran的评论。如果您启动大量线程,则绝对会将它们调度到多个内核。这个答案只是关于让Runtime.getRuntime().availableProcessors()返回正确的值。许多“线程池”启动的线程数量与该方法返回的数量一样:它应该返回可用内核的数量。

似乎有两个主要解决方案,但这两个都不是理想的解决方案:

  • 在任务定义中设置cpu参数。例如,如果您有2个核心并且要同时使用它们,则必须在任务的定义中设置"cpu":2048。这不是很方便,原因有两个:

    • 如果选择更大的实例,则必须确保更新此参数。

    • 如果您希望同时运行两个任务,而这两个任务都可以偶尔使用所有内核进行短期活动,则AWS不会在具有"cpu":2048的2内核系统上安排两个任务。从CPU的角度来看,虚拟机已“满”。这违背了分担工作(Unix等)原则的每个任务都按需完成的工作(例如,想象一下在台式机上,如果您在双核计算机上运行Word和Excel,而Windows不允许您启动其他任何任务,因为Word 可能都需要一个核心,而Excel 可能也需要,所以如果另一个程序 可能需要全部同时没有足够的核心。)

  • 按照here所述,在JDK 10及更高版本中使用-XX:ActiveProcessorCount=xx JVM选项。这不方便,因为:

    • 如上所述,如果更改实例类型,则必须更改该值。

我写了更长的博客文章,描述了我的发现:https://www.databasesandlife.com/java-docker-aws-ecs-multicore/