# Does FastProxy Support Load Balancing? Architecture Analysis and Solutions

> Explore FastProxy's architecture to understand its load balancing capabilities. Discover solutions for distributing traffic across multiple instances using external load balancers.

- Repository: [Kingson4Wu/fast_proxy](https://github.com/kingson4wu/fast_proxy)
- Tags: architecture
- Published: 2026-03-05

---

**FastProxy does not provide built-in load balancing; both the OutProxy and InProxy components are designed to forward traffic to a single upstream endpoint, requiring external load balancers or custom ServiceCenter implementations to distribute requests across multiple instances.**

FastProxy (kingson4wu/fast_proxy) is a lightweight Go proxy library designed for service forwarding and discovery. While it efficiently handles request routing between services, developers evaluating this library for production deployments often need to understand its load balancing capabilities. This article examines the source code architecture to explain why FastProxy lacks native load distribution and how to implement it externally.

## Why FastProxy Does Not Provide Built-In Load Balancing

The core architecture of FastProxy is intentionally simple: each request resolves to exactly one upstream target. Both major components enforce single-endpoint resolution:

- **OutProxy** uses a single `ForwardAddress` configuration string (exposed via `outconfig.Config.ForwardAddress()`) and forwards every request to that specific URL using a standard `net/http/httputil.ReverseProxy`.

- **InProxy** relies on a **ServiceCenter** (`servicediscovery.Create()`) that returns exactly one `Address` struct per service name lookup. The `ServiceCenter` holds a single `addressFunc` with the signature `func(serviceName string) *Address`, providing no mechanism for round-robin, weighted, or health-check-based selection.

Because neither component maintains a pool of upstream candidates or selection algorithms, the library cannot distribute traffic without external intervention.

## OutProxy Single-Target Architecture

In [`outproxy/internal/proxy/reverseProxy.go`](https://github.com/kingson4wu/fast_proxy/blob/main/outproxy/internal/proxy/reverseProxy.go), the OutProxy initializes a `ReverseProxy` with a `Director` function that unconditionally forwards requests to the configured `ForwardAddress`:

```go
// outproxy/internal/proxy/reverseProxy.go
proxy = &httputil.ReverseProxy{
    Director: func(req *http.Request) {
        // Always forwards to the single configured address
        callUrl := outconfig.Get().ForwardAddress() + req.RequestURI
        u, _ := url.Parse(callUrl)
        req.URL = u
        req.Host = u.Host
    },
    // ... response handling omitted ...
}

```

The `ForwardAddress` is loaded from YAML configuration via [`outproxy/outconfig/yaml_config.go`](https://github.com/kingson4wu/fast_proxy/blob/main/outproxy/outconfig/yaml_config.go) and exposed through the interface in [`outproxy/outconfig/outconfig.go`](https://github.com/kingson4wu/fast_proxy/blob/main/outproxy/outconfig/outconfig.go). Since this is a static string value, there is no opportunity to alternate between multiple backends at the proxy level.

## InProxy Service Discovery Limitations

The InProxy component resolves upstream locations through the ServiceCenter defined in [`common/servicediscovery/servicediscovery.go`](https://github.com/kingson4wu/fast_proxy/blob/main/common/servicediscovery/servicediscovery.go). This component maintains a single `addressFunc` callback that returns one `Address` pointer per service name:

```go
// inproxy/internal/servicediscovery/serviceDiscovery.go
addr := server.Center().Address(serviceName) // returns one *Address
if addr == nil {
    return "", nil // no upstream found
}

// Constructs URL from the single returned address
builder := strings.Builder{}
builder.WriteString("http://")
builder.WriteString(addr.Ip)
builder.WriteString(":")
builder.WriteString(strconv.Itoa(addr.Port))
builder.WriteString(requestPath)
callUrl = builder.String()

```

The `Address` struct contains only `Ip` and `Port` fields. Without modifying the `addressFunc` implementation, the InProxy will always route to the same instance for a given service name.

## How to Implement Load Balancing with FastProxy

While FastProxy lacks native load distribution, you can achieve it through two primary architectural approaches.

### Option 1: Deploy an External Load Balancer

Place FastProxy instances behind an external load balancing layer such as Nginx, Envoy, HAProxy, or a cloud provider load balancer (AWS ALB, GCP LB). The external component handles health checking, failover, and request distribution across multiple FastProxy processes, treating each proxy instance as a downstream target.

### Option 2: Build a Custom ServiceCenter

For InProxy deployments, implement a custom `ServiceCenter` with your own selection algorithm. The `servicediscovery.Create()` builder accepts an `AddressFunc` that you can implement with round-robin, random, or least-connections logic:

```go
package main

import (
    "github.com/Kingson4Wu/fast_proxy/common/servicediscovery"
    "sync/atomic"
    "strconv"
    "strings"
)

var (
    targets = []string{
        "127.0.0.1:8081",
        "127.0.0.1:8082",
        "127.0.0.1:8083",
    }
    rrIdx int32
)

func main() {
    sc := servicediscovery.Create().
        AddressFunc(func(serviceName string) *servicediscovery.Address {
            // Atomic round-robin selection
            i := atomic.AddInt32(&rrIdx, 1)
            hostPort := strings.Split(targets[i%int32(len(targets))], ":")
            port, _ := strconv.Atoi(hostPort[1])
            return &servicediscovery.Address{
                Ip:   hostPort[0],
                Port: port,
            }
        }).
        Build()

    // Register the custom ServiceCenter with your server instance
    server.SetCenter(sc)
}

```

This approach embeds load balancing logic directly into the InProxy's resolution chain, allowing dynamic upstream selection without external infrastructure.

## Summary

- FastProxy routes each request to exactly one upstream target by design.
- **OutProxy** forwards exclusively to the `ForwardAddress` configured in `outconfig.Config`.
- **InProxy** retrieves a single `Address` from the `ServiceCenter` per request via `server.Center().Address()`.
- Native load balancing requires either external infrastructure (Nginx, Envoy) or a custom `ServiceCenter` implementation with selection algorithms.

## Frequently Asked Questions

### Does FastProxy support round-robin load balancing out of the box?

No. The `ServiceCenter` in [`common/servicediscovery/servicediscovery.go`](https://github.com/kingson4wu/fast_proxy/blob/main/common/servicediscovery/servicediscovery.go) returns a single `Address` via the `addressFunc` callback without any rotation logic. To achieve round-robin behavior, you must implement a custom `AddressFunc` that tracks state across requests, as shown in the code example above.

### Can I configure multiple upstream endpoints in FastProxy?

Not directly. OutProxy accepts only one `ForwardAddress` string from the YAML configuration, and InProxy resolves service names to a single IP/port pair. Supporting multiple endpoints requires either placing FastProxy behind an external load balancer or writing a custom ServiceCenter that selects from a pool of targets.

### What is the ServiceCenter in FastProxy?

The ServiceCenter is the service discovery component defined in [`common/servicediscovery/servicediscovery.go`](https://github.com/kingson4wu/fast_proxy/blob/main/common/servicediscovery/servicediscovery.go). It resolves service names to network addresses using a configurable `addressFunc`. By default, it returns one static address per service, but you can inject custom logic to implement dynamic resolution or load balancing algorithms.

### Is FastProxy suitable for high-availability deployments?

Yes, but only when paired with external load balancing infrastructure or custom ServiceCenter logic. The proxy itself handles single-endpoint forwarding efficiently, but relies on external systems or custom code to provide redundancy, failover, and traffic distribution across multiple upstream instances.