Title: HTTP2 download of parallel requests is slower than HTTP1.1 · Issue #54874 · nodejs/node · GitHub
Open Graph Title: HTTP2 download of parallel requests is slower than HTTP1.1 · Issue #54874 · nodejs/node
X Title: HTTP2 download of parallel requests is slower than HTTP1.1 · Issue #54874 · nodejs/node
Description: Version v20.17.0 Platform MacOS Sonoma 14.5, 2,3 GHz Quad-Core Intel Core i7 Subsystem No response What steps will reproduce the bug? Define an http2 and http1.1 clients and fetch some data in parallel. You can use the script below. If y...
Open Graph Description: Version v20.17.0 Platform MacOS Sonoma 14.5, 2,3 GHz Quad-Core Intel Core i7 Subsystem No response What steps will reproduce the bug? Define an http2 and http1.1 clients and fetch some data in para...
X Description: Version v20.17.0 Platform MacOS Sonoma 14.5, 2,3 GHz Quad-Core Intel Core i7 Subsystem No response What steps will reproduce the bug? Define an http2 and http1.1 clients and fetch some data in para...
Opengraph URL: https://github.com/nodejs/node/issues/54874
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"HTTP2 download of parallel requests is slower than HTTP1.1","articleBody":"### Version\r\n\r\nv20.17.0\r\n\r\n### Platform\r\n\r\n```text\r\nMacOS Sonoma 14.5, 2,3 GHz Quad-Core Intel Core i7\r\n```\r\n\r\n\r\n### Subsystem\r\n\r\n_No response_\r\n\r\n### What steps will reproduce the bug?\r\n\r\nDefine an http2 and http1.1 clients and fetch some data in parallel.\r\n\r\nYou can use the script below. If you run it using the following command, it will send 25 parallel requests using HTTP1.1\r\n```sh\r\nnode client.js\r\n```\r\n\r\nor you can run this command and it will send 25 parallel requests using HTTP2:\r\n```sh\r\nnode client.js http2\r\n```\r\n\r\n\u003cdetails>\r\n\u003csummary>client.js\u003c/summary>\r\n\u003cp>\r\n\r\n\r\n\r\n\r\n\r\n```javascript\r\nimport http2 from 'node:http2';\r\nimport https from 'node:https';\r\n\r\nconst isHttp2 = process.argv[2] === 'http2';\r\n\r\nconst MB = 1024 * 1024;\r\nconst WINDOW_SIZE = 32 * MB;\r\n\r\nconst url = new URL('https://nodejs.org/dist/v17.1.0/node-v17.1.0-x64.msi');\r\n\r\nconst client = http2.connect(url, {\r\n settings: {\r\n initialWindowSize: WINDOW_SIZE,\r\n },\r\n});\r\n\r\nclient.on('connect', () => {\r\n client.setLocalWindowSize(WINDOW_SIZE);\r\n});\r\n\r\nconst fetchHttp1 = (id) => {\r\n return new Promise((resolve) => {\r\n const req = https.request({\r\n host: url.host,\r\n path: url.pathname,\r\n headers: {\r\n connection: 'keep-alive',\r\n },\r\n }, (res) => {\r\n res.on('data', () => {});\r\n res.on('end', () => {\r\n console.log(`Complete request with id: ${id}`);\r\n resolve();\r\n });\r\n },\r\n );\r\n\r\n req.end();\r\n });\r\n};\r\n\r\nconst fetchHttp2 = (id) => {\r\n return new Promise((resolve) => {\r\n const req = client.request({\r\n ':path': url.pathname,\r\n });\r\n req.on('data', () => {});\r\n req.on('end', () => {\r\n console.log(`Complete request with id: ${id}`);\r\n resolve();\r\n });\r\n req.end();\r\n });\r\n};\r\n\r\nconst main = async () => {\r\n console.log(`Starting requests using HTTP${isHttp2 ? '2' : '1.1'} protocol.`);\r\n\r\n const startTime = Date.now();\r\n\r\n await Promise.all(\r\n Array.from({ length: 25 })\r\n .fill(null)\r\n .map((_, index) => isHttp2 ? fetchHttp2(index) : fetchHttp1(index)),\r\n );\r\n\r\n console.log(`Requests complete. Completion time: ${(Date.now() - startTime) / 1000}s`);\r\n};\r\n\r\nmain();\r\n``` \r\n\r\n\r\n\r\n\r\n\u003c/p>\r\n\u003c/details> \r\n\r\n\r\n### How often does it reproduce? Is there a required condition?\r\n\r\nIt's not quite stable, because sometimes http2 has the same performance or even better performance.\r\n\r\n### What is the expected behavior? Why is that the expected behavior?\r\n\r\nI expect http2 to be faster or at least have the same performance as http1.1.\r\n\r\n### What do you see instead?\r\n\r\nInstead, I often see that http1.1 requests are faster. Most of the times http2 took 25s to complete while http1.1 took 20s.\r\n\r\nThere's a problem, though, because those results are not consistent when using the URL I provided in the example. \r\n\r\nBut, the results are consistent with some internal APIs I'm working with. First, I thought there might be a problem with our internal APIs, but making 25 parallel requests to our internal APIs using `curl` has consistently the same performance on both http 1.1 and http2.\r\n\r\nI ran curl with the following command:\r\n```sh\r\ncurl --config ./config.txt --parallel --parallel-max 25 --http2\r\n```\r\n\r\nwhere config.txt looked like this:\r\n```txt\r\nurl = \"our-internal-api\"\r\noutput = \"/dev/null\"\r\n// repeated 25 times\r\n```\r\n\r\n### Additional information\r\n\r\nI was thinking the reason for such slowness would be TCP stall because http2 uses only 1 tcp connection, so I checked in wireshark how many tcp connections creates node vs curl when using http2, and both created only 1 tcp connection.\r\n\r\nAlso, I noticed node receives first 10 http2 requests randomly, but then sequentially, while http1 requests are all received randomly.\r\n\r\nhttp2:\r\n\r\n\u003cimg width=\"405\" alt=\"image\" src=\"https://github.com/user-attachments/assets/7b1b155e-656b-4266-aca9-64cb009f02cd\">\r\n\r\n---\r\n\r\nhttp1:\r\n\r\n\u003cimg width=\"424\" alt=\"image\" src=\"https://github.com/user-attachments/assets/f317b751-ed98-44aa-b562-1854ccc88835\">\r\n","author":{"url":"https://github.com/stanislav-halyn","@type":"Person","name":"stanislav-halyn"},"datePublished":"2024-09-10T14:46:45Z","url":"https://github.com/nodejs/node/issues/54874"}
| react-profiling | 0 |
| react-import-map | react,react-dom,react-dom/client,react-dom/profiling,react-is,react-reconciler,react/compiler-runtime,react/jsx-dev-runtime,react/jsx-runtime,scheduler@d5750093facf |
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:73db01bc-6b4c-9702-94af-5560a377629a |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 83B8:278B88:1C0FCB:262CDE:6AED4366 |
| html-safe-nonce | ca0389a08a34408da8047c078b668104929ba060373c342461de47dce9e8aba4 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4M0I4OjI3OEI4ODoxQzBGQ0I6MjYyQ0RFOjZBRUQ0MzY2IiwidmlzaXRvcl9pZCI6Ijc1MjAwNDEzODY5MDg2NjQ2NzgiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 2e56c2b0866be6cf0fda635366c7ae2838f1a252d67afd261b4393853a6e07d9 |
| hovercard-subject-tag | issue:2516684987 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/nodejs/node/54874/issue_layout |
| twitter:image | https://opengraph.githubassets.com/afa54a70b784a82393183c035ecf6bc6e15d36ed113f003e0fe4b69a90958a31/nodejs/node/issues/54874 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/afa54a70b784a82393183c035ecf6bc6e15d36ed113f003e0fe4b69a90958a31/nodejs/node/issues/54874 |
| og:image:alt | Version v20.17.0 Platform MacOS Sonoma 14.5, 2,3 GHz Quad-Core Intel Core i7 Subsystem No response What steps will reproduce the bug? Define an http2 and http1.1 clients and fetch some data in para... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | stanislav-halyn |
| hostname | github.com |
| expected-hostname | github.com |
| None | 56fb42677ae87ed3e64410323d67980aa65d0485568a7858f874e7edfc6d1c11 |
| turbo-cache-control | no-preview |
| go-import | github.com/nodejs/node git https://github.com/nodejs/node.git |
| octolytics-dimension-user_id | 9950313 |
| octolytics-dimension-user_login | nodejs |
| octolytics-dimension-repository_id | 27193779 |
| octolytics-dimension-repository_nwo | nodejs/node |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 27193779 |
| octolytics-dimension-repository_network_root_nwo | nodejs/node |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 9c9a37e2423ed382cf39f70b5aa4b4858b40a3b0 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
| react-app-name | issues |
Links:
Viewport: width=device-width