Application endpoint optimization (latency / geo routing)

Latency and geo based DNS routing helps to improve application performance across availability zones and regions. This routing directs customers to the closest geographic location or lowest latency AWS endpoint (e.g. EC2 instances, Elastic IPs or ELBs) that provides the best user experience based on actual performance measurements of the different AWS regions where your application is running.

To get started, first we will need to log into the Amazon Route 53 console. If you already have a zone to work with use it, otherwise create a new hosted zone for your account.

In this example we’re going to assume your running an ELB or instances in each AZ in order to demonstrate how you can flesh out DNS to optimize traffic. Because of how these records work, we first need to create either alias or alternative records to the actual endpoint.

We’re going to use round-robin DNS to distribute traffic amongst each AZ. So for each AZ we’re making a api-east-1-1a.example.com, api-east-1-1b.example.com, api-east-1-1c.example.com, and so on. These should be made as alias records to ELBs if possible. Once that is done, we can make the DNS record for the next level up api-east-1.example.com. We’ll be making weighted policy records for each AZ. Set the record name to api-east-1.example.com, the type to a / alias (selecting the AZ record 1a.api-east-1.example.com for example), the policy to weighted, set id to something unique, and base the weight off the percentage of traffic you would like to send that way. Default to 100.

After you’ve done that for all of the ELBs/AZs you should have something like:

api-east-1.example.com
          |
   (w/roundrobin)
          |
          ====> api-east-1-1a.example.com
          ====> api-east-1-1b.example.com
          ====> api-east-1-1c.example.com
          ====> api-east-1-1d.example.com
          ====> api-east-1-1e.example.com

api-west-2.example.com
          |
   (w/roundrobin)
          |
          ====> api-west-2-2a.example.com
          ====> api-west-2-2b.example.com
          ====> api-west-2-2c.example.com

Assuming all AZs as having an equal weighting traffic should be approximately equally distributed. So for api-east-1 the traffic should be split amongst the 5 ELBs/AZs, and for api-west-2 the traffic should be split amongst the 3 ELBs/AZs.

Next step is to introduce the magic of geo or latency based routing.

Typically I recommend using latency based routing to route user requests to the Amazon EC2 region that will give end users the fastest response. This keeps the user experience optimal. However if you’d like more control over how users are routed then geolocation routing may be the better choice. With geo routing you can map locations to specific Amazon resources sets. This is useful for content localization or to restrict content access. With geo routing you should create a default record, otherwise DNS requests will only resolve for regions that you have created records for.

The process for creating latency (or geo!) based records is fairly similar to the process above for creating round-robin records. Following our working example we’re going to create two records for example.com, with policy type set to latency, the reqion set, and a unique set id.

If done correctly we should have ended up with something similar to:

example.com ====> api-east-1.example.com
            |               |
            |         (w/roundrobin)
            |               |
            |               ====> api-east-1-1a.example.com
       (w/latency)          ====> api-east-1-1b.example.com
            |               ====> api-east-1-1c.example.com
            |               ====> api-east-1-1d.example.com
            |               ====> api-east-1-1e.example.com
            |
            |
            ====> api-west-2.example.com
                            |
                     (w/roundrobin)
                            |
                            ====> api-west-2-2a.example.com
                            ====> api-west-2-2b.example.com
                            ====> api-west-2-2c.example.com

When used correctly this type of DNS structure can enhance user experience and minimize potential downtime. In the example above we could have used health checks to remove down endpoints and we could also introduce failover records - so that if all of our EC2 instances were broken we could direct traffic to S3.

Creating Latency Records with the AWS CLI

To do this with the AWS CLI, you first need to write the changes out in JSON. Official cli examples and documentation.

records.json

{
  "Comment": "optional comment about the changes in this change batch request",
  "Changes": \[
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "example.com",
        "Type": "A",
        "SetIdentifier": "RANDOMTEXT",
        "Region": "us-west-2",
        "AliasTarget": {
          "HostedZoneId": "hosted zone ID for your AWS resource",
          "DNSName": "DNS domain name for your AWS resource",
          "EvaluateTargetHealth": true
        }
      }
    },
    {...}
  \]
}

When you’ve prepared the json file, you can run the command: aws route53 change-resource-record-sets --hosted-zone-id ######### --change-batch ./records.json