我正在使用 AWS 来托管一些相当繁重的计算机视觉处理,并且遇到了一个很难诊断的问题。
使用 AWS SQS 将图像处理基础架构配置为 Elastic Beanstalk 中的工作实例。SQS 将发布到实例上的节点服务器,该节点服务器将派生一个 Java 子进程。为了进行测试,我将其限制为一次执行一项任务,并且每个任务只能处理一次,因此不必担心多个 Java 进程并行运行。实际软件是使用 Docker 部署的,因此 OpenCV 依赖项易于管理,并且实际上可以以合理的方式派生其他节点。
实际的 Java 代码会将图像加载到内存中,然后执行 100,000 次连续矩阵变换,直到收敛到解决方案。所有数学运算均使用 OpenCV 执行。
软件的配置方式是,所有 FileIO 都发生在开始时,然后直到计算结果为止的其余过程都在内存中。不应将任何内容写入磁盘。
在配置最高的 iMac 上运行该程序大约需要 23 秒,非常快。在性能更强大的 Windows 机器上运行时(根据 CPU 和 GPU 规格),大约需要 12 分钟。在 AWS 中的 m4.xlarge 实例上运行时,大约在 50 时失败。时间对于现在的情况来说并不重要,但对于比较我们正在研究的差异很重要。我们不是在本地编译 OpenCV,而是使用nu.pattern OpenCV使用 Gradle。每个实例都预先安装了依赖项。
当进程失败时,它不会只是崩溃,AWS 中的实例会完全进入最大 ReadOps 状态约一小时。读取队列备份如此之多,以至于实例的整个 IOPS 配额都被消耗殆尽,而我运行的所有其他辅助进程(日志记录、ssh 等)都会立即失败。如果幸运的话,再过一两个小时,ReadOps 就会关闭,然后我就可以进入并提取日志。
此时总是出现同一件事:Node 的 V8 引擎内存不足。
现在我尝试测试一下:
1/我已经测试了 node 的子进程,包括分离 node 进程和 java 进程,以确保内存分配一致(我使用的是 spawn)。我已经使用 iotop 检查了每个进程的内存分配,子进程内存从未计入父进程。(正如预期的那样)此外,由于内存空间是单独计算的,因此更改max_old_space_size
没有影响(正如预期的那样)
2/我在本地运行了 VisualVM 分析,并验证了实际 Java 进程的内存空间从未超过 170 MB。垃圾收集工作正常
3/我已经明确强制执行垃圾收集,以确保对象被释放,并且内存中的矩阵保持较低水平。错误仍然发生。
4/我已经验证了节点上和 docker 实例中的 iotop 操作。在进程运行时,我看到的唯一 IO 来自日志记录和 ext4 日志实用程序。所有这些进程看起来都很正常。
当错误发生时,我失去了与节点的连接。我无法在 AWS 之外重现该问题,也无法确定根本故障点是什么。还有其他可以研究的途径吗?