SlideShare a Scribd company logo
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 185
Mahmoud 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 Classes
Abdul 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 Calculator
David Rodenas
 
Android testing
Android testingAndroid testing
Android testing
Sean Tsai
 
ReactJS for Programmers
ReactJS for ProgrammersReactJS for Programmers
ReactJS for Programmers
David Rodenas
 
Removing structural duplication
Removing structural duplicationRemoving structural duplication
Removing structural duplication
Alexandru 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 medica
Washington 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 2
Matt Raible
 
MeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenmentMeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenment
Artur 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 Odoo
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...
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 Service
Gunnar Hillert
 
Building and deploying React applications
Building and deploying React applicationsBuilding and deploying React applications
Building and deploying React applications
Astrails
 
Building a js widget
Building a js widgetBuilding a js widget
Building a js widget
Tudor 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 Symfony
Ignacio Martín
 
Application Security from the Inside - OWASP
Application Security from the Inside - OWASPApplication Security from the Inside - OWASP
Application Security from the Inside - OWASP
Sqreen
 
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
harrisonhoward80223
 
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
React 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 problems
Tier1 app
 
2016 W3C Conference #4 : ANGULAR + ES6
2016 W3C Conference #4 : ANGULAR + ES62016 W3C Conference #4 : ANGULAR + ES6
2016 W3C Conference #4 : ANGULAR + ES6
양재동 코드랩
 
[W3C HTML5 2016] Angular + ES6
[W3C HTML5 2016] Angular + ES6[W3C HTML5 2016] Angular + ES6
[W3C HTML5 2016] 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
Dynatrace
 
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
Michael 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
 
2016 W3C Conference #4 : ANGULAR + ES6
2016 W3C Conference #4 : ANGULAR + ES62016 W3C Conference #4 : ANGULAR + ES6
2016 W3C Conference #4 : ANGULAR + ES6
 
[W3C HTML5 2016] Angular + ES6
[W3C HTML5 2016] Angular + ES6[W3C HTML5 2016] Angular + ES6
[W3C HTML5 2016] 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

First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
Globus
 
Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024
Sharepoint Designs
 
Why React Native as a Strategic Advantage for Startup Innovation.pdf
Why React Native as a Strategic Advantage for Startup Innovation.pdfWhy React Native as a Strategic Advantage for Startup Innovation.pdf
Why React Native as a Strategic Advantage for Startup Innovation.pdf
ayushiqss
 
Advanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowAdvanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should Know
Peter Caitens
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
Juraj Vysvader
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
Matt Welsh
 
Vitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume MontevideoVitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume Montevideo
Vitthal Shirke
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
Tier1 app
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns
 
Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
Tendenci - The Open Source AMS (Association Management Software)
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
Max Andersen
 
Designing for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web ServicesDesigning for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web Services
KrzysztofKkol1
 
Software Testing Exam imp Ques Notes.pdf
Software Testing Exam imp Ques Notes.pdfSoftware Testing Exam imp Ques Notes.pdf
Software Testing Exam imp Ques Notes.pdf
MayankTawar1
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
abdulrafaychaudhry
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Globus
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
Ortus Solutions, Corp
 
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
XfilesPro
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
wottaspaceseo
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
Paco van Beckhoven
 

Recently uploaded (20)

First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
 
Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024
 
Why React Native as a Strategic Advantage for Startup Innovation.pdf
Why React Native as a Strategic Advantage for Startup Innovation.pdfWhy React Native as a Strategic Advantage for Startup Innovation.pdf
Why React Native as a Strategic Advantage for Startup Innovation.pdf
 
Advanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowAdvanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should Know
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
 
Vitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume MontevideoVitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume Montevideo
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
 
Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
 
Designing for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web ServicesDesigning for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web Services
 
Software Testing Exam imp Ques Notes.pdf
Software Testing Exam imp Ques Notes.pdfSoftware Testing Exam imp Ques Notes.pdf
Software Testing Exam imp Ques Notes.pdf
 
Lecture 1 Introduction to games development
Lecture 1 Introduction to games developmentLecture 1 Introduction to games development
Lecture 1 Introduction to games development
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
 
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
 

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