When browsing the internet, we all know that encryption via SSL is very important. At PayPal, security is our top priority. We use end-to-end encryption, not just our public websites, but also for our internal service calls. SSL encryption technology will greatly affect the performance of node.js. We have taken the time to adjust our external services and make the most of them. Here is a list of some SSL configuration tuning that we found to significantly improve SSL's external performance.
SSL Password
Out of the box, Node.js' SSL uses a very powerful set of password algorithms. In particular, Difee Hermann key exchange and elliptic curve algorithms are extremely expensive. And when you use too many external SSL calls in the default configuration, the performance of Node.js will be fundamentally weakened. In order to get the conclusion how slow it is, here is a CPU sample of the service call:
918834.0ms 100.0% 0.0 node (91770)911376.0ms 99.1% 0.0 start911376.0ms 99.1% 0.0 node::Start911363.0ms 99.1% 48.0 uv_run909839.0ms 99.0% 438.0 uv__io_poll876570.0ms 95.4% 849.0 uv__stream_io873590.0ms 95.0% 32.0 node::StreamWrap::OnReadCommon873373.0ms 95.0% 7.0 node::MakeCallback873265.0ms 95.0% 15.0 node::MakeDomainCallback873125.0ms 95.0% 61.0 v8::Function::Call873049.0ms 95.0% 13364.0 _ZN2v88internalL6InvokeEbNS0832660.0ms 90.6% 431.0 _ZN2v88internalL21Builtin821687.0ms 89.4% 39.0 node::crypto::Connection::ClearOut813884.0ms 88.5% 37.0 ssl23_connect813562.0ms 88.5% 54.0 ssl3_connect802651.0ms 87.3% 35.0 ssl3_send_client_key_exchange417323.0ms 45.4% 7.0 EC_KEY_generate_key383185.0ms 41.7% 12.0 ecdh_compute_key1545.0ms 0.1% 4.0 tls1_generate_master_secret123.0ms 0.0% 4.0 ssl3_do_write...
Let's focus on the generation of keys:
802651.0ms 87.3% 35.0 ssl3_send_client_key_exchange417323.0ms 45.4% 7.0 EC_KEY_generate_key383185.0ms 41.7% 12.0 ecdh_compute_key
87% of this call is spent on generating the key!
These passwords can be changed to reduce intensive computing. This idea has been implemented in https (or proxy). For example:
var agent = new https.Agent({ "key": key, "cert": cert, "ciphers": "AES256-GCM-SHA384"});The above keys are no longer exchanged with the expensive Diffie Herman keys. After replacing something similar, we can see significant changes in the following example:
...57945.0ms 32.5% 16.0 ssl3_send_client_key_exchange28958.0ms 16.2% 9.0 generate_key26827.0ms 15.0% 2.0 compute_key...
With the OpenSSL documentation, you can learn more about password strings.
SSL session recovery
If your server supports SSL session recovery, then you can pass the session via https (or proxy). You can also wrap the proxy's createConnection function:
var createConnection = agent.createConnection; agent.createConnection = function (options) { options.session = session; return createConnection.call(agent, options);};By adding a short phone holder system to the connection, session recovery can reduce the use of connections.
Stay active
Allowing the proxy to remain active will ease the SSL handshake. A keep-alive agent, such as agentkeepalive, can fix the problem of node keeping active, but in Node0.12 it is not necessary.
Another thing to remember is the proxy maxSockets. If this value is high, it can have a negative impact on performance. Control your maxSockets value based on the number of external connections you create.
Slab size
tls.SLAB_BUFFER_SIZE determines the allocation size of the slab buffer used by the tls client (server). Its size defaults to 10MB.
These allocated intervals will expand your rss and increase the time for garbage collection. This means that high capacity will affect performance. Adjusting this capacity to a relatively low value can improve memory and garbage collection performance. In version 0.12, the slab allocation has been improved and no further adjustment is required.
Recent changes in SSL in 0.12
Test the SSL enhanced version of Fedor.
Test instructions
Run an http service as an SSL service proxy, all running on the machine.
v0.10.22
Running 10s test @ http://127.0.0.1:3000/20 threads and 20 connectionsThread Stats Avg Stdev Max +/- StdevLatency 69.38ms 30.43ms 268.56ms 95.24%Req/Sec 14.95 4.16 20.00 58.65%3055 requests in 10.01s, 337.12KB readRequests/sec: 305.28Transfer/sec: 33.69KB
v0.11.10-pre (built from the main version)
Running 10s test @ http://127.0.0.1:3000/20 threads and 20 connectionsThread Stats Avg Stdev Max +/- StdevLatency 75.87ms 7.10ms 102.87ms 71.55%Req/Sec 12.77 2.43 19.00 64.17%2620 requests in 10.01s, 276.33KB readRequests/sec: 261.86Transfer/sec: 27.62KB
There is not much difference, but this should be attributed to the default password, so let's adjust the proxy options for the password. For example:
var agent = new https.Agent({ "key": key, "cert": cert, "ciphers": "AES256-GCM-SHA384"});v0.10.22
Running 10s test @ http://localhost:3000/20 threads and 20 connectionsThread Stats Avg Stdev Max +/- StdevLatency 59.85ms 6.77ms 95.71ms 77.29%Req/Sec 16.39 2.36 22.00 61.97%3339 requests in 10.00s, 368.46KB readRequests/sec: 333.79Transfer/sec: 36.83KB
v0.11.10-pre (built from the main version)
Running 10s test @ http://localhost:3000/20 threads and 20 connectionsThread Stats Avg Stdev Max +/- StdevLatency 38.99ms 5.96ms 71.87ms 86.22%Req/Sec 25.43 5.70 35.00 63.36%5160 requests in 10.00s, 569.41KB readRequests/sec: 515.80Transfer/sec: 56.92KB
As we can see, after Fedor modification, this is a huge difference: the performance from 0.10 to 0.12 is almost 2 times worse!
Summarize
Some people may ask "Why not just turn off SSL, it will get faster after it is turned off", and for some people it is also an option. Actually, this is a more representative answer when I ask others how they solve SSL performance problems. However, if anything that enterprise SSL requires only increases but not decreases; and despite a lot of doing to improve SSL in Node.js, performance tuning is still needed. I hope some of the techniques mentioned above will help you adjust the performance of SSL use case.