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 |