SlideShare a Scribd company logo
1 of 69
Download to read offline
Node.js applications diagnostics
under the hood
Nikolay Matvienko
2018
1
Author
Nikolay Matvienko
Full Stack JS developer at Grid Dynamics
twitter: @matvi3nko
facebook: matvienko.nikolay
mail: matvi3nko@gmail.com
github: @matvi3nko
2
Customers in retail domain
3
Diagnostics
Node.js Diagnostics Working Group https://github.com/nodejs/diagnostics
Post Mortem Diagnostics Working Group https://github.com/nodejs/post-mortem
Work is divided into several domains:
1. Tracing
Profiling
Heap and Memory Analysis
Step Debugging
2. Postmortem debugging
4
Stages of Node.js diagnostics evolution before 2017
The first stage The second stage
5
The third stage of Node.js diagnostics evolution
The first stage The second stage The third stage
6
1. Diagnostic tools appeared with a delay.
2. Most tools didn’t support the latest version of V8 (Node.js )
3. We had to choose: performance or tools
4. Or new tools appear, but without support for previous versions of Node. js
V8 engine update
7
Node.js in Enterprise Architecture
Transperfect internationalization CDN
8
* This is a greatly simplified scheme
Node.js Microservices
app app app
Node.js Web
back-end
app app app
Akamai CDN
Oracle
Splunk
NewRelic
Redis
Security Gateway
Java apps
AWS Services
Catalog
Web UIMobile
Tealium Paypal
Bazaar
voice Olapic
… and many other
external services
CDN scene Seven
CMS
Search Engine
Black Friday = ~60% of the annual income.
9
Agenda
1. Debugging in production
2. Performance profiling
3. Search for memory leaks
10
1. Debugging in production
The reasons:
1. Uncaught Exception
2. Difficult reproducible errors
3. Production environment
4. ASAP
11
Example
Controller Service
REST APIError
12
module.exports = class ProductController {
constructor (reservationService) {
this._reservationService = reservationService;
}
reserve (req, res) {
const { id, storeId } = req.cookies['profile'];
const rewards = req.cookies['rewards'];
const { products } = req.body;
this._reservationService.reserve(id, storeId, rewards.id, products)
.then(data => {
return res.send(data);
});
}};
Case 1. Product reservation.
13
Throws an Error when
rewards is undefined
Core dump creation algorithm for postmortem debugging
Serving traffic
uncaught exception
abort() before
the crash
Restart app
core dump
debugging
with llnode
Fix
14
local
node --abort-on-uncaught-exception app.js
name: core.<PID>
size: ~1.5GB
> llnode -c /cores/core.<PID>
Debugging steps
1. Get the Stack Trace and find the last JS function before the exit
2. Read the source code of the function
3. Get input parameters: request and response
15
$ llnode -c /cores/core.13364
$(llnode) v8 bt
frame #4: 0x3501dbc040dd <exit>
frame #5: 0x3501dbceb5cc <builtin>
frame #6: 0x3501dbc12f12 reserve(this=0x0153bf0e84d1:<Object: ProductController>,
0x163b0e223089:<Object: IncomingMessage>, 0x163b0e224e39:<Object: ServerResponse>) at
/demo/controllers/ProductController.js:8:11 fn=0x04c146ed3fa1
frame #7: 0x3501dbcf3fa1 <builtin>
frame #8: 0x3501dbc12f12 (anonymous)(this=0x163b0e223089:<Object: IncomingMessage>) at
/demo/app.js:21:28 fn=0x163b0e227699
frame #9: 0x3501dbcf373c <builtin>
frame #10: 0x3501dbc12f12 emitNone(this=0x0b9b56e02241:<undefined>, 0x163b0e2278a9:<Array:
….
Step 1. Get the Stack Trace and find the last JS function
16
starts llnode debugger with core dump
returns JS and C++ Stack Trace
addresses in the Memory
Step 2. Read the source code of the function
(llnode) v8 inspect --print-source 0x4c146ed3fa1
0x04c146ed3fa1:<function: reserve at /demo/controllers/ProductController.js:8:11
source:
const { id, storeId } = req.cookies['profile'];
const rewards = req.cookies['rewards'];
const { products } = req.body;
this._reservationService.reserve(id, storeId, rewards.id, products)
.then(data => {
return res.send(data);
}
);
17
Step 3. Get input parameter – request
$(llnode) v8 bt 20
frame #4: 0x3501dbc040dd <exit>
frame #5: 0x3501dbceb5cc <builtin>
frame #6: 0x3501dbc12f12 reserve(this=0x0153bf0e84d1:<Object: ProductController>,
0x163b0e223089:<Object: IncomingMessage>, 0x163b0e224e39:<Object: ServerResponse>) at
/demo/controllers/ProductController.js:8:11 fn=0x04c146ed3fa1
frame #7: 0x3501dbcf3fa1 <builtin>
frame #8: 0x3501dbc12f12 (anonymous)(this=0x163b0e223089:<Object: IncomingMessage>) at
/demo/app.js:21:28 fn=0x163b0e227699
frame #9: 0x3501dbcf373c <builtin>
frame #10: 0x3501dbc12f12 emitNone(this=0x0b9b56e02241:<undefined>, 0x163b0e2278a9:<Array:
length=2>,0x0b9b56e022f1:<false>, 0x163b0e223089:<Object: IncomingMessage>)
at events.js:103:18 fn=0x0f2606a87391
….
frame #20: ...
18
Step 3 result. Request object
$(llnode) v8 inspect 0x163b0e223089
0x163b0e223089:<Object: IncomingMessage properties {
._events=0x163b0e223739:<Object: Object>,
.socket=0x163b0e21e4e1:<Object: Socket>,
.complete=0x0b9b56e022c1:<true>,
.cookies=0x5c4b0e863755:<Object: Object>,
.headers=0x163b0e223d11:<Object: Object>,
.(external)=0x163b0e223069:<String: "/product/reserve">,
.method=0x04c146ed42a1:<String: "POST">,
.statusCode=0x0b9b56e02211:<null>,
.statusMessage=0x0b9b56e02211:<null>,
.body=0x163b0e22aee1:<Object: Object>}>
…
19
$(llnode) v8 inspect 0x5c4b0e863755
0x5c4b0e863755:<Object: Object properties {
.profile=0x3d76d2184b41:<Object: Object>,
.rewards=0x163b0e22af51:<undefined>}>
Case 1. Informative Stack Trace
$(llnode) v8 bt
frame #4: 0x3501dbc040dd <exit>
frame #5: 0x3501dbceb5cc <builtin>
frame #6: 0x3501dbc12f12 reserve(this=0x0153bf0e84d1:<Object: ProductController>,
0x163b0e223089:<Object: IncomingMessage>, 0x163b0e224e39:<Object: ServerResponse>) at
/demo/controllers/ProductController.js:8:11 fn=0x04c146ed3fa1
frame #7: 0x3501dbcf3fa1 <builtin>
frame #8: 0x3501dbc12f12 (anonymous)(this=0x163b0e223089:<Object: IncomingMessage>) at
/demo/app.js:21:28 fn=0x163b0e227699
frame #9: 0x3501dbcf373c <builtin>
frame #10: 0x3501dbc12f12 emitNone(this=0x0b9b56e02241:<undefined>, 0x163b0e2278a9:<Array:
length=2>,0x0b9b56e022f1:<false>, 0x163b0e223089:<Object: IncomingMessage>)
at events.js:103:18 fn=0x0f2606a87391
….
20
reserve (req, res, next) {
const { id, storeId } = req.cookies['profile'];
const rewards = req.cookies['rewards'];
const products = req.body;
this._reservationService.reserve(id, storeId, rewards, products)
.then(data => {
return res.send(data);
});
// NO CATCH block is here and next() is not used
}
Case 2. Unhandled rejection
reserve() throws an Error
sinse expect the rewards.id
21
reserve (req, res, next) {
const { id, storeId } = req.cookies['profile'];
const rewards = req.cookies['rewards'];
const products = req.body;
this._reservationService.reserve(id, storeId, rewards, products)
.then(data => {
return res.send(data);
});
// NO CATCH block is here and next() is not used
}
process.on('unhandledRejection', (reason, p) => {
logger.error('Unhandled Rejection at:', p, 'reason:', reason);
process.abort();
});
Case 2. Unhandled rejection
22
Case 2. Uninformative Stack Trace
$(llnode) v8 bt
frame #8: 0x2262d63840dd <exit>
frame #9: 0x2262d64735e9 <builtin>
frame #10: 0x2262d6392f12 process.on(this=0x18901b589ec1:<Object: process>,
0x27a40a5f15d9:<unknown>, 0x27a40a5f11a9:<unknown>) at /demo/app.js:40:34
fn=0x0af20adefc91
frame #11: 0x2262d6472cc8 <builtin>
frame #12: 0x2262d6392f12 emitTwo(this=0x3e5911182241:<undefined>,
0x0af20adefc91:<function: process.on at /demo/app.js:40:34>, 0x3e59111822c1:<true>,
0x18901b589ec1:<Object: process>, 0x27a40a5f15d9:<unknown>, 0x27a40a5f11a9:<unknown>)
at events.js:123:17 fn=0x368a12a07421
frame #13: 0x2262d6473a25 <builtin>
frame #14: 0x2262d6392f12 emit(this=0x18901b589ec1:<Object: process>,
0x368a12a373e1:<String: "unhandledRejecti...">) at events.js:155:44 fn=0x3ef321f07b19
23
Case 2. Finding all req object instances
$(llnode) v8 findjsinstances IncomingMessage
...
0x0af20adff4a1:<Object: IncomingMessage>
0x25c630d8fe69:<Object: IncomingMessage>
0x25c630d97861:<Object: IncomingMessage>
0x25c630d9d811:<Object: IncomingMessage>
0x25c630da9729:<Object: IncomingMessage>
0x25c630daf8d9:<Object: IncomingMessage>
0x25c630dbb669:<Object: IncomingMessage>
0x25c630dc1591:<Object: IncomingMessage>
0x25c630dd6c31:<Object: IncomingMessage>
0x25c630ddcb59:<Object: IncomingMessage>
0x25c630de2ed1:<Object: IncomingMessage>
0x25c630de8d01:<Object: IncomingMessage>
0x25c630deec29:<Object: IncomingMessage>
…
24
N
Case 2. Which request crashed the process
$(llnode) v8 findjsinstances IncomingMessage
...
0x0af20adff4a1:<Object: IncomingMessage>
0x25c630d8fe69:<Object: IncomingMessage>
0x25c630d97861:<Object: IncomingMessage>
0x25c630d9d811:<Object: IncomingMessage>
0x25c630da9729:<Object: IncomingMessage>
0x25c630daf8d9:<Object: IncomingMessage>
0x25c630dbb669:<Object: IncomingMessage>
0x25c630dc1591:<Object: IncomingMessage>
0x25c630dd6c31:<Object: IncomingMessage>
0x25c630ddcb59:<Object: IncomingMessage>
0x25c630de2ed1:<Object: IncomingMessage>
0x25c630de8d01:<Object: IncomingMessage>
0x25c630deec29:<Object: IncomingMessage>
…
25
Case 2. List of the killed requests in current process
$(llnode) v8 findjsinstances IncomingMessage
...
0x0af20adff4a1:<Object: IncomingMessage>
0x25c630d8fe69:<Object: IncomingMessage>
0x25c630d97861:<Object: IncomingMessage>
0x25c630d9d811:<Object: IncomingMessage>
0x25c630da9729:<Object: IncomingMessage>
0x25c630daf8d9:<Object: IncomingMessage>
0x25c630dbb669:<Object: IncomingMessage>
0x25c630dc1591:<Object: IncomingMessage>
0x25c630dd6c31:<Object: IncomingMessage>
0x25c630ddcb59:<Object: IncomingMessage>
0x25c630de2ed1:<Object: IncomingMessage>
0x25c630de8d01:<Object: IncomingMessage>
0x25c630deec29:<Object: IncomingMessage>
…
26
add X-Transaction-ID
Event Loop
request
response
Case 2. Search headers by the value of request ID
$(llnode) v8 findrefs --string "6af9c8d5-1b18-48b0-86fc-b9aac43b3cd6"
0x25c630deef01: Object.X-Transaction-ID=0x25c630deea51 '6af9c8d5-1b18-48b0-86fc-b9aac43b3cd6'
27
string address
address of parent object - headers
Case 2. Search request by address of headers object
$(llnode) v8 findrefs --string "6af9c8d5-1b18-48b0-86fc-b9aac43b3cd6"
0x25c630deef01: Object.X-Transaction-ID=0x25c630deea51 '6af9c8d5-1b18-48b0-86fc-b9aac43b3cd6'
$(llnode) v8 findrefs --value 0x25c630deef01
0x27a40a5bbce9: IncomingMessage.headers=0x25c630deef01
28
the request object that we need
module.exports = class ReservationService {
...
reserve (id, storeId, rewardsId, products) { // id = 'ff104cde3452332e0cc6'
return Promise.all([
this._rest.GET('user', id),
this._db.getStore(storeId, rewardsId)
]).then(([user, rewardsInStore]) => {
const data = { user, products, rewardsInStore };
return this._rest.POST('reserve', data);
});
}};
Search for local variables
29
v8 findrefs --string "'ff104cde3452332e0cc6'"
v8 findrefs --name "rewardsInStore"
v8 findrefs --string "jeans-xxl"
Middleware Controller Service Storage
node-report
Event: exception, location: "OnUncaughtException"
Dump event time: 2017/09/27 00:57:26
Process ID: 35866
==== JavaScript Stack Trace ====================================
Object.fs.readFileSync (fs.js:1:1)
ProductController.reserve (/demo/controllers/ProductController.js:1:1)
==== Native Stack Trace ========================================
0: [pc=0x1023eb7b1] nodereport::OnUncaughtException(v8::Isolate*)
1: [pc=0x1006da003] v8::internal::Isolate::Throw(v8::internal::Object*)
==== JavaScript Heap and Garbage Collector ======================
Heap space name: new_space
Memory size: 4,194,304 bytes, committed memory: 2,116,048 bytes
Capacity: 2,062,336 bytes, used: 824,392 bytes, available: 1,237,944 byte
Heap memory limit: 1,501,560,832
30
Where?
What?
When?
Errors in production
31
I use core dump!
32
I use core dump! Let’s the debugging begin!
33
I use core dump! Let’s the debugging begin!
What is the difference between all of them?
34
I use core dump! Let’s the debugging begin!
What is the difference between all of them?
35
Boss: How much time do you need to solve
the issue?
Core dump flood
const gencore = require('gencore');
const errorRegistry = new ErrorRegistry(redisClient);
app.use( function errorHandlerMiddleware (err, req, res, next) {
errorRegistry.add(err, req)
.then(result => {
if (result) { // was error added to registry
gencore.collectCore((error, name) => {
logger.info(`Core dump created at: ${name}
for request: ${req.headers['X-Transaction-ID']}`);
});
}
// … send 500 status
})
.catch(err => { … // handleError(err, req, res, next); })
});
Error handler with Error Registry and gencore
36
npm install --save-dev gencore
Makes process fork and creates core dump
core
dump
* This is the simplified example
error selection logic
Core dump creation algorithm in production
Serving Traffic Error Handler
core dump
logs
Request ID
Fix
No
Yes
37
caught
create
dump?
gencore
process fork
abort
Restart node-report
report
abort
core dump
write log
read in Splunk
llnode
No
Yes
Core dump creation algorithm in production
Serving Traffic Error Handler
core dump
logs
Request ID
Fix
No
Yes
38
caught
create
dump?
gencore
process fork
abort
Restart node-report
report
abort
core dump
write log
read in Splunk
llnode
No
Yes
Core dump creation algorithm in production
Serving Traffic Error Handler
core dump
logs
Request ID
Fix
No
Yes
39
caught
create
dump?
gencore
process fork
abort
Restart node-report
report
abort
core dump
write log
read in Splunk
llnode
No
Yes
Core dump creation algorithm in production
Serving Traffic Error Handler
core dump
logs
Request ID
Fix
No
Yes
40
caught
create
dump?
gencore
process fork
abort
Restart node-report
report
abort
core dump
write log
read in Splunk
llnode
No
Yes
Core dump creation algorithm in production
Serving Traffic Error Handler
core dump
logs
Request ID
Fix
No
Yes
41
caught
create
dump?
gencore
process fork
abort
Restart node-report
report
abort
core dump
write log
read in Splunk
llnode
No
Yes
Core dump creation algorithm in production
Serving Traffic Error Handler
core dump
logs
Request ID
Fix
No
Yes
42
caught
create
dump?
gencore
process fork
abort
Restart node-report
report
abort
core dump
write log
read in Splunk
llnode
No
Yes
Core dump creation algorithm in production
Serving Traffic Error Handler
core dump
logs
Request ID
Fix
No
Yes
43
caught
create
dump?
gencore
process fork
abort
Restart node-report
report
abort
core dump
write log
read in Splunk
llnode
No
Yes
Core dump creation algorithm in production
Serving Traffic Error Handler
core dump
logs
Request ID
Fix
No
Yes
44
caught
create
dump?
gencore
process fork
abort
Restart node-report
report
abort
core dump
write log
read in Splunk
llnode
No
Yes
Tips
1. Follow to Error handling best practices
2. Call abort() only in centralized error handler
3. Use gencore
4. Use node-report to generate a report
5. Track requests using id – X-Transaction-ID or X-Request-ID (NGINX) header (or Zipkin headers)
6. Avoid core dump flood
45
Progress
1. Debugging in production ✔
2. Performance profiling
3. Search for memory leaks
46
2. The response of the Node.js web server has
grown from ~300 to ~1500 ms
47
Profiling: node --prof(iler) + apache bench/JMeter
node --prof app.js and node --prof-process isolate-0x-v8.log > profile.txt
[Summary]:
ticks total nonlib name
2710 18.9% 19.0% JavaScript
13348 58.7% 58.9% C++
561 2.5% 2.5% GC
[JavaScript]:
112 0.5% 0.5% Builtin: CallFunction_ReceiverIsNotNullOrUndefined
4 0.0% 0.0% LazyCompile: *emit events.js:136:44
42 15.2% 15.2% presentation/handlebars/helpers/urlBuilder.helper.js:51:37
2 0.0% 0.0% LazyCompile: ~substr native string.js:324:22
...
[C++]:
1292 5.7% 5.7% node::ContextifyScript::New(v8::FunctionCallbackInfo<v8::Value> const&)
...
48
49
50
modules App logic logic in handlebars templates fs lodash
page rendering
partials/helpers hbspartials/helpers
~65% on page
rendering (SSR)
~20% on lodash
operations with
data
~10% on data
retrieval from API
(Promises)
Application spends:
lodash
merge
handlebars
helpers
utils
52
lodash baseMerge, baseMergeDeep
forEach, lodash cloneDeep
Data processing
Performance improvements
After performance profiling with perf, DTrace, 0x and bcc utils we:
▪ Reduced CPU intensive operations:
a. lodash objects merge, deep clone
b. long cycles
c. JSON parse
▪ Removed logic from view templates and helpers
▪ Reviewed and updated npm dependencies
▪ Gradually implemented React SSR
53
54
3d party libraries
page
rendering
<15%
App main logicAPI callsApp logic 3d party libraries
SSR
Tips
55
1. Performance should be a part of requirements.
2. Measure performance before embedding third-party libraries and after
3. Collect measurement results archive
4. Profile on staging/pre-production environments
5. Monitor diagnostic tools performance impact
3. Memory grows
Ways to identify:
▪ Application Monitoring tools (N|Solid, NewRelic)
▪ DTrace, Instruments, perf
▪ node-memwatch
▪ GC Tracing
▪ Valgrind for C++ modules
▪ heapdump
▪ Fatal error
▪ and other...
56
Case: Excessive garbage collection.
The creation a lot of new objects
57
GC rate grows in New Space (Scavenge GC)
256201 ms: Scavenge 824.5 (1014.4) -> 811.4 (1016.2) MB, 16.9 / 0.0 ms [allocation failure].
256218 ms: Scavenge 838.8 (1019.3) -> 827.7 (1024.7) MB, 17.6 / 0.0 ms [allocation failure].
256236 ms: Scavenge 852.8 (1024.7) -> 842.9 (1026.5) MB, 11.0 / 0.0 ms [allocation failure].
256557 ms: Scavenge 869.8 (1201.6) -> 858.1 (1209.6) MB, 33.3 / 0.0 ms (+ 86.0 ms in 176 steps since
last GC) [allocation failure].
256925 ms: Scavenge 884.1 (1232.8) -> 871.9 (1239.2) MB, 36.5 / 0.0 ms (+ 56.7 ms in 168 steps since
last GC) [allocation failure].
Case: Scavenge GC in New Space.
58
Long Garbage collectionMemory grows
Interval
node --trace_gc --trace_gc_verbose app.js > gc-trace.log
{
"name": "LazyCompile:~insert
/Users/nmatvienko/projects/x/src/cms/cmsHelper.js:806",
"children":
{
"name": "LazyCompile:*replace native string.js:132",
"children": [
{
"name": "Stub:CEntryStub",
"children": [
{
"name": "v8::internal::Scavenger::ScavengeObjectSlow"
}
Garbage collection
Profiling
replace native string
v8::internal::Heap::CollectGarbage
insert CmsHelper
v8::internal::Heap::Scavenge()
v8::internal::ScavengingVisitor
Operation that requested memory allocation
JS
V8
GC
Flame Graph
node
Text representationVisual representation
{
"name": "LazyCompile:~ /Users/nmatvienko/projects/x/api/domain/product/mappers/ProductMapper.js:11",
"value": 1240,
"top": 2,
"children": [
… {
"name": "LazyCompile:*map native array.js:994",
"value": 1025,
"top": 20,
"children": [
...
{
"name": "Stub:CEntryStub",
"value": 41,
"top": 32,
"children": [
{
"name": "node`v8::internal::Scavenger::ScavengeObject",
"value": 2,
"top": 2
},
{
"name": "node`v8::internal::Space::AllocationStep",
"value": 1,
"top": }
]
Garbage collection in New Space
Operation that requested allocation
of memory
172047 ms: Scavenge 546.9 (592.6) -> 538.4 (592.6) MB, 1.5 / 0.0 ms [allocation failure].
172093 ms: Scavenge 547.8 (593.6) -> 534.0 (593.6) MB, 2.8 / 0.0 ms [allocation failure].
172136 ms: Scavenge 549.1 (594.6) -> 535.0 (595.6) MB, 2.2 / 0.0 ms [allocation failure].
172202 ms: Scavenge 550.4 (595.6) -> 536.3 (596.6) MB, 3.3 / 0.0 ms (+ 14.3 ms in 206 steps since last GC)
[allocation failure].
172269 ms: Scavenge 551.6 (596.6) -> 537.1 (597.6) MB, 3.9 / 0.0 ms (+ 15.5 ms in 238 steps since last GC)
[allocation failure].
GC tracing in New Space after improvements
61
Garbage collection timeMemory doesn’t grow
Case: Many references, missed closures and timers.
GC in Old Space
168372 ms: Mark-sweep 493.7 (558.6) -> 151.4 (352.1) MB, 90.3 ms (+ 150.3 ms in 731 steps, biggest step
18.1 ms)
134838 ms: Mark-sweep 525.3 (680.7) -> 169.7 (366.8) MB, 91.2 ms (+ 157.0 ms in 790 steps, biggest step
14.2 ms) …
300609 ms: Mark-sweep 664.8 (825.1) -> 192.0 (387.1) MB, 110.4 ms (+ 193.8 ms in 982 steps, biggest
step 19.5 ms)
956609 ms: Mark-sweep 1164.8 (1325.1) -> 792.0 (1007.1) MB, 214.2 ms (+ 296.8 ms in 1482 steps,
biggest step 19.5 ms)
990164 ms: Mark-sweep 1183.8 (1405.1) -> 799.0 (1124.1) MB, 216.7 ms (+ 307.7 ms in 1496 steps,
biggest step 20.7 ms)
62
Long garbage collection
$(llnode) v8 findjsobjects
Instances Total Size Name
---------- ---------- ----
251 88216 ServerResponse
251 58440 IncomingMessage
40 9920 Socket
42 9408 WritableState
93 34016 ReadableState
94 15528 BufferList
86 6880 Module
194 12504 TickObject
3688 118016 (Array)
250 21920 Timeout
31043 369864 (String)
…
Get all JS objects from the Heap using llnode
63
$(llnode) v8 findjsinstances IncomingMessage
0xaf20adff4a1:<Object: IncomingMessage>
0x25c630d8fe69:<Object: IncomingMessage>
0x25c630d97861:<Object: IncomingMessage>
0x25c630d9d811:<Object: IncomingMessage>
0x25c630da37c9:<Object: IncomingMessage>
0x25c630daf8d9:<Object: IncomingMessage>
0x25c630db5741:<Object: IncomingMessage>
0x25c630dbb669:<Object: IncomingMessage>
0x25c630dc1591:<Object: IncomingMessage>
0x25c630dd6c31:<Object: IncomingMessage>
0x27a40a588a11:<Object: IncomingMessage>
0x27a40a58e841:<Object: IncomingMessage>
0x27a40a5a38f1:<Object: IncomingMessage>
0x27a40a5a9819:<Object: IncomingMessage>
Find all IncomingMessage instances
64
$(llnode) v8 findjsinstances IncomingMessage
0xaf20adff4a1:<Object: IncomingMessage>
0x25c630d8fe69:<Object: IncomingMessage>
0x25c630d97861:<Object: IncomingMessage>
0x25c630d9d811:<Object: IncomingMessage>
0x25c630da37c9:<Object: IncomingMessage>
0x25c630daf8d9:<Object: IncomingMessage>
0x25c630db5741:<Object: IncomingMessage>
0x25c630dbb669:<Object: IncomingMessage>
0x25c630dc1591:<Object: IncomingMessage>
0x25c630dd6c31:<Object: IncomingMessage>
0x27a40a588a11:<Object: IncomingMessage>
0x27a40a58e841:<Object: IncomingMessage>
0x27a40a5a38f1:<Object: IncomingMessage>
0x27a40a5a9819:<Object: IncomingMessage>
Find req object holders
65
$(llnode) v8 findrefs -v 0xaf20adff4a1
0x25c630d8ada1: (Array)[250]=0xaf20adff4a1
0x25c630d83329: ServerResponse.req=0xaf20adff4a1
$(llnode) v8 findjsinstances IncomingMessage
0xaf20adff4a1:<Object: IncomingMessage>
0x25c630d8fe69:<Object: IncomingMessage>
0x25c630d97861:<Object: IncomingMessage>
0x25c630d9d811:<Object: IncomingMessage>
0x25c630da37c9:<Object: IncomingMessage>
0x25c630daf8d9:<Object: IncomingMessage>
0x25c630db5741:<Object: IncomingMessage>
0x25c630dbb669:<Object: IncomingMessage>
0x25c630dc1591:<Object: IncomingMessage>
0x25c630dd6c31:<Object: IncomingMessage>
0x27a40a588a11:<Object: IncomingMessage>
0x27a40a58e841:<Object: IncomingMessage>
0x27a40a5a38f1:<Object: IncomingMessage>
0x27a40a5a9819:<Object: IncomingMessage>
Find all IncomingMessage instances
66
$(llnode) v8 findrefs -v 0x0af20adff4a1
0x25c630d8ada1: (Array)[250]=0xaf20adff4a1
0x25c630d83329: ServerResponse.req=0xaf20adff4a1
$(llnode) v8 findrefs -v 0x25c630d8ada1
0x3b312aee27d9: ProfileMiddleware._requests =0x25c630d8ada1
Tips
1. Control the Life Cycle of app Objects and Sessions
2. Trace Scavenge GC in Profiler Stacks to find allocation cause (bcc/tools/stackcount.py)
3. Use D8 to check Javascript behavior in V8 (%DebugTrackRetainingPath(x))
4. Call GC manually to check memory allocation
5. Write memory usage tests for code and libraries with leakage
6. Create heapdump/ coredump for deep investigation
67
Result
1 month before 3 weeks of investigation
and refactoring
After improvements
original
time has been
grown x4
68
new baseline
Nikolay Matvienko
mail: matvi3nko@gmail.com
twitter: @matvi3nko
github: @nickkooper
Linked-in nikolaymatvienko
69
Resources
https://github.com/nickkooper/
nodejs-diagnostics-resources

More Related Content

What's hot

The Ring programming language version 1.5.4 book - Part 71 of 185
The Ring programming language version 1.5.4 book - Part 71 of 185The Ring programming language version 1.5.4 book - Part 71 of 185
The Ring programming language version 1.5.4 book - Part 71 of 185Mahmoud Samir Fayed
 
Windows 8 Pure Imagination - 2012-11-25 - Extending Your Game with Windows 8 ...
Windows 8 Pure Imagination - 2012-11-25 - Extending Your Game with Windows 8 ...Windows 8 Pure Imagination - 2012-11-25 - Extending Your Game with Windows 8 ...
Windows 8 Pure Imagination - 2012-11-25 - Extending Your Game with Windows 8 ...Frédéric Harper
 
Data binding в массы!
Data binding в массы!Data binding в массы!
Data binding в массы!Artjoker
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Mahmoud Hamed Mahmoud
 
Java Virtual Keyboard Using Robot, Toolkit and JToggleButton Classes
Java Virtual Keyboard Using Robot, Toolkit and JToggleButton ClassesJava Virtual Keyboard Using Robot, Toolkit and JToggleButton Classes
Java Virtual Keyboard Using Robot, Toolkit and JToggleButton ClassesAbdul Rahman Sherzad
 
An iOS Authentication Architecture for All
An iOS Authentication Architecture for AllAn iOS Authentication Architecture for All
An iOS Authentication Architecture for AllRené Cacheaux
 
ES3-2020-P3 TDD Calculator
ES3-2020-P3 TDD CalculatorES3-2020-P3 TDD Calculator
ES3-2020-P3 TDD CalculatorDavid Rodenas
 
Android testing
Android testingAndroid testing
Android testingSean Tsai
 
ReactJS for Programmers
ReactJS for ProgrammersReactJS for Programmers
ReactJS for ProgrammersDavid Rodenas
 
Removing structural duplication
Removing structural duplicationRemoving structural duplication
Removing structural duplicationAlexandru Bolboaca
 
10 Typical Enterprise Java Problems
10 Typical Enterprise Java Problems10 Typical Enterprise Java Problems
10 Typical Enterprise Java ProblemsEberhard Wolff
 
Net Beans Codes for Student Portal
Net Beans Codes for Student PortalNet Beans Codes for Student Portal
Net Beans Codes for Student PortalPeeyush Ranjan
 
Tools & tricks for testing React applications
Tools & tricks for testing React applications Tools & tricks for testing React applications
Tools & tricks for testing React applications React London Community
 
Swift Montevideo Meetup - iPhone, una herramienta medica
Swift Montevideo Meetup - iPhone, una herramienta medicaSwift Montevideo Meetup - iPhone, una herramienta medica
Swift Montevideo Meetup - iPhone, una herramienta medicaWashington Miranda
 
Scaling Crashlytics: Building Analytics on Redis 2.6
Scaling Crashlytics: Building Analytics on Redis 2.6Scaling Crashlytics: Building Analytics on Redis 2.6
Scaling Crashlytics: Building Analytics on Redis 2.6Crashlytics
 

What's hot (16)

The Ring programming language version 1.5.4 book - Part 71 of 185
The Ring programming language version 1.5.4 book - Part 71 of 185The Ring programming language version 1.5.4 book - Part 71 of 185
The Ring programming language version 1.5.4 book - Part 71 of 185
 
Rolebased security
Rolebased securityRolebased security
Rolebased security
 
Windows 8 Pure Imagination - 2012-11-25 - Extending Your Game with Windows 8 ...
Windows 8 Pure Imagination - 2012-11-25 - Extending Your Game with Windows 8 ...Windows 8 Pure Imagination - 2012-11-25 - Extending Your Game with Windows 8 ...
Windows 8 Pure Imagination - 2012-11-25 - Extending Your Game with Windows 8 ...
 
Data binding в массы!
Data binding в массы!Data binding в массы!
Data binding в массы!
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
 
Java Virtual Keyboard Using Robot, Toolkit and JToggleButton Classes
Java Virtual Keyboard Using Robot, Toolkit and JToggleButton ClassesJava Virtual Keyboard Using Robot, Toolkit and JToggleButton Classes
Java Virtual Keyboard Using Robot, Toolkit and JToggleButton Classes
 
An iOS Authentication Architecture for All
An iOS Authentication Architecture for AllAn iOS Authentication Architecture for All
An iOS Authentication Architecture for All
 
ES3-2020-P3 TDD Calculator
ES3-2020-P3 TDD CalculatorES3-2020-P3 TDD Calculator
ES3-2020-P3 TDD Calculator
 
Android testing
Android testingAndroid testing
Android testing
 
ReactJS for Programmers
ReactJS for ProgrammersReactJS for Programmers
ReactJS for Programmers
 
Removing structural duplication
Removing structural duplicationRemoving structural duplication
Removing structural duplication
 
10 Typical Enterprise Java Problems
10 Typical Enterprise Java Problems10 Typical Enterprise Java Problems
10 Typical Enterprise Java Problems
 
Net Beans Codes for Student Portal
Net Beans Codes for Student PortalNet Beans Codes for Student Portal
Net Beans Codes for Student Portal
 
Tools & tricks for testing React applications
Tools & tricks for testing React applications Tools & tricks for testing React applications
Tools & tricks for testing React applications
 
Swift Montevideo Meetup - iPhone, una herramienta medica
Swift Montevideo Meetup - iPhone, una herramienta medicaSwift Montevideo Meetup - iPhone, una herramienta medica
Swift Montevideo Meetup - iPhone, una herramienta medica
 
Scaling Crashlytics: Building Analytics on Redis 2.6
Scaling Crashlytics: Building Analytics on Redis 2.6Scaling Crashlytics: Building Analytics on Redis 2.6
Scaling Crashlytics: Building Analytics on Redis 2.6
 

Similar to JS Conf 2018 AU Node.js applications diagnostics under the hood

Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Matt Raible
 
MeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenmentMeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenmentArtur Szott
 
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...Techsylvania
 
Asynchronous JS in Odoo
Asynchronous JS in OdooAsynchronous JS in Odoo
Asynchronous JS in OdooOdoo
 
Developing a Joomla 3.x Component using RAD FOF- Part 2: Front-end + demo - J...
Developing a Joomla 3.x Component using RAD FOF- Part 2: Front-end + demo - J...Developing a Joomla 3.x Component using RAD FOF- Part 2: Front-end + demo - J...
Developing a Joomla 3.x Component using RAD FOF- Part 2: Front-end + demo - J...Peter Martin
 
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...Codemotion
 
jRecruiter - The AJUG Job Posting Service
jRecruiter - The AJUG Job Posting ServicejRecruiter - The AJUG Job Posting Service
jRecruiter - The AJUG Job Posting ServiceGunnar Hillert
 
Building and deploying React applications
Building and deploying React applicationsBuilding and deploying React applications
Building and deploying React applicationsAstrails
 
Building a js widget
Building a js widgetBuilding a js widget
Building a js widgetTudor Barbu
 
Build your own trello witihin 100 LOC (with Meteor)
Build your own trello witihin 100 LOC (with Meteor)Build your own trello witihin 100 LOC (with Meteor)
Build your own trello witihin 100 LOC (with Meteor)Andy Dai
 
Server side rendering with React and Symfony
Server side rendering with React and SymfonyServer side rendering with React and Symfony
Server side rendering with React and SymfonyIgnacio Martín
 
Application Security from the Inside - OWASP
Application Security from the Inside - OWASPApplication Security from the Inside - OWASP
Application Security from the Inside - OWASPSqreen
 
PRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docx
PRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docxPRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docx
PRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docxharrisonhoward80223
 
Logux, a new approach to client-server communication by Andrey Sitnik
Logux, a new approach to client-server communication by Andrey SitnikLogux, a new approach to client-server communication by Andrey Sitnik
Logux, a new approach to client-server communication by Andrey SitnikReact London 2017
 
Angular 1 + es6
Angular 1 + es6Angular 1 + es6
Angular 1 + es6장현 한
 
Troubleshooting real production problems
Troubleshooting real production problemsTroubleshooting real production problems
Troubleshooting real production problemsTier1 app
 
2016 W3C Conference #4 : ANGULAR + ES6
2016 W3C Conference #4 : ANGULAR + ES62016 W3C Conference #4 : ANGULAR + ES6
2016 W3C Conference #4 : ANGULAR + ES6양재동 코드랩
 
4 Node.js Gotchas: What your ops team needs to know
4 Node.js Gotchas: What your ops team needs to know4 Node.js Gotchas: What your ops team needs to know
4 Node.js Gotchas: What your ops team needs to knowDynatrace
 
What's new and exciting with JSF 2.0
What's new and exciting with JSF 2.0What's new and exciting with JSF 2.0
What's new and exciting with JSF 2.0Michael Fons
 

Similar to JS Conf 2018 AU Node.js applications diagnostics under the hood (20)

Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2
 
MeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenmentMeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenment
 
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
Cristiano Betta (Betta Works) - Lightweight Libraries with Rollup, Riot and R...
 
Asynchronous JS in Odoo
Asynchronous JS in OdooAsynchronous JS in Odoo
Asynchronous JS in Odoo
 
Developing a Joomla 3.x Component using RAD FOF- Part 2: Front-end + demo - J...
Developing a Joomla 3.x Component using RAD FOF- Part 2: Front-end + demo - J...Developing a Joomla 3.x Component using RAD FOF- Part 2: Front-end + demo - J...
Developing a Joomla 3.x Component using RAD FOF- Part 2: Front-end + demo - J...
 
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
 
jRecruiter - The AJUG Job Posting Service
jRecruiter - The AJUG Job Posting ServicejRecruiter - The AJUG Job Posting Service
jRecruiter - The AJUG Job Posting Service
 
Building and deploying React applications
Building and deploying React applicationsBuilding and deploying React applications
Building and deploying React applications
 
Building a js widget
Building a js widgetBuilding a js widget
Building a js widget
 
Build your own trello witihin 100 LOC (with Meteor)
Build your own trello witihin 100 LOC (with Meteor)Build your own trello witihin 100 LOC (with Meteor)
Build your own trello witihin 100 LOC (with Meteor)
 
Server side rendering with React and Symfony
Server side rendering with React and SymfonyServer side rendering with React and Symfony
Server side rendering with React and Symfony
 
Application Security from the Inside - OWASP
Application Security from the Inside - OWASPApplication Security from the Inside - OWASP
Application Security from the Inside - OWASP
 
PRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docx
PRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docxPRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docx
PRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docx
 
Logux, a new approach to client-server communication by Andrey Sitnik
Logux, a new approach to client-server communication by Andrey SitnikLogux, a new approach to client-server communication by Andrey Sitnik
Logux, a new approach to client-server communication by Andrey Sitnik
 
Angular 1 + es6
Angular 1 + es6Angular 1 + es6
Angular 1 + es6
 
Troubleshooting real production problems
Troubleshooting real production problemsTroubleshooting real production problems
Troubleshooting real production problems
 
[W3C HTML5 2016] Angular + ES6
[W3C HTML5 2016] Angular + ES6[W3C HTML5 2016] Angular + ES6
[W3C HTML5 2016] Angular + ES6
 
2016 W3C Conference #4 : ANGULAR + ES6
2016 W3C Conference #4 : ANGULAR + ES62016 W3C Conference #4 : ANGULAR + ES6
2016 W3C Conference #4 : ANGULAR + ES6
 
4 Node.js Gotchas: What your ops team needs to know
4 Node.js Gotchas: What your ops team needs to know4 Node.js Gotchas: What your ops team needs to know
4 Node.js Gotchas: What your ops team needs to know
 
What's new and exciting with JSF 2.0
What's new and exciting with JSF 2.0What's new and exciting with JSF 2.0
What's new and exciting with JSF 2.0
 

Recently uploaded

Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfkalichargn70th171
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 

Recently uploaded (20)

Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 

JS Conf 2018 AU Node.js applications diagnostics under the hood

  • 1. Node.js applications diagnostics under the hood Nikolay Matvienko 2018 1
  • 2. Author Nikolay Matvienko Full Stack JS developer at Grid Dynamics twitter: @matvi3nko facebook: matvienko.nikolay mail: matvi3nko@gmail.com github: @matvi3nko 2
  • 4. Diagnostics Node.js Diagnostics Working Group https://github.com/nodejs/diagnostics Post Mortem Diagnostics Working Group https://github.com/nodejs/post-mortem Work is divided into several domains: 1. Tracing Profiling Heap and Memory Analysis Step Debugging 2. Postmortem debugging 4
  • 5. Stages of Node.js diagnostics evolution before 2017 The first stage The second stage 5
  • 6. The third stage of Node.js diagnostics evolution The first stage The second stage The third stage 6
  • 7. 1. Diagnostic tools appeared with a delay. 2. Most tools didn’t support the latest version of V8 (Node.js ) 3. We had to choose: performance or tools 4. Or new tools appear, but without support for previous versions of Node. js V8 engine update 7
  • 8. Node.js in Enterprise Architecture Transperfect internationalization CDN 8 * This is a greatly simplified scheme Node.js Microservices app app app Node.js Web back-end app app app Akamai CDN Oracle Splunk NewRelic Redis Security Gateway Java apps AWS Services Catalog Web UIMobile Tealium Paypal Bazaar voice Olapic … and many other external services CDN scene Seven CMS Search Engine
  • 9. Black Friday = ~60% of the annual income. 9
  • 10. Agenda 1. Debugging in production 2. Performance profiling 3. Search for memory leaks 10
  • 11. 1. Debugging in production The reasons: 1. Uncaught Exception 2. Difficult reproducible errors 3. Production environment 4. ASAP 11
  • 13. module.exports = class ProductController { constructor (reservationService) { this._reservationService = reservationService; } reserve (req, res) { const { id, storeId } = req.cookies['profile']; const rewards = req.cookies['rewards']; const { products } = req.body; this._reservationService.reserve(id, storeId, rewards.id, products) .then(data => { return res.send(data); }); }}; Case 1. Product reservation. 13 Throws an Error when rewards is undefined
  • 14. Core dump creation algorithm for postmortem debugging Serving traffic uncaught exception abort() before the crash Restart app core dump debugging with llnode Fix 14 local node --abort-on-uncaught-exception app.js name: core.<PID> size: ~1.5GB > llnode -c /cores/core.<PID>
  • 15. Debugging steps 1. Get the Stack Trace and find the last JS function before the exit 2. Read the source code of the function 3. Get input parameters: request and response 15
  • 16. $ llnode -c /cores/core.13364 $(llnode) v8 bt frame #4: 0x3501dbc040dd <exit> frame #5: 0x3501dbceb5cc <builtin> frame #6: 0x3501dbc12f12 reserve(this=0x0153bf0e84d1:<Object: ProductController>, 0x163b0e223089:<Object: IncomingMessage>, 0x163b0e224e39:<Object: ServerResponse>) at /demo/controllers/ProductController.js:8:11 fn=0x04c146ed3fa1 frame #7: 0x3501dbcf3fa1 <builtin> frame #8: 0x3501dbc12f12 (anonymous)(this=0x163b0e223089:<Object: IncomingMessage>) at /demo/app.js:21:28 fn=0x163b0e227699 frame #9: 0x3501dbcf373c <builtin> frame #10: 0x3501dbc12f12 emitNone(this=0x0b9b56e02241:<undefined>, 0x163b0e2278a9:<Array: …. Step 1. Get the Stack Trace and find the last JS function 16 starts llnode debugger with core dump returns JS and C++ Stack Trace addresses in the Memory
  • 17. Step 2. Read the source code of the function (llnode) v8 inspect --print-source 0x4c146ed3fa1 0x04c146ed3fa1:<function: reserve at /demo/controllers/ProductController.js:8:11 source: const { id, storeId } = req.cookies['profile']; const rewards = req.cookies['rewards']; const { products } = req.body; this._reservationService.reserve(id, storeId, rewards.id, products) .then(data => { return res.send(data); } ); 17
  • 18. Step 3. Get input parameter – request $(llnode) v8 bt 20 frame #4: 0x3501dbc040dd <exit> frame #5: 0x3501dbceb5cc <builtin> frame #6: 0x3501dbc12f12 reserve(this=0x0153bf0e84d1:<Object: ProductController>, 0x163b0e223089:<Object: IncomingMessage>, 0x163b0e224e39:<Object: ServerResponse>) at /demo/controllers/ProductController.js:8:11 fn=0x04c146ed3fa1 frame #7: 0x3501dbcf3fa1 <builtin> frame #8: 0x3501dbc12f12 (anonymous)(this=0x163b0e223089:<Object: IncomingMessage>) at /demo/app.js:21:28 fn=0x163b0e227699 frame #9: 0x3501dbcf373c <builtin> frame #10: 0x3501dbc12f12 emitNone(this=0x0b9b56e02241:<undefined>, 0x163b0e2278a9:<Array: length=2>,0x0b9b56e022f1:<false>, 0x163b0e223089:<Object: IncomingMessage>) at events.js:103:18 fn=0x0f2606a87391 …. frame #20: ... 18
  • 19. Step 3 result. Request object $(llnode) v8 inspect 0x163b0e223089 0x163b0e223089:<Object: IncomingMessage properties { ._events=0x163b0e223739:<Object: Object>, .socket=0x163b0e21e4e1:<Object: Socket>, .complete=0x0b9b56e022c1:<true>, .cookies=0x5c4b0e863755:<Object: Object>, .headers=0x163b0e223d11:<Object: Object>, .(external)=0x163b0e223069:<String: "/product/reserve">, .method=0x04c146ed42a1:<String: "POST">, .statusCode=0x0b9b56e02211:<null>, .statusMessage=0x0b9b56e02211:<null>, .body=0x163b0e22aee1:<Object: Object>}> … 19 $(llnode) v8 inspect 0x5c4b0e863755 0x5c4b0e863755:<Object: Object properties { .profile=0x3d76d2184b41:<Object: Object>, .rewards=0x163b0e22af51:<undefined>}>
  • 20. Case 1. Informative Stack Trace $(llnode) v8 bt frame #4: 0x3501dbc040dd <exit> frame #5: 0x3501dbceb5cc <builtin> frame #6: 0x3501dbc12f12 reserve(this=0x0153bf0e84d1:<Object: ProductController>, 0x163b0e223089:<Object: IncomingMessage>, 0x163b0e224e39:<Object: ServerResponse>) at /demo/controllers/ProductController.js:8:11 fn=0x04c146ed3fa1 frame #7: 0x3501dbcf3fa1 <builtin> frame #8: 0x3501dbc12f12 (anonymous)(this=0x163b0e223089:<Object: IncomingMessage>) at /demo/app.js:21:28 fn=0x163b0e227699 frame #9: 0x3501dbcf373c <builtin> frame #10: 0x3501dbc12f12 emitNone(this=0x0b9b56e02241:<undefined>, 0x163b0e2278a9:<Array: length=2>,0x0b9b56e022f1:<false>, 0x163b0e223089:<Object: IncomingMessage>) at events.js:103:18 fn=0x0f2606a87391 …. 20
  • 21. reserve (req, res, next) { const { id, storeId } = req.cookies['profile']; const rewards = req.cookies['rewards']; const products = req.body; this._reservationService.reserve(id, storeId, rewards, products) .then(data => { return res.send(data); }); // NO CATCH block is here and next() is not used } Case 2. Unhandled rejection reserve() throws an Error sinse expect the rewards.id 21
  • 22. reserve (req, res, next) { const { id, storeId } = req.cookies['profile']; const rewards = req.cookies['rewards']; const products = req.body; this._reservationService.reserve(id, storeId, rewards, products) .then(data => { return res.send(data); }); // NO CATCH block is here and next() is not used } process.on('unhandledRejection', (reason, p) => { logger.error('Unhandled Rejection at:', p, 'reason:', reason); process.abort(); }); Case 2. Unhandled rejection 22
  • 23. Case 2. Uninformative Stack Trace $(llnode) v8 bt frame #8: 0x2262d63840dd <exit> frame #9: 0x2262d64735e9 <builtin> frame #10: 0x2262d6392f12 process.on(this=0x18901b589ec1:<Object: process>, 0x27a40a5f15d9:<unknown>, 0x27a40a5f11a9:<unknown>) at /demo/app.js:40:34 fn=0x0af20adefc91 frame #11: 0x2262d6472cc8 <builtin> frame #12: 0x2262d6392f12 emitTwo(this=0x3e5911182241:<undefined>, 0x0af20adefc91:<function: process.on at /demo/app.js:40:34>, 0x3e59111822c1:<true>, 0x18901b589ec1:<Object: process>, 0x27a40a5f15d9:<unknown>, 0x27a40a5f11a9:<unknown>) at events.js:123:17 fn=0x368a12a07421 frame #13: 0x2262d6473a25 <builtin> frame #14: 0x2262d6392f12 emit(this=0x18901b589ec1:<Object: process>, 0x368a12a373e1:<String: "unhandledRejecti...">) at events.js:155:44 fn=0x3ef321f07b19 23
  • 24. Case 2. Finding all req object instances $(llnode) v8 findjsinstances IncomingMessage ... 0x0af20adff4a1:<Object: IncomingMessage> 0x25c630d8fe69:<Object: IncomingMessage> 0x25c630d97861:<Object: IncomingMessage> 0x25c630d9d811:<Object: IncomingMessage> 0x25c630da9729:<Object: IncomingMessage> 0x25c630daf8d9:<Object: IncomingMessage> 0x25c630dbb669:<Object: IncomingMessage> 0x25c630dc1591:<Object: IncomingMessage> 0x25c630dd6c31:<Object: IncomingMessage> 0x25c630ddcb59:<Object: IncomingMessage> 0x25c630de2ed1:<Object: IncomingMessage> 0x25c630de8d01:<Object: IncomingMessage> 0x25c630deec29:<Object: IncomingMessage> … 24 N
  • 25. Case 2. Which request crashed the process $(llnode) v8 findjsinstances IncomingMessage ... 0x0af20adff4a1:<Object: IncomingMessage> 0x25c630d8fe69:<Object: IncomingMessage> 0x25c630d97861:<Object: IncomingMessage> 0x25c630d9d811:<Object: IncomingMessage> 0x25c630da9729:<Object: IncomingMessage> 0x25c630daf8d9:<Object: IncomingMessage> 0x25c630dbb669:<Object: IncomingMessage> 0x25c630dc1591:<Object: IncomingMessage> 0x25c630dd6c31:<Object: IncomingMessage> 0x25c630ddcb59:<Object: IncomingMessage> 0x25c630de2ed1:<Object: IncomingMessage> 0x25c630de8d01:<Object: IncomingMessage> 0x25c630deec29:<Object: IncomingMessage> … 25
  • 26. Case 2. List of the killed requests in current process $(llnode) v8 findjsinstances IncomingMessage ... 0x0af20adff4a1:<Object: IncomingMessage> 0x25c630d8fe69:<Object: IncomingMessage> 0x25c630d97861:<Object: IncomingMessage> 0x25c630d9d811:<Object: IncomingMessage> 0x25c630da9729:<Object: IncomingMessage> 0x25c630daf8d9:<Object: IncomingMessage> 0x25c630dbb669:<Object: IncomingMessage> 0x25c630dc1591:<Object: IncomingMessage> 0x25c630dd6c31:<Object: IncomingMessage> 0x25c630ddcb59:<Object: IncomingMessage> 0x25c630de2ed1:<Object: IncomingMessage> 0x25c630de8d01:<Object: IncomingMessage> 0x25c630deec29:<Object: IncomingMessage> … 26 add X-Transaction-ID Event Loop request response
  • 27. Case 2. Search headers by the value of request ID $(llnode) v8 findrefs --string "6af9c8d5-1b18-48b0-86fc-b9aac43b3cd6" 0x25c630deef01: Object.X-Transaction-ID=0x25c630deea51 '6af9c8d5-1b18-48b0-86fc-b9aac43b3cd6' 27 string address address of parent object - headers
  • 28. Case 2. Search request by address of headers object $(llnode) v8 findrefs --string "6af9c8d5-1b18-48b0-86fc-b9aac43b3cd6" 0x25c630deef01: Object.X-Transaction-ID=0x25c630deea51 '6af9c8d5-1b18-48b0-86fc-b9aac43b3cd6' $(llnode) v8 findrefs --value 0x25c630deef01 0x27a40a5bbce9: IncomingMessage.headers=0x25c630deef01 28 the request object that we need
  • 29. module.exports = class ReservationService { ... reserve (id, storeId, rewardsId, products) { // id = 'ff104cde3452332e0cc6' return Promise.all([ this._rest.GET('user', id), this._db.getStore(storeId, rewardsId) ]).then(([user, rewardsInStore]) => { const data = { user, products, rewardsInStore }; return this._rest.POST('reserve', data); }); }}; Search for local variables 29 v8 findrefs --string "'ff104cde3452332e0cc6'" v8 findrefs --name "rewardsInStore" v8 findrefs --string "jeans-xxl" Middleware Controller Service Storage
  • 30. node-report Event: exception, location: "OnUncaughtException" Dump event time: 2017/09/27 00:57:26 Process ID: 35866 ==== JavaScript Stack Trace ==================================== Object.fs.readFileSync (fs.js:1:1) ProductController.reserve (/demo/controllers/ProductController.js:1:1) ==== Native Stack Trace ======================================== 0: [pc=0x1023eb7b1] nodereport::OnUncaughtException(v8::Isolate*) 1: [pc=0x1006da003] v8::internal::Isolate::Throw(v8::internal::Object*) ==== JavaScript Heap and Garbage Collector ====================== Heap space name: new_space Memory size: 4,194,304 bytes, committed memory: 2,116,048 bytes Capacity: 2,062,336 bytes, used: 824,392 bytes, available: 1,237,944 byte Heap memory limit: 1,501,560,832 30 Where? What? When?
  • 32. I use core dump! 32
  • 33. I use core dump! Let’s the debugging begin! 33
  • 34. I use core dump! Let’s the debugging begin! What is the difference between all of them? 34
  • 35. I use core dump! Let’s the debugging begin! What is the difference between all of them? 35 Boss: How much time do you need to solve the issue? Core dump flood
  • 36. const gencore = require('gencore'); const errorRegistry = new ErrorRegistry(redisClient); app.use( function errorHandlerMiddleware (err, req, res, next) { errorRegistry.add(err, req) .then(result => { if (result) { // was error added to registry gencore.collectCore((error, name) => { logger.info(`Core dump created at: ${name} for request: ${req.headers['X-Transaction-ID']}`); }); } // … send 500 status }) .catch(err => { … // handleError(err, req, res, next); }) }); Error handler with Error Registry and gencore 36 npm install --save-dev gencore Makes process fork and creates core dump core dump * This is the simplified example error selection logic
  • 37. Core dump creation algorithm in production Serving Traffic Error Handler core dump logs Request ID Fix No Yes 37 caught create dump? gencore process fork abort Restart node-report report abort core dump write log read in Splunk llnode No Yes
  • 38. Core dump creation algorithm in production Serving Traffic Error Handler core dump logs Request ID Fix No Yes 38 caught create dump? gencore process fork abort Restart node-report report abort core dump write log read in Splunk llnode No Yes
  • 39. Core dump creation algorithm in production Serving Traffic Error Handler core dump logs Request ID Fix No Yes 39 caught create dump? gencore process fork abort Restart node-report report abort core dump write log read in Splunk llnode No Yes
  • 40. Core dump creation algorithm in production Serving Traffic Error Handler core dump logs Request ID Fix No Yes 40 caught create dump? gencore process fork abort Restart node-report report abort core dump write log read in Splunk llnode No Yes
  • 41. Core dump creation algorithm in production Serving Traffic Error Handler core dump logs Request ID Fix No Yes 41 caught create dump? gencore process fork abort Restart node-report report abort core dump write log read in Splunk llnode No Yes
  • 42. Core dump creation algorithm in production Serving Traffic Error Handler core dump logs Request ID Fix No Yes 42 caught create dump? gencore process fork abort Restart node-report report abort core dump write log read in Splunk llnode No Yes
  • 43. Core dump creation algorithm in production Serving Traffic Error Handler core dump logs Request ID Fix No Yes 43 caught create dump? gencore process fork abort Restart node-report report abort core dump write log read in Splunk llnode No Yes
  • 44. Core dump creation algorithm in production Serving Traffic Error Handler core dump logs Request ID Fix No Yes 44 caught create dump? gencore process fork abort Restart node-report report abort core dump write log read in Splunk llnode No Yes
  • 45. Tips 1. Follow to Error handling best practices 2. Call abort() only in centralized error handler 3. Use gencore 4. Use node-report to generate a report 5. Track requests using id – X-Transaction-ID or X-Request-ID (NGINX) header (or Zipkin headers) 6. Avoid core dump flood 45
  • 46. Progress 1. Debugging in production ✔ 2. Performance profiling 3. Search for memory leaks 46
  • 47. 2. The response of the Node.js web server has grown from ~300 to ~1500 ms 47
  • 48. Profiling: node --prof(iler) + apache bench/JMeter node --prof app.js and node --prof-process isolate-0x-v8.log > profile.txt [Summary]: ticks total nonlib name 2710 18.9% 19.0% JavaScript 13348 58.7% 58.9% C++ 561 2.5% 2.5% GC [JavaScript]: 112 0.5% 0.5% Builtin: CallFunction_ReceiverIsNotNullOrUndefined 4 0.0% 0.0% LazyCompile: *emit events.js:136:44 42 15.2% 15.2% presentation/handlebars/helpers/urlBuilder.helper.js:51:37 2 0.0% 0.0% LazyCompile: ~substr native string.js:324:22 ... [C++]: 1292 5.7% 5.7% node::ContextifyScript::New(v8::FunctionCallbackInfo<v8::Value> const&) ... 48
  • 49. 49
  • 50. 50 modules App logic logic in handlebars templates fs lodash page rendering partials/helpers hbspartials/helpers ~65% on page rendering (SSR) ~20% on lodash operations with data ~10% on data retrieval from API (Promises) Application spends:
  • 52. 52 lodash baseMerge, baseMergeDeep forEach, lodash cloneDeep Data processing
  • 53. Performance improvements After performance profiling with perf, DTrace, 0x and bcc utils we: ▪ Reduced CPU intensive operations: a. lodash objects merge, deep clone b. long cycles c. JSON parse ▪ Removed logic from view templates and helpers ▪ Reviewed and updated npm dependencies ▪ Gradually implemented React SSR 53
  • 54. 54 3d party libraries page rendering <15% App main logicAPI callsApp logic 3d party libraries SSR
  • 55. Tips 55 1. Performance should be a part of requirements. 2. Measure performance before embedding third-party libraries and after 3. Collect measurement results archive 4. Profile on staging/pre-production environments 5. Monitor diagnostic tools performance impact
  • 56. 3. Memory grows Ways to identify: ▪ Application Monitoring tools (N|Solid, NewRelic) ▪ DTrace, Instruments, perf ▪ node-memwatch ▪ GC Tracing ▪ Valgrind for C++ modules ▪ heapdump ▪ Fatal error ▪ and other... 56
  • 57. Case: Excessive garbage collection. The creation a lot of new objects 57 GC rate grows in New Space (Scavenge GC)
  • 58. 256201 ms: Scavenge 824.5 (1014.4) -> 811.4 (1016.2) MB, 16.9 / 0.0 ms [allocation failure]. 256218 ms: Scavenge 838.8 (1019.3) -> 827.7 (1024.7) MB, 17.6 / 0.0 ms [allocation failure]. 256236 ms: Scavenge 852.8 (1024.7) -> 842.9 (1026.5) MB, 11.0 / 0.0 ms [allocation failure]. 256557 ms: Scavenge 869.8 (1201.6) -> 858.1 (1209.6) MB, 33.3 / 0.0 ms (+ 86.0 ms in 176 steps since last GC) [allocation failure]. 256925 ms: Scavenge 884.1 (1232.8) -> 871.9 (1239.2) MB, 36.5 / 0.0 ms (+ 56.7 ms in 168 steps since last GC) [allocation failure]. Case: Scavenge GC in New Space. 58 Long Garbage collectionMemory grows Interval node --trace_gc --trace_gc_verbose app.js > gc-trace.log
  • 59. { "name": "LazyCompile:~insert /Users/nmatvienko/projects/x/src/cms/cmsHelper.js:806", "children": { "name": "LazyCompile:*replace native string.js:132", "children": [ { "name": "Stub:CEntryStub", "children": [ { "name": "v8::internal::Scavenger::ScavengeObjectSlow" } Garbage collection Profiling replace native string v8::internal::Heap::CollectGarbage insert CmsHelper v8::internal::Heap::Scavenge() v8::internal::ScavengingVisitor Operation that requested memory allocation JS V8 GC Flame Graph node Text representationVisual representation
  • 60. { "name": "LazyCompile:~ /Users/nmatvienko/projects/x/api/domain/product/mappers/ProductMapper.js:11", "value": 1240, "top": 2, "children": [ … { "name": "LazyCompile:*map native array.js:994", "value": 1025, "top": 20, "children": [ ... { "name": "Stub:CEntryStub", "value": 41, "top": 32, "children": [ { "name": "node`v8::internal::Scavenger::ScavengeObject", "value": 2, "top": 2 }, { "name": "node`v8::internal::Space::AllocationStep", "value": 1, "top": } ] Garbage collection in New Space Operation that requested allocation of memory
  • 61. 172047 ms: Scavenge 546.9 (592.6) -> 538.4 (592.6) MB, 1.5 / 0.0 ms [allocation failure]. 172093 ms: Scavenge 547.8 (593.6) -> 534.0 (593.6) MB, 2.8 / 0.0 ms [allocation failure]. 172136 ms: Scavenge 549.1 (594.6) -> 535.0 (595.6) MB, 2.2 / 0.0 ms [allocation failure]. 172202 ms: Scavenge 550.4 (595.6) -> 536.3 (596.6) MB, 3.3 / 0.0 ms (+ 14.3 ms in 206 steps since last GC) [allocation failure]. 172269 ms: Scavenge 551.6 (596.6) -> 537.1 (597.6) MB, 3.9 / 0.0 ms (+ 15.5 ms in 238 steps since last GC) [allocation failure]. GC tracing in New Space after improvements 61 Garbage collection timeMemory doesn’t grow
  • 62. Case: Many references, missed closures and timers. GC in Old Space 168372 ms: Mark-sweep 493.7 (558.6) -> 151.4 (352.1) MB, 90.3 ms (+ 150.3 ms in 731 steps, biggest step 18.1 ms) 134838 ms: Mark-sweep 525.3 (680.7) -> 169.7 (366.8) MB, 91.2 ms (+ 157.0 ms in 790 steps, biggest step 14.2 ms) … 300609 ms: Mark-sweep 664.8 (825.1) -> 192.0 (387.1) MB, 110.4 ms (+ 193.8 ms in 982 steps, biggest step 19.5 ms) 956609 ms: Mark-sweep 1164.8 (1325.1) -> 792.0 (1007.1) MB, 214.2 ms (+ 296.8 ms in 1482 steps, biggest step 19.5 ms) 990164 ms: Mark-sweep 1183.8 (1405.1) -> 799.0 (1124.1) MB, 216.7 ms (+ 307.7 ms in 1496 steps, biggest step 20.7 ms) 62 Long garbage collection
  • 63. $(llnode) v8 findjsobjects Instances Total Size Name ---------- ---------- ---- 251 88216 ServerResponse 251 58440 IncomingMessage 40 9920 Socket 42 9408 WritableState 93 34016 ReadableState 94 15528 BufferList 86 6880 Module 194 12504 TickObject 3688 118016 (Array) 250 21920 Timeout 31043 369864 (String) … Get all JS objects from the Heap using llnode 63
  • 64. $(llnode) v8 findjsinstances IncomingMessage 0xaf20adff4a1:<Object: IncomingMessage> 0x25c630d8fe69:<Object: IncomingMessage> 0x25c630d97861:<Object: IncomingMessage> 0x25c630d9d811:<Object: IncomingMessage> 0x25c630da37c9:<Object: IncomingMessage> 0x25c630daf8d9:<Object: IncomingMessage> 0x25c630db5741:<Object: IncomingMessage> 0x25c630dbb669:<Object: IncomingMessage> 0x25c630dc1591:<Object: IncomingMessage> 0x25c630dd6c31:<Object: IncomingMessage> 0x27a40a588a11:<Object: IncomingMessage> 0x27a40a58e841:<Object: IncomingMessage> 0x27a40a5a38f1:<Object: IncomingMessage> 0x27a40a5a9819:<Object: IncomingMessage> Find all IncomingMessage instances 64
  • 65. $(llnode) v8 findjsinstances IncomingMessage 0xaf20adff4a1:<Object: IncomingMessage> 0x25c630d8fe69:<Object: IncomingMessage> 0x25c630d97861:<Object: IncomingMessage> 0x25c630d9d811:<Object: IncomingMessage> 0x25c630da37c9:<Object: IncomingMessage> 0x25c630daf8d9:<Object: IncomingMessage> 0x25c630db5741:<Object: IncomingMessage> 0x25c630dbb669:<Object: IncomingMessage> 0x25c630dc1591:<Object: IncomingMessage> 0x25c630dd6c31:<Object: IncomingMessage> 0x27a40a588a11:<Object: IncomingMessage> 0x27a40a58e841:<Object: IncomingMessage> 0x27a40a5a38f1:<Object: IncomingMessage> 0x27a40a5a9819:<Object: IncomingMessage> Find req object holders 65 $(llnode) v8 findrefs -v 0xaf20adff4a1 0x25c630d8ada1: (Array)[250]=0xaf20adff4a1 0x25c630d83329: ServerResponse.req=0xaf20adff4a1
  • 66. $(llnode) v8 findjsinstances IncomingMessage 0xaf20adff4a1:<Object: IncomingMessage> 0x25c630d8fe69:<Object: IncomingMessage> 0x25c630d97861:<Object: IncomingMessage> 0x25c630d9d811:<Object: IncomingMessage> 0x25c630da37c9:<Object: IncomingMessage> 0x25c630daf8d9:<Object: IncomingMessage> 0x25c630db5741:<Object: IncomingMessage> 0x25c630dbb669:<Object: IncomingMessage> 0x25c630dc1591:<Object: IncomingMessage> 0x25c630dd6c31:<Object: IncomingMessage> 0x27a40a588a11:<Object: IncomingMessage> 0x27a40a58e841:<Object: IncomingMessage> 0x27a40a5a38f1:<Object: IncomingMessage> 0x27a40a5a9819:<Object: IncomingMessage> Find all IncomingMessage instances 66 $(llnode) v8 findrefs -v 0x0af20adff4a1 0x25c630d8ada1: (Array)[250]=0xaf20adff4a1 0x25c630d83329: ServerResponse.req=0xaf20adff4a1 $(llnode) v8 findrefs -v 0x25c630d8ada1 0x3b312aee27d9: ProfileMiddleware._requests =0x25c630d8ada1
  • 67. Tips 1. Control the Life Cycle of app Objects and Sessions 2. Trace Scavenge GC in Profiler Stacks to find allocation cause (bcc/tools/stackcount.py) 3. Use D8 to check Javascript behavior in V8 (%DebugTrackRetainingPath(x)) 4. Call GC manually to check memory allocation 5. Write memory usage tests for code and libraries with leakage 6. Create heapdump/ coredump for deep investigation 67
  • 68. Result 1 month before 3 weeks of investigation and refactoring After improvements original time has been grown x4 68 new baseline
  • 69. Nikolay Matvienko mail: matvi3nko@gmail.com twitter: @matvi3nko github: @nickkooper Linked-in nikolaymatvienko 69 Resources https://github.com/nickkooper/ nodejs-diagnostics-resources