Datasäkerhet och Informationssäkerhet

Robert Malmgren AB

“Trust is good, control is better.”

a blog about unixy stuff and so on

2012/03/12

HTTPS 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.

HTTPHTTPSHTTPS with keepalives
Requests per second125.766.7794.39
Time per request7.951ms147.658ms10.595ms
Time taken for tests79.515s1476.578105.949s