nodejs / nodejs/node

Investigating a Severe Performance Regression in Node.js v22 and v24

Đang mở
#60,719 16 bình luận 1 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

performance sqlite
Ngôn ngữ chính
JavaScript
Star
122k
Fork
37.3k
Merge trung bình
4 ngày 2 giờ
Pull request đã merge (30 ngày)
283

Mô tả

Investigating a Severe Performance Regression in Node.js v22 and v24

Hello everyone,

We (@forwardemail) have been running some benchmarks with better-sqlite3-multiple-ciphers and came across what appears to be a significant performance regression in newer Node.js versions. I wanted to share my findings in case they are helpful to the community, especially for those who rely on native modules with SQLite. We use encrypted SQLite databases for storing folks email, see our write-up at https://forwardemail.net/en/blog/docs/best-quantum-safe-encrypted-email-service.

Summary of Findings

My benchmarks indicate that Node.js v24 is approximately 57% slower than v20 for SQLite SELECT operations, while Node.js v22 shows a smaller regression of about 7-9%. These findings suggest the performance issue may not be specific to better-sqlite3 but could be related to a broader change in the V8 engine that affects native modules.

Benchmark Results

I've created a benchmark suite to reproduce these results, which you can find here: https://github.com/forwardemail/sqlite-benchmarks

Here is a summary of the results I observed with better-sqlite3-multiple-ciphers:

Node.js Version SELECT ops/sec vs v20 LTS
v20.19.5 (LTS) 18,383 baseline
v22.21.1 ~17,000 -7%
v24.11.1 ~7,900 -57%

As the table shows, the performance on v24 is less than half of that on v20 for this specific database workload.

Potential Root Cause

After some investigation, I believe this regression may be linked to the V8 13.6 engine upgrade in Node.js v24. The V8 versions for each Node.js release are as follows:

  • Node.js v20: V8 11.3 (Stable Performance)
  • Node.js v22: V8 12.4 (Minor Regression)
  • Node.js v24: V8 13.6 (Major Regression)

The most significant change in V8 13.6 appears to be the move to a V8-owned CppHeap (nodejs/node#52718), which alters how C++ objects are managed and garbage collected in native modules. While this change was intended to simplify the API, it seems to have had an unintended impact on the performance of native modules that frequently cross the JS/C++ boundary.

How This Might Affect SQLite Performance

The performance-critical paths in better-sqlite3 involve frequent C++ object allocation, heavy interaction between JS and C++, and string conversions. The new V8-owned CppHeap may have introduced different garbage collection timing, allocation patterns, or boundary-crossing overhead that could be contributing to this slowdown.

Related Upstream Issues

This issue may be part of a broader pattern of performance regressions in recent Node.js versions:

  1. Startup regression: nodejs/performance#180
  2. Module loading regression: nodejs/node#60397
  3. CppHeap deprecation: nodejs/node#52718

These issues suggest that V8 11.3 (in Node.js v20) may have been a more optimized version for native module performance.

Suggestions for a Path Forward

I've put together some thoughts on how we might be able to approach this. I'm happy to help with any of these steps.

For Users Experiencing This Issue

For those affected by this performance regression, a possible short-term workaround could be to remain on Node.js v20 LTS. It appears to be the most stable and performant version for this workload and is supported until April 2026.

Potential Areas for Investigation

It seems the performance degradation might be linked to the CppHeap changes in V8. It could be beneficial for the V8 and Node.js teams to investigate this further. Some areas that might be worth exploring include:

  • Benchmarking the CppHeap regression: A performance comparison of native modules before and after the CppHeap changes could help confirm the impact.
  • Profiling hot paths: It might be useful to profile the following areas:
    • Object allocation in the V8-owned CppHeap
    • Garbage collection behavior for frequently created C++ objects
    • Overhead from JS/C++ boundary crossings
    • String encoding/decoding with WriteUtf8V2()
Possible Long-Term Solutions

If the regression in V8 cannot be addressed upstream, it might be necessary for native modules like better-sqlite3 to adapt. Some potential strategies could include:

  • Object pooling: Reusing statement objects to reduce allocation overhead.
  • Batch operations: Processing multiple rows at once to minimize boundary crossings.
  • Optimized string handling: Caching string conversions or exploring alternative V8 APIs.
  • Manual memory management: Taking more explicit control over the object lifecycle to mitigate GC issues.

However, it seems that addressing this at the V8 level would be the most effective solution, as it would benefit all native modules.

Reproduction

To reproduce the benchmark results, you can clone the repository and run the tests:

git clone https://github.com/forwardemail/sqlite-benchmarks.git
cd sqlite-benchmarks
npm install

# Test with different Node.js versions
nvm use 20 && npm run benchmark
nvm use 22 && npm run benchmark
nvm use 24 && npm run benchmark

The results have been consistent on both macOS ARM and Linux x64.

Questions for the Community

  1. Has anyone else encountered similar performance issues with v24?
  2. Are there any V8 flags or Node.js options that might help mitigate this?
  3. Would it be appropriate to escalate this to the V8 team for their input?

I am more than willing to assist with further profiling, testing, or providing any additional information that might be helpful. Thank you for your time and consideration.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu với repository bên ngoài sqlite-benchmarks và chạy các lệnh npm install và benchmark của repository này trên Node.js 20, 22 và 24. So sánh regression SELECT được báo cáo giữa macOS ARM và Linux x64, sau đó điều tra các tham chiếu đến V8 13.6 và CppHeap cùng các issue upstream được liên kết. Được xem là hoàn tất khi xác nhận hoặc thu hẹp được nguyên nhân của regression và xác định được một hướng upstream có thể triển khai.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
javascript, node.js, sqlite
Lĩnh vực
backend, performance
Loại issue
Lỗi
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Cần làm rõ
Mức phù hợp với người mới
32/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.