How to Implement a Weighted DNS Resolver with Failover in Python

Simulates a weighted DNS load balancer that distributes traffic across IPs by weight and automatically fails over when a server is marked unhealthy.

Medium Python 3.9+ Aug 9, 2026 Automation & scripting 13 views 0 copies

Python code

51 lines
Python 3.9+
import random
import time

class WeightedDNSResolver:
    def __init__(self, records):
        self.records = records  # list of (ip, weight)
        self.total_weight = sum(weight for _, weight in records)
        self.failed_ips = set()

    def resolve(self):
        available = [(ip, weight) for ip, weight in self.records if ip not in self.failed_ips]
        if not available:
            return None
        
        total = sum(weight for _, weight in available)
        rand = random.uniform(0, total)
        cumulative = 0
        
        for ip, weight in available:
            cumulative += weight
            if rand <= cumulative:
                return ip

    def mark_failed(self, ip):
        self.failed_ips.add(ip)

    def simulate_traffic(self, num_requests=10):
        results = {}
        for _ in range(num_requests):
            ip = self.resolve()
            if ip:
                results[ip] = results.get(ip, 0) + 1
                if random.random() < 0.2:
                    self.mark_failed(ip)
            time.sleep(0.01)
        return results

if __name__ == "__main__":
    records = [("192.168.1.10", 50), ("192.168.1.11", 30), ("192.168.1.12", 20)]
    resolver = WeightedDNSResolver(records)
    
    print("Initial resolution test (10 requests):")
    results = resolver.simulate_traffic(10)
    for ip, count in sorted(results.items(), key=lambda x: -x[1]):
        print(f"  {ip}: {count} requests")
    
    resolver.mark_failed("192.168.1.10")
    print("\nAfter failover (10 more requests, .10 marked failed):")
    results = resolver.simulate_traffic(10)
    for ip, count in sorted(results.items(), key=lambda x: -x[1]):
        print(f"  {ip}: {count} requests")

Output

stdout
Initial resolution test (10 requests):
  192.168.1.11: 4 requests
  192.168.1.10: 3 requests
  192.168.1.12: 3 requests

After failover (10 more requests, .10 marked failed):
  192.168.1.11: 5 requests
  192.168.1.12: 5 requests

How it works

The WeightedDNSResolver class stores the total weight across all records and, on each resolve() call, builds a list of available IPs that aren't marked as failed. A random number between 0 and the total available weight is generated, then the resolver walks through IPs in order, accumulating weight until the random value lands in a range — the heavier the weight, the higher the chance it gets picked. mark_failed() adds an IP to the failed_ips set, which removes it from future selections and redistributes traffic proportionally among the remaining healthy servers. The simulate_traffic() method tracks request counts per IP and randomly marks servers as failed with a 20% probability, mimicking a readiness check that detects unhealthy nodes.

Common mistakes

  • Forgetting to recompute total weight after filtering failed IPs, which skews the distribution
  • Using the original total_weight instead of the available sum when selecting the random threshold
  • Not handling the edge case where all IPs are marked failed and resolve() returns None
  • Marking an IP as failed repeatedly without a health-check mechanism to restore it

Variations

  1. Use a health-check thread that periodically unmarks IPs after they recover
  2. Replace random.uniform with a deterministic round-robin to guarantee exact traffic ratios

Real-world use cases

  • Load balancing HTTP requests across backend servers in a microservice architecture.
  • Simulating DNS failover behavior for infrastructure testing before a production deployment.
  • Weighting traffic toward newly deployed canary servers while monitoring their error rates.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Automation & scripting

Related tutorials and quizzes for this topic.