Route 53 weighted routing lets you send a specified percentage of traffic to different resources, making it a powerful tool for A/B testing live.

Imagine you have two versions of your application, v1.example.com and v2.example.com, and you want to send 90% of traffic to v1 and 10% to v2 to test a new feature.

aws route53 change-resource-record-sets --hosted-zone-id Z1XXXXXX123456 \
--change-batch file://change-batch.json

Here’s the change-batch.json content:

{
  "Comment": "A/B test with weighted routing",
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "example.com.",
        "Type": "A",
        "TTL": 60,
        "Weight": 90,
        "SetIdentifier": "v1-production",
        "AliasTarget": {
          "HostedZoneId": "Z2FXXXXXX123456",
          "DNSName": "v1.example.com.",
          "EvaluateTargetHealth": false
        }
      }
    },
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "example.com.",
        "Type": "A",
        "TTL": 60,
        "Weight": 10,
        "SetIdentifier": "v2-new-feature",
        "AliasTarget": {
          "HostedZoneId": "Z3XXXXXX123456",
          "DNSName": "v2.example.com.",
          "EvaluateTargetHealth": false
        }
      }
    }
  ]
}

When a user’s DNS resolver queries for example.com, Route 53 receives the request. It then randomly selects one of the record sets based on the assigned weights. For every 100 queries, approximately 90 will be directed to the resource associated with v1-production (90% weight) and 10 will be directed to the resource associated with v2-new-feature (10% weight). The SetIdentifier is crucial for distinguishing between multiple records of the same type and name. AliasTarget is used here to point to other AWS resources like Elastic Load Balancers, which is common for A/B testing.

The underlying mechanism is a pseudo-random selection algorithm within Route 53’s DNS servers. When a query arrives for a weighted record set, Route 53 generates a random number and uses it to pick which of the weighted records to return. The probability of picking a specific record is directly proportional to its assigned weight relative to the total weight of all records in the set. This ensures that over time, traffic distribution will closely match the specified percentages.

You can dynamically adjust these weights without downtime. To shift more traffic to v2, you’d update the change-batch.json file and re-run the aws route53 change-resource-record-sets command. For instance, to send 50% to v1 and 50% to v2:

{
  "Comment": "Update A/B test weights",
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "example.com.",
        "Type": "A",
        "TTL": 60,
        "Weight": 50,
        "SetIdentifier": "v1-production",
        "AliasTarget": {
          "HostedZoneId": "Z2FXXXXXX123456",
          "DNSName": "v1.example.com.",
          "EvaluateTargetHealth": false
        }
      }
    },
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "example.com.",
        "Type": "A",
        "TTL": 60,
        "Weight": 50,
        "SetIdentifier": "v2-new-feature",
        "AliasTarget": {
          "HostedZoneId": "Z3XXXXXX123456",
          "DNSName": "v2.example.com.",
          "EvaluateTargetHealth": false
        }
      }
    }
  ]
}

The most surprising thing about weighted routing is that it doesn’t guarantee exactly 90/10 splits for any small number of requests. DNS is a distributed system, and caching plays a significant role. A single client’s DNS resolver might cache a response for example.com for the duration of the TTL (e.g., 60 seconds). During that time, all subsequent requests from that resolver will receive the same IP address, regardless of subsequent changes Route 53 might have processed. This means that while the overall distribution across all users and resolvers will converge to the weights, individual users might consistently hit one version for a period.

To monitor your A/B test, you’d typically use application-level metrics (e.g., conversion rates, error rates) on v1 and v2 and correlate them with the traffic distribution. You can also use CloudWatch alarms based on Route 53 health checks if you’ve configured them for your targets.

If you want to ensure that traffic is only sent to healthy endpoints, you should configure health checks and set EvaluateTargetHealth to true in the AliasTarget configuration.

The next step in advanced traffic management is often using Route 53 latency-based routing to direct users to the geographically closest endpoint.

Want structured learning?

Take the full Route53 course →