Skip to content

Commit 449549b

Browse files
sam-githubMylesBorins
authored andcommitted
doc: threadpool size, and APIs using the pool
Not knowing which APIs use libuv's threadpool can lead to surprising performance problems. Document the APIs, and also document UV_THREADPOOL_SIZE, which can be used to fix problems. PR-URL: #14995 Reviewed-By: Brian White <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 6bb8133 commit 449549b

File tree

5 files changed

+66
-9
lines changed

5 files changed

+66
-9
lines changed

doc/api/cli.md

+25
Original file line numberDiff line numberDiff line change
@@ -568,10 +568,35 @@ appended to if it does. If an error occurs while attempting to write the
568568
warning to the file, the warning will be written to stderr instead. This is
569569
equivalent to using the `--redirect-warnings=file` command-line flag.
570570

571+
### `UV_THREADPOOL_SIZE=size`
572+
573+
Set the number of threads used in libuv's threadpool to `size` threads.
574+
575+
Asynchronous system APIs are used by Node.js whenever possible, but where they
576+
do not exist, libuv's threadpool is used to create asynchronous node APIs based
577+
on synchronous system APIs. Node.js APIs that use the threadpool are:
578+
579+
- all `fs` APIs, other than the file watcher APIs and those that are explicitly
580+
synchronous
581+
- `crypto.pbkdf2()`
582+
- `crypto.randomBytes()`, unless it is used without a callback
583+
- `crypto.randomFill()`
584+
- `dns.lookup()`
585+
- all `zlib` APIs, other than those that are explicitly synchronous
586+
587+
Because libuv's threadpool has a fixed size, it means that if for whatever
588+
reason any of these APIs takes a long time, other (seemingly unrelated) APIs
589+
that run in libuv's threadpool will experience degraded performance. In order to
590+
mitigate this issue, one potential solution is to increase the size of libuv's
591+
threadpool by setting the `'UV_THREADPOOL_SIZE'` environment variable to a value
592+
greater than `4` (its current default value). For more information, see the
593+
[libuv threadpool documentation][].
594+
571595
[`--openssl-config`]: #cli_openssl_config_file
572596
[Buffer]: buffer.html#buffer_buffer
573597
[Chrome Debugging Protocol]: https://chromedevtools.github.io/debugger-protocol-viewer
574598
[REPL]: repl.html
575599
[SlowBuffer]: buffer.html#buffer_class_slowbuffer
576600
[debugger]: debugger.html
577601
[emit_warning]: process.html#process_process_emitwarning_warning_type_code_ctor
602+
[libuv threadpool documentation]: http://docs.libuv.org/en/latest/threadpool.html

doc/api/crypto.md

+13
Original file line numberDiff line numberDiff line change
@@ -1555,6 +1555,10 @@ crypto.pbkdf2('secret', 'salt', 100000, 512, 'sha512', (err, derivedKey) => {
15551555
An array of supported digest functions can be retrieved using
15561556
[`crypto.getHashes()`][].
15571557

1558+
Note that this API uses libuv's threadpool, which can have surprising and
1559+
negative performance implications for some applications, see the
1560+
[`UV_THREADPOOL_SIZE`][] documentation for more information.
1561+
15581562
### crypto.pbkdf2Sync(password, salt, iterations, keylen, digest)
15591563
<!-- YAML
15601564
added: v0.9.3
@@ -1719,6 +1723,10 @@ This should normally never take longer than a few milliseconds. The only time
17191723
when generating the random bytes may conceivably block for a longer period of
17201724
time is right after boot, when the whole system is still low on entropy.
17211725

1726+
Note that this API uses libuv's threadpool, which can have surprising and
1727+
negative performance implications for some applications, see the
1728+
[`UV_THREADPOOL_SIZE`][] documentation for more information.
1729+
17221730
### crypto.randomFillSync(buffer[, offset][, size])
17231731
<!-- YAML
17241732
added: v7.10.0
@@ -1779,6 +1787,10 @@ crypto.randomFill(buf, 5, 5, (err, buf) => {
17791787
});
17801788
```
17811789

1790+
Note that this API uses libuv's threadpool, which can have surprising and
1791+
negative performance implications for some applications, see the
1792+
[`UV_THREADPOOL_SIZE`][] documentation for more information.
1793+
17821794
### crypto.setEngine(engine[, flags])
17831795
<!-- YAML
17841796
added: v0.11.11
@@ -2204,6 +2216,7 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL.
22042216

22052217
[`Buffer`]: buffer.html
22062218
[`EVP_BytesToKey`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_BytesToKey.html
2219+
[`UV_THREADPOOL_SIZE`]: cli.html#cli_uv_threadpool_size_size
22072220
[`cipher.final()`]: #crypto_cipher_final_outputencoding
22082221
[`cipher.update()`]: #crypto_cipher_update_data_inputencoding_outputencoding
22092222
[`crypto.createCipher()`]: #crypto_crypto_createcipher_algorithm_password

doc/api/dns.md

+13-9
Original file line numberDiff line numberDiff line change
@@ -620,15 +620,16 @@ but note that changing these files will change the behavior of _all other
620620
programs running on the same operating system_.
621621

622622
Though the call to `dns.lookup()` will be asynchronous from JavaScript's
623-
perspective, it is implemented as a synchronous call to getaddrinfo(3) that
624-
runs on libuv's threadpool. Because libuv's threadpool has a fixed size, it
625-
means that if for whatever reason the call to getaddrinfo(3) takes a long
626-
time, other operations that could run on libuv's threadpool (such as filesystem
627-
operations) will experience degraded performance. In order to mitigate this
628-
issue, one potential solution is to increase the size of libuv's threadpool by
629-
setting the `'UV_THREADPOOL_SIZE'` environment variable to a value greater than
630-
`4` (its current default value). For more information on libuv's threadpool, see
631-
[the official libuv documentation][].
623+
perspective, it is implemented as a synchronous call to getaddrinfo(3) that runs
624+
on libuv's threadpool. This can have surprising negative performance
625+
implications for some applications, see the [`UV_THREADPOOL_SIZE`][]
626+
documentation for more information.
627+
628+
Note that various networking APIs will call `dns.lookup()` internally to resolve
629+
host names. If that is an issue, consider resolving the hostname to and address
630+
using `dns.resolve()` and using the address instead of a host name. Also, some
631+
networking APIs (such as [`socket.connect()`][] and [`dgram.createSocket()`][])
632+
allow the default resolver, `dns.lookup()`, to be replaced.
632633

633634
### `dns.resolve()`, `dns.resolve*()` and `dns.reverse()`
634635

@@ -644,6 +645,8 @@ They do not use the same set of configuration files than what [`dns.lookup()`][]
644645
uses. For instance, _they do not use the configuration from `/etc/hosts`_.
645646

646647
[`Error`]: errors.html#errors_class_error
648+
[`UV_THREADPOOL_SIZE`]: cli.html#cli_uv_threadpool_size_size
649+
[`dgram.createSocket()`]: dgram.html#dgram_dgram_createsocket_options_callback
647650
[`dns.getServers()`]: #dns_dns_getservers
648651
[`dns.lookup()`]: #dns_dns_lookup_hostname_options_callback
649652
[`dns.resolve()`]: #dns_dns_resolve_hostname_rrtype_callback
@@ -660,6 +663,7 @@ uses. For instance, _they do not use the configuration from `/etc/hosts`_.
660663
[`dns.resolveTxt()`]: #dns_dns_resolvetxt_hostname_callback
661664
[`dns.reverse()`]: #dns_dns_reverse_ip_callback
662665
[`dns.setServers()`]: #dns_dns_setservers_servers
666+
[`socket.connect()`]: net.html#net_socket_connect_options_connectlistener
663667
[`util.promisify()`]: util.html#util_util_promisify_original
664668
[DNS error codes]: #dns_error_codes
665669
[Implementation considerations section]: #dns_implementation_considerations

doc/api/fs.md

+8
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ example `fs.readdirSync('c:\\')` can potentially return a different result than
100100
`fs.readdirSync('c:')`. For more information, see
101101
[this MSDN page][MSDN-Rel-Path].
102102

103+
## Threadpool Usage
104+
105+
Note that all file system APIs except `fs.FSWatcher()` and those that are
106+
explicitly synchronous use libuv's threadpool, which can have surprising and
107+
negative performance implications for some applications, see the
108+
[`UV_THREADPOOL_SIZE`][] documentation for more information.
109+
103110
## WHATWG URL object support
104111
<!-- YAML
105112
added: v7.6.0
@@ -2845,6 +2852,7 @@ The following constants are meant for use with the [`fs.Stats`][] object's
28452852
[`ReadDirectoryChangesW`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365465%28v=vs.85%29.aspx
28462853
[`ReadStream`]: #fs_class_fs_readstream
28472854
[`URL`]: url.html#url_the_whatwg_url_api
2855+
[`UV_THREADPOOL_SIZE`]: cli.html#cli_uv_threadpool_size_size
28482856
[`WriteStream`]: #fs_class_fs_writestream
28492857
[`event ports`]: http://illumos.org/man/port_create
28502858
[`fs.FSWatcher`]: #fs_class_fs_fswatcher

doc/api/zlib.md

+7
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ zlib.unzip(buffer, (err, buffer) => {
4343
});
4444
```
4545

46+
## Threadpool Usage
47+
48+
Note that all zlib APIs except those that are explicitly synchronous use libuv's
49+
threadpool, which can have surprising and negative performance implications for
50+
some applications, see the [`UV_THREADPOOL_SIZE`][] documentation for more
51+
information.
52+
4653
## Compressing HTTP requests and responses
4754

4855
The `zlib` module can be used to implement support for the `gzip` and `deflate`

0 commit comments

Comments
 (0)