在瀏覽網路時,我們都知道,透過SSL進行加密是非常重要的。在貝寶(PayPal),安全是我們的首要任務。我們使用端到端的加密,不僅只是我們的公共網站,對於我們的內部服務呼叫也同樣如此。 SSL加密技術將在很大程度上影響node.js的效能。我們已經花時間調整我們的對外服務,並充分利用他們。以下是一些我們發現能顯著地提高SSL對外效能的SSL配置調整清單。
SSL密碼
開箱即用,Node.js 的SSL使用一組非常強大的密碼演算法。特別是,迪菲赫爾曼密鑰交換和橢圓曲線演算法是極其昂貴的。而且當你在預設配置中用了太多的對外SSL調用,Node.js的效能將從根本上得到削弱。為了得到它到底有多慢這個結論,這兒有個服務呼叫的CPU樣本:
918834.0ms 100.0% 0.0 node (91770) 911376.0ms 99.1% 0.0 start 911376.0ms 99.1% 0.0 node::Start 911363.0ms 99.1% 48.0 uv_run 909839.0ms 99.0% 438.0 uv__io_poll 876570.0ms 95.4% 849.0 uv__stream_io 873590.0ms 95.0% 32.0 node::StreamWrap::OnReadCommon 873373.0ms 95.0% 7.0 node::MakeCallback 873265.0ms 95.0% 15.0 node::MakeDomainCallback 873125.0ms 95.0% 61.0 v8::Function::Call 873049.0ms 95.0% 13364.0 _ZN2v88internalL6InvokeEbNS0 832660.0ms 90.6% 431.0 _ZN2v88internalL21Builtin 821687.0ms 89.4% 39.0 node::crypto::Connection::ClearOut 813884.0ms 88.5% 37.0 ssl23_connect 813562.0ms 88.5% 54.0 ssl3_connect 802651.0ms 87.3% 35.0 ssl3_send_client_key_exchange 417323.0ms 45.4% 7.0 EC_KEY_generate_key 383185.0ms 41.7% 12.0 ecdh_compute_key 1545.0ms 0.1% 4.0 tls1_generate_master_secret 123.0ms 0.0% 4.0 ssl3_do_write ...
讓我們專注於金鑰的產生:
802651.0ms 87.3% 35.0 ssl3_send_client_key_exchange 417323.0ms 45.4% 7.0 EC_KEY_generate_key 383185.0ms 41.7% 12.0 ecdh_compute_key
這個呼叫87%的時間都花在產生金鑰上了!
這些密碼能被改變以減少密集的計算。這個想法已經在https(或代理商)得以實現了。例如:
var agent = new https.Agent({ "key": key, "cert": cert, "ciphers": "AES256-GCM-SHA384" });
上面的密鑰已經沒用過昂貴的迪菲赫曼密鑰交換。用相似的東西取代之後,在下面的範例中我們能看到顯著的變化:
... 57945.0ms 32.5% 16.0 ssl3_send_client_key_exchange 28958.0ms 16.2% 9.0 generate_key 26827.0ms 15.0% 2.0 compute_key ...
透過OpenSSL文檔,你可以學習更多關於密碼串的東西。
SSL會話恢復
如果您的伺服器支援SSL會話恢復,那麼您可以透過https(或代理程式)來傳遞會話。你也可以將代理程式的createConnection函數包裹起來:
var createConnection = agent.createConnection; agent.createConnection = function (options) { options.session = session; return createConnection.call(agent, options); };
透過增加連線的簡短握手機制,會話恢復能降低連線數的使用。
保持活動量
允許代理商保持活動將緩和SSL握手。一個保持活動的代理,例如agentkeepalive可以修復結點保持活動的問題,但在Node0.12中它是非必須的。
另一個需要銘記在心的東西是代理的maxSockets,這個值高的話能對性能造成負面的影響。在你創建的對外連接數量的基礎上控制你的maxSockets值。
Slab的大小
tls.SLAB_BUFFER_SIZE決定了被tls客戶端(伺服器)所使用的slab緩衝區的分配大小。它的大小預設為10MB。
這些分配的區間將會擴大你的rss且會增加垃圾回收的時間。這意味著高容量將會影響到效能。把這個容量調整到一個比較低的值可以改善記憶體和垃圾收集的效能。在0.12 版本中,slab的分配已經改善了,沒有必須再調整了。
SSL在0.12中近期的改變
測試Fedor的SSL增強版。
測試說明
運行一個作為SSL服務代理的http服務,全部運行在本機上。
v0.10.22
Running 10s test @ http://127.0.0.1:3000/ 20 threads and 20 connections Thread Stats Avg Stdev Max +/- Stdev Latency 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 read Requests/sec: 305.28 Transfer/sec: 33.69KB
v0.11.10-pre (從主版建構)
Running 10s test @ http://127.0.0.1:3000/ 20 threads and 20 connections Thread Stats Avg Stdev Max +/- Stdev Latency 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 read Requests/sec: 261.86 Transfer/sec: 27.62KB
這沒有太多的區別,但這應歸於預設密碼,所以讓我們調整密碼的代理選項。例如:
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 connections Thread Stats Avg Stdev Max +/- Stdev Latency 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 read Requests/sec: 333.79 Transfer/sec: 36.83KB
v0.11.10-pre (從主版建構)
Running 10s test @ http://localhost:3000/ 20 threads and 20 connections Thread Stats Avg Stdev Max +/- Stdev Latency 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 read Requests/sec: 515.80 Transfer/sec: 56.92KB
如我們所見,經過Fedor的修改,這有著巨大的差異:從0.10到0.12表現差不多差著2倍左右!
總結
有人可能會問“為什麼不僅僅只是關掉SSL呢,關了之後它就會變得快起來”,而且對於一些人來說這也是一種選擇。實際上,當我問別人他們是如何解決SSL效能問題的時候這是比較有代表性的答案。但是,如果企業SSL要求的任何東西只增加不減少;而且儘管已經做了很多來改善Node.js中的SSL,性能調整仍然還是需要的。我希望上述的一些技藝能夠幫助你調整SSL用例效能。