# How v2rayN Implements Load Balancing and Server Health Checking: A Technical Deep Dive

> Explore how v2rayN offers advanced load balancing strategies like round-robin and least-ping, plus continuous server health checking with configurable HTTP probes. Optimize your proxy performance today.

- Repository: [2dust/v2rayN](https://github.com/2dust/v2rayN)
- Tags: deep-dive
- Published: 2026-02-27

---

**v2rayN leverages V2Ray core's native balancer and observatory modules to enable automatic traffic distribution across multiple proxy servers, supporting strategies ranging from round-robin to least-ping while continuously monitoring endpoint health through configurable HTTP probes.**

The open-source proxy client v2rayN (maintained by 2dust) provides sophisticated load balancing and server health checking capabilities by dynamically generating V2Ray core configurations. Rather than implementing custom networking logic, v2rayN orchestrates the core's built-in balancer and observatory features through strategic JSON configuration generation. This article examines the specific C# implementations in the v2rayN source code that enable automatic server selection and continuous health monitoring.

## Load Balancing Architecture in v2rayN

v2rayN implements load balancing by treating server groups as collections of discrete outbound connections, then applying V2Ray core's balancer strategies across them. The implementation spans configuration generation, health monitoring, and routing rule transformation.

### Strategy Selection via EMultipleLoad

The available balancing strategies are defined as an enumeration in [`v2rayN/ServiceLib/Enums/EMultipleLoad.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Enums/EMultipleLoad.cs):

```csharp
public enum EMultipleLoad
{
    LeastPing,
    Fallback,
    Random,
    RoundRobin,
    LeastLoad
}

```

Users select one of these five strategies when configuring a server group. This selection is stored in `ProtocolExtraItem.MultipleLoad` and later consumed by the core configuration generator to determine which V2Ray balancer strategy to apply.

### Dynamic Outbound Generation

When processing a server group, `CoreConfigV2rayService.GenRoutingUserRuleOutbound` generates individual outbound configurations for each server in the group:

```csharp
// v2rayN/ServiceLib/Services/CoreConfig/V2ray/CoreConfigV2rayService.cs
var proxyOutbounds = new CoreConfigV2rayService(context with { Node = node, })
                         .BuildAllProxyOutbounds(tag);
_coreConfig.outbounds.AddRange(proxyOutbounds);
if (proxyOutbounds.Count(n => n.tag.StartsWith(tag)) > 1)
{
    var multipleLoad = node.GetProtocolExtra().MultipleLoad ?? EMultipleLoad.LeastPing;
    GenObservatory(multipleLoad, tag);
    GenBalancer(multipleLoad, tag);
}

```

When the group contains multiple servers, the code invokes `GenObservatory` to establish health monitoring and `GenBalancer` to create the load distribution logic. This conditional check ensures that single-server groups do not incur the overhead of balancing infrastructure.

## Server Health Checking Implementation

v2rayN implements health checking through two distinct observatory types that feed real-time status data to the V2Ray core balancer.

### Observatory and Burst Observatory

The health monitoring configuration is generated in [`v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayBalancerService.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayBalancerService.cs) via the `GenObservatory` method:

```csharp
private void GenObservatory(EMultipleLoad multipleLoad, string baseTagName = Global.ProxyTag)
{
    if (multipleLoad is EMultipleLoad.LeastLoad or EMultipleLoad.Fallback)
    {
        // Burst-observatory (load-based) – ping config
        _coreConfig.burstObservatory = new BurstObservatory4Ray
        {
            subjectSelector = [baseTagName],
            pingConfig = new()
            {
                destination = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
                interval = "5m",
                timeout = "30s",
                sampling = 2,
            }
        };
    }
    else if (multipleLoad is EMultipleLoad.LeastPing)
    {
        // Observatory (ping-based) – probe URL
        _coreConfig.observatory = new Observatory4Ray
        {
            subjectSelector = [baseTagName],
            probeUrl = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
            probeInterval = "3m",
            enableConcurrency = true,
        };
    }
}

```

**Observatory** (`observatory`) performs periodic HTTP probes to the `probeUrl` every three minutes with concurrency enabled. **Burst observatory** (`burstObservatory`) executes rapid ping bursts every five minutes to measure load distribution, specifically supporting the *LeastLoad* and *Fallback* strategies that require granular performance metrics.

### Health Check Configuration Parameters

The underlying data structures in [`v2rayN/ServiceLib/Models/V2rayConfig.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Models/V2rayConfig.cs) define the configuration schema:

```csharp
public class Observatory4Ray
{
    public List<string>? subjectSelector { get; set; }
    public string? probeUrl { get; set; }
    public string? probeInterval { get; set; }
    public bool? enableConcurrency { get; set; }
}

public class BurstObservatory4Ray
{
    public List<string>? subjectSelector { get; set; }
    public BurstObservatoryPingConfig4Ray? pingConfig { get; set; }
}

public class BurstObservatoryPingConfig4Ray
{
    public string? destination { get; set; }
    public string? interval { get; set; }
    public string? timeout { get; set; }
    public int? sampling { get; set; }
}

```

The `subjectSelector` array filters which outbound tags the observatory monitors, while `probeUrl` defaults to the GUI's configured speed test endpoint. V2Ray core continuously updates health status based on these probe results, making the data available to balancers for routing decisions.

### gRPC Transport Health Checks

For gRPC-based outbound connections, v2rayN adds transport-specific health check parameters in [`v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayOutboundService.cs):

```csharp
case nameof(ETransport.grpc):
    GrpcSettings4Ray grpcSettings = new()
    {
        // ... other settings ...
        health_check_timeout = _config.GrpcItem.HealthCheckTimeout,
    };

```

The `health_check_timeout` value is sourced from `GrpcItem.HealthCheckTimeout` and instructs the V2Ray core to terminate connections that fail health verification within the specified duration, ensuring rapid failover for gRPC streams.

## The Balancer Configuration Pipeline

Once health monitoring is established, v2rayN generates the balancer configuration that ties outbounds to routing strategies.

### Mapping Strategies to V2Ray Core

The `GenBalancer` method in [`V2rayBalancerService.cs`](https://github.com/2dust/v2rayN/blob/main/V2rayBalancerService.cs) translates the `EMultipleLoad` enum into V2Ray core strategy strings:

```csharp
private void GenBalancer(EMultipleLoad multipleLoad, string selector = Global.ProxyTag)
{
    var strategyType = multipleLoad switch
    {
        EMultipleLoad.Random      => "random",
        EMultipleLoad.RoundRobin  => "roundRobin",
        EMultipleLoad.LeastPing   => "leastPing",
        EMultipleLoad.LeastLoad   => "leastLoad",
        _                         => "roundRobin",
    };

    var balancer = new BalancersItem4Ray
    {
        selector = [selector],
        strategy = new()
        {
            type = strategyType,
            settings = new() { expected = 1 },
        },
        tag = $"{selector}{Global.BalancerTagSuffix}",
    };
    _coreConfig.routing.balancers ??= new();
    _coreConfig.routing.balancers.Add(balancer);
}

```

The balancer's `selector` array identifies which outbound tags participate in load distribution, while the `strategy` object configures the algorithm. The `expected` setting of `1` indicates that the balancer should select one optimal outbound per routing decision.

### Routing Rule Transformation

To activate the balancer, routing rules must reference the balancer's tag rather than specific outbounds. The [`V2rayRoutingService.cs`](https://github.com/2dust/v2rayN/blob/main/V2rayRoutingService.cs) file handles this transformation:

```csharp
// v2rayN/ServiceLib/Services/CoreConfig/V2ray/V2rayRoutingService.cs
var balancerTagList = _coreConfig.routing.balancers?.Select(p => p.tag).ToList() ?? [];
if (balancerTagList.Count > 0)
{
    foreach (var rulesItem in _coreConfig.routing.rules
                     .Where(r => balancerTagList.Contains(r.outboundTag + Global.BalancerTagSuffix)))
    {
        rulesItem.balancerTag = rulesItem.outboundTag + Global.BalancerTagSuffix;
        rulesItem.outboundTag = null;
    }
}

```

This code iterates through routing rules and rewrites any rule pointing to a load-balanced group by setting `balancerTag` to the generated balancer identifier and clearing the `outboundTag` field. This redirection ensures that V2Ray core invokes the balancer strategy when matching traffic against these rules.

## Generated Configuration Structure

When v2rayN processes a server group named `MyGroup` with the **LeastPing** strategy, it generates a V2Ray core configuration similar to this condensed JSON:

```json
{
  "routing": {
    "rules": [
      {
        "type": "field",
        "outboundTag": null,
        "balancerTag": "MyGroup-proxy-balance",
        "domain": ["example.com"]
      }
    ],
    "balancers": [
      {
        "tag": "MyGroup-proxy-balance",
        "selector": ["MyGroup-proxy-1", "MyGroup-proxy-2"],
        "strategy": {
          "type": "leastPing",
          "settings": { "expected": 1 }
        }
      }
    ]
  },
  "observatory": {
    "subjectSelector": ["MyGroup-proxy"],
    "probeUrl": "https://www.gstatic.com/generate_204",
    "probeInterval": "3m",
    "enableConcurrency": true
  }
}

```

The **balancer** references individual outbound tags and applies the `leastPing` strategy, while the **observatory** continuously probes both outbounds every three minutes to provide latency data for routing decisions.

## Summary

- **v2rayN generates multiple outbounds** for server groups via [`CoreConfigV2rayService.cs`](https://github.com/2dust/v2rayN/blob/main/CoreConfigV2rayService.cs), then creates balancer and observatory configurations when multiple servers are detected.
- **Health monitoring uses two modes**: standard `observatory` for ping-based strategies (LeastPing) and `burstObservatory` for load-based strategies (LeastLoad, Fallback), configured in [`V2rayBalancerService.cs`](https://github.com/2dust/v2rayN/blob/main/V2rayBalancerService.cs).
- **Five balancing strategies** are supported—Random, RoundRobin, LeastPing, LeastLoad, and Fallback—mapped to V2Ray core algorithm types through the `GenBalancer` method.
- **Routing rules are dynamically rewritten** in [`V2rayRoutingService.cs`](https://github.com/2dust/v2rayN/blob/main/V2rayRoutingService.cs) to use `balancerTag` instead of `outboundTag`, enabling transparent load balancing without manual rule modification.
- **gRPC connections** receive additional `health_check_timeout` parameters to ensure transport-layer responsiveness.

## Frequently Asked Questions

### How does v2rayN determine which server to use in a load-balanced group?

v2rayN delegates server selection to the V2Ray core balancer. The core evaluates the configured strategy (random, round-robin, least-ping, etc.) against real-time health data provided by the observatory. For `leastPing` strategies, the core selects the outbound with the lowest latency; for `leastLoad`, it considers the burst observatory's load measurements.

### What is the difference between observatory and burst-observatory in v2rayN?

The standard **observatory** performs periodic HTTP probes (default every 3 minutes) to measure basic connectivity and latency for `leastPing` balancing. The **burst-observatory** executes rapid ping bursts (default every 5 minutes with 30-second timeouts) to collect granular performance metrics required for `leastLoad` and `fallback` strategies that need to assess server load rather than just reachability.

### How often does v2rayN check server health?

Health check intervals are hardcoded in the configuration generation logic: standard observatories probe every **3 minutes**, while burst observatories probe every **5 minutes**. These intervals are defined in [`V2rayBalancerService.cs`](https://github.com/2dust/v2rayN/blob/main/V2rayBalancerService.cs) and apply to all servers within the monitored group simultaneously.

### Can I use load balancing with gRPC transport protocols?

Yes. v2rayN supports load balancing across gRPC outbounds and adds a `health_check_timeout` parameter to gRPC settings configured in [`V2rayOutboundService.cs`](https://github.com/2dust/v2rayN/blob/main/V2rayOutboundService.cs). This ensures that unresponsive gRPC connections are terminated quickly, allowing the balancer to redirect traffic to healthy endpoints within the group.