preface

In the process of page performance tuning, many front-end engineers pay less attention to the execution efficiency of the code itself and more attention to the network consumption, such as resource consolidation to reduce the number of requests, compression to reduce the size of resources, caching, etc. I don’t think it’s not reasonable, instead, to a great extent, this is the right thing to do enough, for example, JS itself is the execution time of 30 ms (ms), in the page load time at 35 seconds is too low a proportion, spelled a life even 10 times the performance improvement, execution time dropped to 3 ms, the overall performance is insignificant, Not even at the user level. It is therefore more sensible to optimize for other large performance costs.

However, from the node.js (server) perspective, the execution time of JS itself becomes critical. As in the previous example, if the execution time drops from 30ms to 3ms, theoretically QPS can be increased by 10 times. In other words, the traffic that used to take 10 servers can now be carried by 1 server, and the response time is much shorter.

How do you optimize Node performance?

methods

There are two ways to do it, One is through the Node/V8’s own ability to profile (https://nodejs.org/uk/docs/guides/simple-profiling/), The other is through alinode’s (http://alinode.alibaba-inc.com/) CPU profile feature. The former only lists the execution ratio of each function, while the latter includes a more complete call stack, which is more readable and easier to locate problems. Therefore, the latter is recommended.

Method 1: Node comes with a profile

  • Step 1: Start the Node application with the –prof parameter


     
  1. $ node --prof index.js

Copy the code
  • Step 2: through pressure measuring tools a loadtest (https://github.com/alexfernandez/loadtest) to the service pressure


     
  1. $ loadtest  http://127.0.0.1:6001 --rps 10

Copy the code
  • Step 3: Process the generated log file


     
  1. $ node --prof-process isolate-0XXXXXXXXXXX-v8-XXXX.log > profile.txt

Copy the code
  • Step 4: Analyze the profile.txt file

Profile. TXT file below, including how many ticks, JS and c + + code consumption each concrete analysis methods can be found in the node profile document (https://nodejs.org/uk/docs/guides/simple-profiling/)

Method 2: ALinode’s CPU profile

  • Step 1: Install alinode

Alinode is a binary runtime environment that is fully compatible with Node Community edition and is recommended to be installed using TNVM tools


     
  1. $ wget -O- https://raw.githubusercontent.com/aliyun-node/tnvm/master/install.sh | bash

Copy the code

After the installation is complete, TNVM needs to be added as a command line program. Depending on the platform, this may be ~/.bashrc, ~/.profile, or ~/.zshrc, etc


     
  1. $ source ~/.zshrc

Copy the code

For example, alinode-v3.8.0, corresponding to Node-v8.9.0, download this version and enable it


     
  1. $TNVM install alinode - v3.8.0

  2. $TNVM use alinode - v3.8.0

Copy the code
  • Step 2: Start the application with the installed Alinode runtime


     
  1. $ node --perf-basic-prof-only-functions index.js

Copy the code
  • Step 3: through pressure measuring tools a loadtest (https://github.com/alexfernandez/loadtest) to the service pressure


     
  1. $ loadtest  http://127.0.0.1:6001 --rps 10

Copy the code
  • Step 4: CPU profile

Assuming the starting worker process number is 6989, execute the following script: Three minutes later, a cpuprofile file/TMP/cpu-profile-6899-xxx will be generated in the/TMP/directory. See the cpuprofile script for details take_cpu_profile.sh(https://github.com/alibaba/beidou/blob/master/scripts/take cpuprofile.sh)


     
  1. $ sh take_cpu_profile.sh 6989

Copy the code
  • Step 5: Import the generated CPUProfile file into Chrome Developer Tools for analysis

In actual combat

The following shows how to do performance tuning step by step with a real life example.

1000 requests are made by loadtest, and the average RT is calculated. The initial RT is 15.8ms

Excluding program and GC costs, the top three performance costs are get, J and _eval, respectively

Expand the most expensive get method call stack to locate the location of the GET method as shown in the following code


     
  1. {

  2.    key: 'get',

  3.    value: function get(propName) {

  4. if (! this.state[propName]) {

  5.        return null;

  6.      }

  7.      return JSON.parse(JSON.stringify(this.state[propName]));

  8.    }

  9.  }

Copy the code

In the body of the method, json.parse (json.stringify (obj)), while easy to use, is CPU intensive. Return this.state[propName]. RT time reduced to 12.3ms

Parse (json.stringify (obj))) should not be removed directly as this will affect the business logic. For details about performance comparison of common copy methods (http://jsben.ch/bWfk9), configure ladders. Screenshot below:

Among them, LoDash Deep Clone has the best performance, which is replaced by the library. After verification again, RT is reduced to 12.8ms

The second performance cost is the J method, which mostly contains the render time of each component. Skip it for now and optimize the _eval method in the same way. RT is reduced to 10.1ms.

In the same way, find out the performance consumption points according to the CPU profile and optimize them one by one.

Remark: This article first published in beidou isomorphism lot (https://github.com/alibaba/beidou/blob/master/packages/beidou-docs/articles/node-performance-optimizat Ion.md), reproduced please indicate the source.