# Resolver Balancing Strategies in MasterDnsVPN: Round Robin, Least Loss, and Lowest Latency

> MasterDnsVPN offers Round Robin, Least Loss, and Lowest Latency resolver balancing strategies to optimize your upstream DNS traffic. Choose the best method for your needs.

- Repository: [Amin Mahmoudi/MasterDnsVPN](https://github.com/masterking32/MasterDnsVPN)
- Tags: deep-dive
- Published: 2026-05-10

---

**MasterDnsVPN implements three DNS resolver balancing strategies—Round Robin, Least Loss, and Lowest Latency—controlled by a strategy ID passed to the `Balancer` component in [`internal/client/balancer.go`](https://github.com/masterking32/MasterDnsVPN/blob/main/internal/client/balancer.go) to optimize upstream DNS traffic distribution.**

The `masterking32/MasterDnsVPN` repository provides a production-ready DNS VPN client that intelligently distributes UDP packets across multiple upstream resolvers. By selecting the appropriate **resolver balancing strategy**, you can optimize DNS query distribution for raw performance, packet loss avoidance, or latency-sensitive applications.

## Round Robin Strategy

The **Round Robin** strategy (`BalancingRoundRobin`) cycles through active resolvers in a deterministic order without tracking performance metrics. It uses an atomic counter (`rrCounter`) to maintain position across concurrent requests.

When selecting a resolver, the balancer calculates the index using `rrCounter % len(activeIDs)` inside `selectRoundRobinLocked`. This provides lock-free, evenly distributed traffic across all healthy upstream connections regardless of performance characteristics.

```go
// Round robin selection (simplified from line 1640)
func (b *Balancer) selectRoundRobinLocked(count int) []Connection {
    n := len(b.activeIDs)
    start := roundRobinStartIndex(b.rrCounter.Add(uint64(count))-uint64(count), n)
    // Returns next available resolver in sequence
}

```

## Least Loss Strategy

The **Least Loss** strategy (`BalancingLeastLoss`) prioritizes upstream resolvers that demonstrate the lowest packet loss ratios. The balancer computes a **loss score** using the formula `(lost × 1000) / sent` via the `lossScoreLocked` method.

This strategy requires a minimum sample size of 5 sent packets before scoring activates; otherwise, it assigns a neutral penalty of `200`. Resolvers with zero loss receive a perfect score of `0`, making them preferred targets.

```go
// Loss score calculation (line 2033)
func (b *Balancer) lossScoreLocked(idx int) uint64 {
    sent, _, lost, _, _ := b.stats[idx].snapshot()
    if sent < 5 { return 200 }
    if lost == 0 { return 0 }
    return (lost * 1000) / sent
}

```

## Lowest Latency Strategy

The **Lowest Latency** strategy (`BalancingLowestLatency`) routes queries to the resolver with the smallest average round-trip time (RTT). The **latency score** equals `sumRTT / count` for the last N successful replies, calculated in `latencyScoreLocked` at line 2047.

The strategy enforces a minimum threshold of 5 successful replies before calculating averages. Resolvers with insufficient samples receive a penalty of `999000` microseconds, effectively removing them from selection until adequate data exists.

```go
// Latency score calculation (line 2047)
func (b *Balancer) latencyScoreLocked(idx int) uint64 {
    _, _, _, sum, count := b.stats[idx].snapshot()
    if count < 5 { return 999000 }
    return sum / count  // average RTT in microseconds
}

```

## How the Balancer Evaluates Resolvers

The selection entry point is `GetBestConnection`, which checks the configured strategy and delegates to the appropriate scorer function. For statistical strategies (Least Loss and Lowest Latency), `strategyScorerLocked` (line 1836) returns both a scorer function and a signal flag indicating whether sufficient statistics exist.

```go
// Strategy routing (line 1836)
func (b *Balancer) strategyScorerLocked() (func(int) uint64, bool) {
    switch b.strategy {
    case BalancingLeastLoss:
        return b.lossScoreLocked, b.hasLossSignalLocked()
    case BalancingLowestLatency:
        return b.lossScoreLocked, b.hasLatencySignalLocked()
    // ...
    }
}

```

The `bestScoredConnectionLocked` method then iterates through active connections, invokes the scorer, and returns the resolver with the minimum calculated value.

## Configuring the Balancing Strategy

In [`internal/client/client.go`](https://github.com/masterking32/MasterDnsVPN/blob/main/internal/client/client.go), the client initialization reads `ResolverBalancingStrategy` from the JSON configuration structure defined in [`internal/config/client.go`](https://github.com/masterking32/MasterDnsVPN/blob/main/internal/config/client.go). The constructor `NewBalancer` (line 125) accepts the strategy constant as its first argument.

```go
// Example instantiations
balRR := NewBalancer(BalancingRoundRobin, logger)       // Cyclic distribution
balLL := NewBalancer(BalancingLeastLoss, logger)        // Loss-aware
balLT := NewBalancer(BalancingLowestLatency, logger)  // Latency-optimized

// Usage
conn, ok := balLL.GetBestConnection()
if !ok {
    // Handle no active resolvers
}

```

If the configuration omits an explicit strategy, the system defaults to round-robin behavior.

## Summary

- **Round Robin** provides deterministic, cyclic distribution across resolvers without metric overhead, ideal for uniform infrastructure.
- **Least Loss** calculates packet loss ratios after 5 samples, preferring reliable connections in unstable network environments.
- **Lowest Latency** averages RTT measurements after 5 replies, optimizing for speed-sensitive DNS resolution.
- All strategies are implemented in [`internal/client/balancer.go`](https://github.com/masterking32/MasterDnsVPN/blob/main/internal/client/balancer.go), with configuration managed through [`internal/config/client.go`](https://github.com/masterking32/MasterDnsVPN/blob/main/internal/config/client.go).

## Frequently Asked Questions

### How do I enable the Lowest Latency strategy in MasterDnsVPN?

Set the `ResolverBalancingStrategy` field in your client configuration JSON to the `BalancingLowestLatency` constant, then pass this value when calling `NewBalancer` in [`internal/client/client.go`](https://github.com/masterking32/MasterDnsVPN/blob/main/internal/client/client.go). The balancer automatically begins tracking RTT samples and will prioritize the fastest resolver after collecting at least 5 latency measurements.

### What is the minimum sample size before Least Loss scoring activates?

The balancer requires **5 sent packets** before calculating loss scores. Until this threshold is met, the `lossScoreLocked` function returns a neutral penalty of `200`, preventing premature optimization based on insufficient data.

### Does Round Robin track performance metrics?

No. The Round Robin strategy operates statelessly using only an atomic counter (`rrCounter`) to cycle through `activeIDs`. It does not collect latency, loss, or throughput statistics, resulting in minimal CPU and memory overhead compared to the statistical strategies.

### Which strategy should I use for unreliable network connections?

Use **Least Loss** (`BalancingLeastLoss`) when operating over unstable networks. By calculating `(lost × 1000) / sent`, it actively avoids resolvers demonstrating packet loss, automatically routing traffic through the most reliable available upstream connection as network conditions fluctuate.