a blog about unixy stuff and so on
2012/03/12HTTPS and Performance
Many people state that performance is the main issue that prevent them from enabling HTTPS on the websites. Sure, the difference from doing a simple http get and a full TLS handshake and then a http get is quite huge, especially since it's performing the handshake for every connection. This means that the TLS penalty needs to be paid for every time the user gets a javascript, a stylesheet, a picture etc.
Using the Apache Bench program, we can quite easily determine just how high the performance impact is by comparing TLS with non TLS communication.
The test was done against ROMABs webserver from our office network. Here are some results:
minuteman:https-benchmarks andreas$ ab -n 10000 http://www.romab.com/index.html This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking www.romab.com (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: lighttpd/1.4.28 Server Hostname: www.romab.com Server Port: 80 Document Path: /index.html Document Length: 5569 bytes Concurrency Level: 1 Time taken for tests: 79.515 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Total transferred: 58040000 bytes HTML transferred: 55690000 bytes Requests per second: 125.76 [#/sec] (mean) Time per request: 7.951 [ms] (mean) Time per request: 7.951 [ms] (mean, across all concurrent requests) Transfer rate: 712.82 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 6 160.5 1 10989 Processing: 2 2 2.6 2 257 Waiting: 0 1 0.4 1 33 Total: 2 8 160.5 3 10991 Percentage of the requests served within a certain time (ms) 50% 3 66% 3 75% 3 80% 3 90% 4 95% 4 98% 4 99% 4 100% 10991 (longest request)
Ok, without doing any deeper analysis, we can see that the important one there is requests per second, (125/sec). Now lets do the same test against With TLS
minuteman:https-benchmarks andreas$ ab -n 10000 https://www.romab.com/index.html This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking www.romab.com (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: lighttpd/1.4.28 Server Hostname: www.romab.com Server Port: 443 SSL/TLS Protocol: TLSv1/SSLv3,AES256-SHA,4096,256 Document Path: /index.html Document Length: 5569 bytes Concurrency Level: 1 Time taken for tests: 1476.578 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Total transferred: 58660000 bytes HTML transferred: 55690000 bytes Requests per second: 6.77 [#/sec] (mean) Time per request: 147.658 [ms] (mean) Time per request: 147.658 [ms] (mean, across all concurrent requests) Transfer rate: 38.80 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 143 145 3.4 145 415 Processing: 2 2 1.5 2 134 Waiting: 0 1 1.4 1 133 Total: 145 147 3.8 147 417 Percentage of the requests served within a certain time (ms) 50% 147 66% 147 75% 147 80% 148 90% 148 95% 149 98% 155 99% 155 100% 417 (longest request)
OUCH! we went from 125 requests per second, to 6.7 requests per second. In addition, the time per request skyrocketed. The reason for this is that we are performing a new TLS handshake for each connection, which is costly.
We can however get significant performance imporvements to this by enabling Keep-alives, and letting the client reuse the TLS session already open.
minuteman:https-benchmarks andreas$ ab -k -n 10000 https://www.romab.com/index.html This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking www.romab.com (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: lighttpd/1.4.28 Server Hostname: www.romab.com Server Port: 443 SSL/TLS Protocol: TLSv1/SSLv3,AES256-SHA,4096,256 Document Path: /index.html Document Length: 5569 bytes Concurrency Level: 1 Time taken for tests: 105.949 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Keep-Alive requests: 9412 Total transferred: 58707060 bytes HTML transferred: 55690000 bytes Requests per second: 94.39 [#/sec] (mean) Time per request: 10.595 [ms] (mean) Time per request: 10.595 [ms] (mean, across all concurrent requests) Transfer rate: 541.12 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 9 34.4 0 447 Processing: 2 2 0.1 2 3 Waiting: 1 1 0.1 1 3 Total: 2 11 34.4 2 449 Percentage of the requests served within a certain time (ms) 50% 2 66% 2 75% 2 80% 2 90% 2 95% 146 98% 147 99% 147 100% 449 (longest request)
Quite the improvement! In reality however, keep alives are almost always enabled by default so there a rarely any need to tune it. The big gains are instead usually gained by using agressive caching of javascript, images and stylesheets. Other type of static content can of course also be cached such as iframes that never change. This also have the bennefit of improving performance for non-https acessed content as well.
HTTP | HTTPS | HTTPS with keepalives | |
Requests per second | 125.76 | 6.77 | 94.39 |
Time per request | 7.951ms | 147.658ms | 10.595ms |
Time taken for tests | 79.515s | 1476.578 | 105.949s |