Understanding the Center Component in FastProxy: Service Discovery and Routing

The Center component in FastProxy acts as a service discovery façade that translates logical service names into network addresses, extracts target services from HTTP requests, and handles dynamic registration with discovery backends.

The kingson4wu/fast_proxy repository implements a high-performance proxy system that separates routing logic from service discovery concerns. The Center component—formally known as ServiceCenter—provides a unified interface for address resolution, client identification, and service registration without entangling the core proxy implementation with specific discovery mechanisms like Apollo or Consul.

Core Responsibilities of the Center Component

Service Address Resolution

The Center component translates logical service names into concrete network endpoints. The Address method in common/servicediscovery/servicediscovery.go implements this lookup:

func (sc *ServiceCenter) Address(serviceName string) *Address

This method returns an *Address struct containing the IP and port for the requested service. Proxy handlers invoke this via the global accessor to determine where to forward requests:

addr := server.Center().Address(targetName)
// Forward to addr.Ip:addr.Port

Client Service Identification

Before routing, the proxy must identify which service the client intends to reach. The ClientName method extracts this information from incoming HTTP requests:

func (sc *ServiceCenter) ClientName(req *http.Request) string

The default implementation reads the C_ServiceName header, though this behavior is fully customizable through the builder pattern. Both inbound and outbound proxies use this method to resolve the target service before address lookup.

Dynamic Service Registration

The Center handles registration of the proxy instance itself with external discovery systems. The Register method initiates this process:

func (sc *ServiceCenter) Register(name, ip string, port int) chan bool

This method returns a channel used to signal registration termination. In common/server/server.go, the server lifecycle invokes this during startup when a ServiceCenter is configured, ensuring the proxy advertises itself to the discovery backend (such as Apollo).

Pluggable Architecture via Builder Pattern

The ServiceCenterBuilder struct enables customization of all three core functions without modifying the proxy core. Located in common/servicediscovery/servicediscovery.go, the builder provides setters for:

  • AddressFunc – Custom service resolution logic
  • ClientNameFunc – Alternative methods for extracting the target service from requests
  • RegisterFunc – Integration with Consul, etcd, or other registries

The Build() method produces a ready-to-use *ServiceCenter instance with the injected behaviors.

Implementation Details and Source Code

ServiceCenter Structure and Methods

The core implementation resides in common/servicediscovery/servicediscovery.go. This file defines the ServiceCenter struct and its three primary methods: Address, ClientName, and Register. The builder pattern implementation allows runtime configuration of these behaviors, making the component adaptable to various infrastructure environments without code changes to the proxy handlers.

Integration with Server Lifecycle

The common/server/server.go file manages the global Proxy instance and exposes the Center() accessor method. During server startup, the Start() method checks for a configured ServiceCenter (p.sc != nil) and invokes Register() to initiate service advertisement. This integration ensures that the Center component participates in both the request routing path and the server lifecycle management.

Practical Usage Examples

Creating a Custom ServiceCenter

The following example demonstrates building a ServiceCenter with custom address resolution and client identification logic:

import (
    "github.com/kingson4wu/fast_proxy/common/servicediscovery"
    "net/http"
)

// Define a static address map for local testing
addrMap := map[string]*servicediscovery.Address{
    "user-service": {Ip: "10.1.2.3", Port: 8080},
    "order-service": {Ip: "10.1.2.4", Port: 8081},
}

// Build a custom ServiceCenter
sc := servicediscovery.Create().
    AddressFunc(func(name string) *servicediscovery.Address {
        return addrMap[name]
    }).
    ClientNameFunc(func(r *http.Request) string {
        // Extract service name from query parameter instead of header
        return r.URL.Query().Get("svc")
    }).
    RegisterFunc(func(name, ip string, port int) chan bool {
        // No-op registration for local testing
        return nil
    }).
    Build()

Starting a Server with the Custom Center

Integrate the custom ServiceCenter into the server lifecycle:

cfg := config.LoadFromFile("config.yaml")
logger := logger.NewZapLogger()

// Create the server instance
srv := outproxy.NewServer(cfg, logger, proxyHandler)

// Start with the custom ServiceCenter
srv.Start(server.WithServiceCenter(sc))

Using the Center in Proxy Handlers

Proxy handlers access the Center to resolve targets dynamically:

func handleProxy(w http.ResponseWriter, r *http.Request) {
    // Identify the target service from the request
    serviceName := server.Center().ClientName(r)
    
    // Resolve to concrete address
    addr := server.Center().Address(serviceName)
    if addr == nil {
        http.Error(w, "service not found", http.StatusBadGateway)
        return
    }
    
    // Forward request to addr.Ip:addr.Port
    // ...
}

Key Files and Architecture

The Center component spans several files within the kingson4wu/fast_proxy repository:

Summary

  • The Center component in FastProxy acts as a service discovery façade, decoupling proxy routing logic from specific discovery implementations.
  • It provides three core capabilities: service address resolution (Address), client service identification (ClientName), and dynamic registration (Register).
  • The builder pattern in common/servicediscovery/servicediscovery.go enables customization of all behaviors without modifying the proxy core.
  • The global accessor server.Center() in common/server/server.go provides convenient access from proxy handlers while integrating with the server lifecycle.
  • Default implementations use header-based routing (C_ServiceName), but the architecture supports integration with Apollo, Consul, etcd, or static maps.

Frequently Asked Questions

What is the primary purpose of the Center component in FastProxy?

The Center component serves as a service discovery abstraction layer that separates proxy routing logic from the underlying discovery mechanism. It translates logical service names into concrete network addresses, identifies which service a client wants to reach, and handles registration of the proxy instance with external discovery systems like Apollo.

How does FastProxy's Center component handle service discovery?

The Center component handles discovery through three pluggable functions defined in common/servicediscovery/servicediscovery.go. The Address method resolves service names to IP/port combinations, ClientName extracts the target service from HTTP requests (defaulting to the C_ServiceName header), and Register advertises the proxy instance to discovery backends. These behaviors can be customized via the ServiceCenterBuilder to integrate with Consul, etcd, or static configuration maps.

Can I customize the Center component to use a different service registry like Consul or etcd?

Yes, the Center component is designed for customization through the builder pattern. You can create a custom ServiceCenter by calling servicediscovery.Create() and providing your own AddressFunc, ClientNameFunc, and RegisterFunc implementations. This allows you to integrate with Consul, etcd, Zookeeper, or any custom discovery system without modifying the proxy handlers or core server logic.

Where is the Center component initialized in the FastProxy codebase?

The Center component is initialized in common/server/server.go within the server startup flow. The Start() method checks if a ServiceCenter has been configured (p.sc != nil) and invokes the Register() method to begin service advertisement. Proxy handlers access the initialized Center through the global server.Center() accessor, which retrieves the instance stored in the server's internal state.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →