For one website we operate, we wanted to introduce a Canadian version of the website. The reasoning behind this was to allow Canadians to browse the site with pricing in Canadian Dollars, as well as to gain the benefit of potentially better rankings on Google Canada and other related search engines by having a presence within Canada.

Under Google’s algorithm for ranking sites in Canadian search results several different factors are evaluated to determine whether or not a particular site is relevant to Canadians. One of these factors is the domain name (does it end in .com, or, .ca?). Another factor is where the website itself is hosted, is it hosted in the USA or does it make use of a Canadian web host?

At the time this project began, the site already had a .com version hosted out of New York, New York, USA. In order to get a Canadian version running there were several considerations.

  1. We wanted the same database and inventory to be used across both versions of the site (the .com and the .ca).
  2. We wanted the Canadian version to be hosted in Canada in order to stand the best possible chance with Google’s rankings.
  3. We were already satisfied with the hosting and performance of the .com version and would like similar or better performance in Canada.
  4. Canada was not a high traffic environment or generator of many sales, and, we wanted Canadian operations to be simple enough to test the hypothesis that increasing a Canadian presence would aid Canadian sales without costing an arm and a leg for server hosting when the US server was already more than adequately provisioned to handle both US and Canadian traffic.

There were two things to figure out in doing this:

  1. Where should we host the .ca version?
  2. What setup should we use for the .ca version? Possible options included hosting a separate installation of the web site using the same database server used for the US or creating a reverse proxy.

There are a variety of hosts located in Canada which could have hosted the website. We wanted to use a company with whom we already had an existing business relationship and which offered cloud servers in Canada. Several of the big names in cloud computing do not offer Canadian-hosted servers including Amazon AWS and Rackspace. Microsoft Azure does but we did not already have an existing business relationship with Azure and would have preferred to keep things simple.

At the outset of this project, only one provider qualified: OVH (we were using them for hosted Microsoft Exchange email). Later, DigitalOcean began providing service in Canada and it was decided to reevaluate the choice of provider and determine whether or not an optimal decision was being made. OVH operates a data centre in Beauharnois, Quebec. DigitalOcean operates out of a leased data centre in Toronto, Ontario.

Copy of the Application vs. Reverse Proxy

We had initially setup the project on a VPS provided by OVH as a mirror of the production server. The installation had its own copy of Apache and the Python Flask app that connected to the existing US Database. While functional, we wanted to determine whether or not this setup was optimal.

To do so, we decided to benchmark the existing site against a version that merely used nginx as a reverse proxy to the main US web+database server. This benchmark was done using ApacheBench from a third (unrelated) host to compare performance on a typical page of the website across 1000 requests. The initial Apache version was left in place on port 80 while the nginx installation with a reverse proxy was setup on port 82 and run in parallel.

The existing setup, at OVH:

Concurrency Level: 1
Time taken for tests: 2440.510 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 95791000 bytes
HTML transferred: 95599000 bytes
Requests per second: 0.41 [#/sec] (mean)
Time per request: 2440.510 [ms] (mean)
Time per request: 2440.510 [ms] (mean, across all concurrent requests)
Transfer rate: 38.33 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 10 11 8.1 10 201
Processing: 1985 2429 913.6 2231 10096
Waiting: 1933 2391 907.0 2197 9989
Total: 1995 2440 916.7 2242 10106

Percentage of the requests served within a certain time (ms)
50% 2242
66% 2295
75% 2341
80% 2373
90% 2469
95% 3221
98% 6591
99% 7583
100% 10106 (longest request)

The nginx reverse proxy setup, on the same server:

Concurrency Level: 1
Time taken for tests: 665.254 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 96663000 bytes
HTML transferred: 96472000 bytes
Requests per second: 1.50 [#/sec] (mean)
Time per request: 665.254 [ms] (mean)
Time per request: 665.254 [ms] (mean, across all concurrent requests)
Transfer rate: 141.90 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 10 11 7.4 10 130
Processing: 384 654 250.5 585 3162
Waiting: 350 599 242.9 529 3128
Total: 395 665 251.3 597 3173

Percentage of the requests served within a certain time (ms)
50% 597
66% 714
75% 773
80% 823
90% 940
95% 1060
98% 1298
99% 1605
100% 3173 (longest request)

Clearly, there was a significant difference between the two approaches. The nginx reverse proxy completed 1000 tests in 665.254 seconds (~11 minutes) vs 2440.510 seconds (~40 minutes) for the original with extreme differences in the time taken by the longest request (and these days, 10 seconds is a bit too long for someone to wait for a page to load).

From these results, it’s clear that the nginx reverse proxy approach was significantly superior to the approach of running another copy of the application in terms of performance. It also greatly simplifies maintenance requirements as new versions of the application do not need to result in any change at all to the nginx reverse proxy approach.

Hosting Providers

What about the comparison between providers? (DigitalOcean and OVH). To compare, we ran the nginx reverse proxy on a newly created DigitalOcean Droplet in the Toronto region.

Concurrency Level: 1
Time taken for tests: 605.785 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 95791000 bytes
HTML transferred: 95599000 bytes
Requests per second: 1.65 [#/sec] (mean)
Time per request: 605.785 [ms] (mean)
Time per request: 605.785 [ms] (mean, across all concurrent requests)
Transfer rate: 154.42 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 22 24 1.1 24 30
Processing: 387 582 186.1 516 2829
Waiting: 330 515 185.2 447 2753
Total: 410 606 186.2 540 2854

Percentage of the requests served within a certain time (ms)
50% 540
66% 609
75% 677
80% 727
90% 855
95% 942
98% 1090
99% 1204
100% 2854 (longest request)

These results show that the DigitalOcean droplet completed the 1000 requests in 605.785 seconds (~10 minutes) vs. 665.254 seconds (~11 minutes) for the OVH server. Additionally, the longest request was 2854ms vs. 3173ms with the OVH server.

While DigitalOcean was faster, it was not so dramatic a difference as between the nginx reverse proxy approach vs. copy of the application.

Conclusions:

  1. For this application, an nginx reverse proxy setup was dramatically superior to running another copy of the application with a shared database (almost 4 times faster).
  2. DigitalOcean Toronto offered better performance than OVH Beauharnois for similarly priced entry level cloud servers.
Case Study: Cloud Server Performance in Canada