简体   繁体   English

Node.js 跨多个磁盘驱动器的文件系统 I/O 性能:工作线程与否?

[英]Node.js performance in file system I/O across multiple disk drives: worker threads or not?

I've read several questions and answers here about the performance benefits of Node.js' ability to performantly handle file I/O operations quickly in a non-blocking way versus using worker threads with either blocking or non-blocking requests, however none seem to answer the question I have.我在这里阅读了几个关于 Node.js 以非阻塞方式快速处理文件 I/O 操作的能力与使用阻塞或非阻塞请求的工作线程相比的性能优势的问题答案,但似乎没有回答我的问题。

I'm writing a Node.js application that will be opening, hashing, and writing very large files (multiple gigs) that are stored on multiple hard drives.我正在编写一个 Node.js 应用程序,它将打开、散列和写入存储在多个硬盘驱动器上的非常大的文件(多个演出)。 I'm exploring the idea of worker threads, as they'd allow me to isolate commands to a particular hard drive.我正在探索工作线程的想法,因为它们允许我将命令隔离到特定的硬盘驱动器。 For example: assume I have a thread handling copying one file on hard drive A to hard drive B, and another thread handling copying one file from hard drive C to hard drive D.例如:假设我有一个线程处理将硬盘 A 上的一个文件复制到硬盘 B,另一个线程处理将一个文件从硬盘 C 复制到硬盘 D。

Assuming I scale this to many more hard drives all at the same time, does it make more sense for me to just use Node.js without worker threads and let it handle all these requests, or does worker threads make more sense if I can isolate I/O by drive, and handle multiple drives' worth of requests at the same time?假设我同时将其扩展到更多的硬盘驱动器,仅使用 Node.js 而不使用工作线程并让它处理所有这些请求对我来说是否更有意义,或者如果我可以隔离 I/ O 按驱动器同时处理多个驱动器的请求?

Given what I've read, worker threads seem like the obvious solution, but I've also seen that just letting the single Node.js process handle a queue of file I/O is generally faster.鉴于我所读到的内容,工作线程似乎是显而易见的解决方案,但我也看到仅让单个 Node.js 进程处理文件 I/O 队列通常会更快。 Thanks for any guidance you can offer!感谢您提供的任何指导!

Edit: Apparently (based on a comment below), nodejs has only one thread pool shared across all the worker threads.编辑:显然(基于下面的评论),nodejs 只有一个线程池在所有工作线程之间共享。 If that's the case, then the only way to get a separate pool per disk would be to use multiple processes, not multiple threads.如果是这种情况,那么为每个磁盘获得一个单独的池的唯一方法是使用多个进程,而不是多个线程。

Or, you could enlarge the worker pool and then make your own queuing system that only puts a couple requests for each separate disk into the worker pool at a time, giving you more parallelism across separate drives.或者,您可以扩大工作池,然后制作自己的排队系统,一次只将对每个单独磁盘的几个请求放入工作池,从而在不同的驱动器之间提供更多的并行性。

Original answer (some of which still applies):原始答案(其中一些仍然适用):

Without worker threads, you will have a single libuv thread pool serving all disk I/O requests.如果没有工作线程,您将只有一个 libuv 线程池来处理所有磁盘 I/O 请求。 So, they will all go into the same pool and once the threads in that pool are busy (regardless of what disk they are serving), new requests will be queued in the order they arrive.因此,它们会将所有 go 放入同一个池中,一旦该池中的线程繁忙(无论它们正在服务哪个磁盘),新请求将按照它们到达的顺序排队。 This is potentially less than ideal because if you have 5 requests for drive A and 1 request for drive B and 1 request for drive C, you would like to not just fill up the pool with 5 requests for drive A first because that will make the requests for drive B and drive C wait until several requests on drive A are done before they can get started.这可能不太理想,因为如果您对驱动器 A 有 5 个请求,对驱动器 B 有 1 个请求,对驱动器 C 有 1 个请求,您不希望首先用对驱动器 A 的 5 个请求填充池,因为这将使驱动器 B 和驱动器 C 的请求等到驱动器 A 上的多个请求完成后,它们才能开始。 This loses some opportunities for some parallelism across the separate drives.这失去了一些跨单独驱动器的并行性的机会。 Of course, whether you truly get parallelism on separate drives also depends upon the drive controller implementation and whether they actually have separate SATA controllers or not.当然,您是否真正在单独的驱动器上获得并行性还取决于驱动器 controller 的实现以及它们是否实际上具有单独的 SATA 控制器。

If you did use worker threads, one nodejs worker thread for each disk, you can at least guarantee that you have a separate pool of OS threads in the thread pool for each disk and you can make it much more likely that no set of requests for one drive will keep the requests for the other drives from getting a chance to start and miss their opportunity to run in parallel with requests to other drives.如果您确实使用了工作线程,每个磁盘一个 nodejs 工作线程,您至少可以保证每个磁盘的线程池中都有一个单独的操作系统线程池,并且更有可能没有一组请求一个驱动器将阻止对其他驱动器的请求有机会启动并错过与对其他驱动器的请求并行运行的机会。

Now, of course, all of this discussion is theoretical.现在,当然,所有这些讨论都是理论上的。 In the world of disk drives, controller cards, operating systems on top of the controllers with libuv on top of that with nodejs on top of that, there are lots of opportunities for the theoretical discussion to not bear out in real world measurements.在磁盘驱动器、controller 卡、控制器之上的操作系统以及 libuv 之上的 nodejs 之上,理论讨论有很多机会无法在现实世界的测量中得到证实。

So, the only way to really know for sure would be to implement the worker thread option and then benchmark compare it to a non-worker thread option with several different disk usage scenarios, including a couple you think might be worst case.因此,真正确定的唯一方法是实施工作线程选项,然后将其与具有多种不同磁盘使用场景的非工作线程选项进行基准比较,包括您认为可能是最坏的情况。 So, as with any important performance-related question, you will inevitably have to benchmark and measure to know for sure one way or the other.因此,与任何与性能相关的重要问题一样,您将不可避免地必须进行基准测试和衡量才能确定其中一种方式。 And, your results will need very careful construction of the benchmark tests too in order to be maximally useful.而且,您的结果也需要非常仔细地构建基准测试才能发挥最大作用。

Just to expand on the per process model, it looks the same as the worker threads suggested by jfriend00 just the IPC mechanism changes.只是为了扩展每个进程 model,它看起来与 jfriend00 建议的工作线程相同,只是 IPC 机制发生了变化。

Manage the job queue from a "head" manager process and split the drive/hashing work into a node process for each worker so there's no IO/CPU contention in each worker.从“头”管理器进程管理作业队列,并将驱动/散列工作拆分为每个工作人员的节点进程,这样每个工作人员就不会发生 IO/CPU 争用。

Have each worker pick up a single job at a time from a work queue for it's drive (or drive group).让每个工作人员一次从其驱动器(或驱动器组)的工作队列中选择一项工作。 All you need is reliability, monitoring for workers that aren't processing and a return channel for worker completion/errors.您所需要的只是可靠性、监控未处理的工作人员以及工作人员完成/错误的返回渠道。

The queuing mechanism doesn't really matter, a database table would suffice (or any type of.network messaging http, grpc, nanomsg, redis, nats, rabbitmq).排队机制并不重要,一个数据库表就足够了(或任何类型的.network messaging http、grpc、nanomsg、redis、nats、rabbitmq)。 This is based on not needing to share a lot of data between the manager and the workers other than a simple job messages "Hey worker, here is a file go process it", "I am done with this file" or "I broke, help!"这是基于除了简单的工作消息“嘿工人,这是一个文件 go 处理它”,“我完成了这个文件”或“我打破了,帮助!”

| Manager                        |
| Pub 1 2 3                      |
| Sub 1    | Sub 2    | Sub 3    |
| Worker   | Worker   | Worker   |
|          |          |          |
| DriveA   | DriveC   | DriveE   |
| DriveB   | DriveD   | DriveF   |

Run a worker per core if the process ends up CPU bound, or as few as you need to manage the IO requirements.如果进程最终受 CPU 限制,或者管理 IO 要求所需的数量,则每个内核运行一个工作程序。 Workers can easily expand as you add drives or more servers.随着您添加驱动器或更多服务器,工作人员可以轻松扩展。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM