|
| 1 | +## Proxy Kit |
| 2 | + |
| 3 | +A production-grade reverse proxy library implemented in Go. It not only provides high performance and multiple load balancing strategies, but also supports **dynamic route management**, allowing you to add or remove backend servers at runtime via API — without restarting the service. |
| 4 | + |
| 5 | +<br> |
| 6 | + |
| 7 | +### Core Features |
| 8 | + |
| 9 | +* **Dynamic Service Discovery**: Add or remove backend nodes in real-time through HTTP APIs. |
| 10 | +* **High Performance Core**: Built on `net/http/httputil` with deeply optimized connection pooling for effortless high-concurrency handling. |
| 11 | +* **Rich Load Balancing Strategies**: Includes Round Robin, The Least Connections, and IP Hash. |
| 12 | +* **Active Health Checks**: Automatically detects and isolates unhealthy nodes, and brings them back online once they recover. |
| 13 | +* **Multi-route Support**: Distribute traffic to different backend groups based on path prefixes. |
| 14 | + |
| 15 | +<br> |
| 16 | + |
| 17 | +### Example of Usage |
| 18 | + |
| 19 | +```go |
| 20 | +package main |
| 21 | + |
| 22 | +import ( |
| 23 | + "log" |
| 24 | + "net/http" |
| 25 | + "time" |
| 26 | + "github.com/go-dev-frame/sponge/pkg/proxykit" |
| 27 | +) |
| 28 | + |
| 29 | +func main() { |
| 30 | + prefixPath := "/proxy/" |
| 31 | + |
| 32 | + // 1. Create the route manager |
| 33 | + manager := proxykit.NewRouteManager() |
| 34 | + |
| 35 | + // 2. Initialize backend targets |
| 36 | + initialTargets := []string{"http://localhost:8081", "http://localhost:8082"} |
| 37 | + backends, _ := proxykit.ParseBackends(prefixPath, initialTargets) |
| 38 | + proxykit.StartHealthChecks(backends, proxykit.HealthCheckConfig{Interval: 5 * time.Second}) |
| 39 | + balancer := proxykit.NewRoundRobin(backends) |
| 40 | + |
| 41 | + // Register route |
| 42 | + apiRoute, err := manager.AddRoute(prefixPath, balancer) |
| 43 | + if err != nil { |
| 44 | + log.Fatalf("Could not add initial route: %v", err) |
| 45 | + } |
| 46 | + |
| 47 | + // 3. Build standard library mux |
| 48 | + mux := http.NewServeMux() |
| 49 | + |
| 50 | + // 4. Register proxy handler (same as gin.Any) |
| 51 | + mux.Handle(prefixPath, apiRoute.Proxy) |
| 52 | + |
| 53 | + // 5. Management API (corresponds to /endpoints/...) |
| 54 | + mux.HandleFunc("/endpoints/add", manager.HandleAddBackends) |
| 55 | + mux.HandleFunc("/endpoints/remove", manager.HandleRemoveBackends) |
| 56 | + mux.HandleFunc("/endpoints/list", manager.HandleListBackends) |
| 57 | + mux.HandleFunc("/endpoints", manager.HandleGetBackend) |
| 58 | + |
| 59 | + // 6. Other normal routes |
| 60 | + mux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) { |
| 61 | + w.Header().Set("Content-Type", "application/json") |
| 62 | + w.Write([]byte(`{"message": "pong"}`)) |
| 63 | + }) |
| 64 | + |
| 65 | + // 7. Start HTTP server |
| 66 | + log.Println("HTTP server with dynamic proxy started on http://localhost:8080") |
| 67 | + log.Printf("Proxying requests from %s*\n", prefixPath) |
| 68 | + log.Println("Management API available at /endpoints/*") |
| 69 | + |
| 70 | + err = http.ListenAndServe(":8080", mux) |
| 71 | + if err != nil { |
| 72 | + log.Fatal("ListenAndServe:", err) |
| 73 | + } |
| 74 | +} |
| 75 | +``` |
| 76 | + |
| 77 | +<br> |
| 78 | + |
| 79 | +### Management API Guide |
| 80 | + |
| 81 | +After the proxy is started, you can manage backend services dynamically via the following APIs. |
| 82 | + |
| 83 | +#### 1. List all backends |
| 84 | + |
| 85 | +Retrieve all backend nodes and their health status for the given route. |
| 86 | + |
| 87 | +* **GET** `/endpoints/list?prefixPath=/api/` |
| 88 | + |
| 89 | +```json |
| 90 | +{ |
| 91 | + "prefixPath": "/api/", |
| 92 | + "targets": [ |
| 93 | + {"target": "http://localhost:8081", "healthy": true} |
| 94 | + ] |
| 95 | +} |
| 96 | +``` |
| 97 | + |
| 98 | +#### 2. Add backend nodes |
| 99 | + |
| 100 | +Dynamically scale out. New nodes will automatically enter the health check loop and start receiving traffic. |
| 101 | + |
| 102 | +* **POST** `/endpoints/add` |
| 103 | +* **Body**: |
| 104 | + |
| 105 | + ```json |
| 106 | + { |
| 107 | + "prefixPath": "/api/", |
| 108 | + "targets": ["http://localhost:8083", "http://localhost:8084"] |
| 109 | + } |
| 110 | + ``` |
| 111 | + |
| 112 | +#### 3. Remove backend nodes |
| 113 | + |
| 114 | +Dynamically scale in. Health checks for removed nodes will stop automatically. |
| 115 | + |
| 116 | +* **POST** `/endpoints/remove` |
| 117 | +* **Body**: |
| 118 | + |
| 119 | + ```json |
| 120 | + { |
| 121 | + "prefixPath": "/api/", |
| 122 | + "targets": ["http://localhost:8081"] |
| 123 | + } |
| 124 | + ``` |
| 125 | + |
| 126 | +#### 4. Inspect a single backend node |
| 127 | + |
| 128 | +* **GET** `/endpoints?prefixPath=/api/&target=http://localhost:8082` |
| 129 | + |
| 130 | +```json |
| 131 | +{ |
| 132 | + "target": "http://localhost:8082", |
| 133 | + "healthy": true |
| 134 | +} |
| 135 | +``` |
0 commit comments