|
| 1 | +# Load Balancer in GO |
| 2 | + |
| 3 | +<div align="center"> |
| 4 | + |
| 5 | +[Features](#features) • [Quick Start](#quick-start) • [Usage](#usage) • [Configuration](#yaml-configuration-parameters) • [Strategies](#load-balancing-strategies) • [Health Checking](#health-checking) |
| 6 | + |
| 7 | +</div> |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +## Overview |
| 12 | + |
| 13 | +A **load balancer** built with Go that provides intelligent traffic distribution, automatic health checking, and multiple load balancing strategies. |
| 14 | + |
| 15 | +## Features |
| 16 | + |
| 17 | +- **Multiple Load Balancing Strategies:** Round Robin, Weighted, Smooth Weighted, Least Connections, Random |
| 18 | +- **Intelligent Health Checking:** Concurrent checks, recovery, configurable intervals |
| 19 | +- **Safe Architecture:** Thread-safe, graceful shutdown and logging |
| 20 | +- **Flexible Configuration:** YAML, environment defaults, minimal setup |
| 21 | + |
| 22 | +## Quick Start |
| 23 | + |
| 24 | +```bash |
| 25 | +git clone https://github.com/franciscodelahoz/load-balancer.git |
| 26 | +cd load-balancer |
| 27 | +go mod tidy |
| 28 | +go build -o load-balancer ./cmd/server |
| 29 | +./load-balancer |
| 30 | +``` |
| 31 | + |
| 32 | +## Usage |
| 33 | + |
| 34 | +```bash |
| 35 | +go run ./cmd/server/main.go |
| 36 | +go run ./cmd/server/main.go -config=production.yaml |
| 37 | +curl http://localhost:8080/ |
| 38 | +``` |
| 39 | + |
| 40 | +### Example Test Backends |
| 41 | + |
| 42 | +```bash |
| 43 | +# Terminal 1 |
| 44 | +python3 -m http.server 3001 |
| 45 | +# Terminal 2 |
| 46 | +python3 -m http.server 3002 |
| 47 | +``` |
| 48 | + |
| 49 | +--- |
| 50 | + |
| 51 | +## YAML Configuration Parameters |
| 52 | + |
| 53 | +All configuration is done via a YAML file. Below, each parameter is explained in detail, including its purpose and default value if omitted. |
| 54 | + |
| 55 | +--- |
| 56 | + |
| 57 | +### **server** |
| 58 | + |
| 59 | +- **port** |
| 60 | + *(default: `8080`)* |
| 61 | + Port on which the load balancer HTTP server listens. |
| 62 | + |
| 63 | +### **load_balancer** |
| 64 | + |
| 65 | +- **strategy** |
| 66 | + *(default: `"round-robin"`)* |
| 67 | + Load balancing algorithm. Options: `"round-robin"`, `"weighted-round-robin"`, `"smooth-weighted-round-robin"`, `"least-connections"`, `"random"`. |
| 68 | + |
| 69 | +### **backends** |
| 70 | + |
| 71 | +- **url** |
| 72 | + *(required)* |
| 73 | + The URL of the backend service. |
| 74 | + |
| 75 | +- **weight** |
| 76 | + *(default: `1`)* |
| 77 | + Relative weight for distributing traffic. Higher values mean more requests sent to this backend. |
| 78 | + |
| 79 | +### **health_check** |
| 80 | + |
| 81 | +- **enabled** |
| 82 | + *(default: `true`)* |
| 83 | + Enables or disables health checking. |
| 84 | + |
| 85 | +- **interval** |
| 86 | + *(default: `10s`)* |
| 87 | + How often to perform health checks (Go duration format, e.g., `10s`, `1m`). |
| 88 | + |
| 89 | +- **timeout** |
| 90 | + *(default: `5s`)* |
| 91 | + Timeout for each health check request. |
| 92 | + |
| 93 | +- **path** |
| 94 | + *(default: `"/health"`)* |
| 95 | + Path to request on each backend for health checking. |
| 96 | + |
| 97 | +- **method** |
| 98 | + *(default: `"GET"`)* |
| 99 | + HTTP method to use for health checks. |
| 100 | + |
| 101 | +- **success_threshold** |
| 102 | + *(default: `3`)* |
| 103 | + Number of consecutive successful health checks required before a backend is marked healthy. |
| 104 | + |
| 105 | +- **failure_threshold** |
| 106 | + *(default: `3`)* |
| 107 | + Number of consecutive failed health checks required before a backend is marked unhealthy. |
| 108 | + |
| 109 | +--- |
| 110 | + |
| 111 | +### **Examples** |
| 112 | + |
| 113 | +**Minimal Configuration:** |
| 114 | + |
| 115 | +```yaml |
| 116 | +backends: |
| 117 | + - url: "http://service-1:8080" |
| 118 | +``` |
| 119 | +
|
| 120 | +**Full Configuration:** |
| 121 | +
|
| 122 | +```yaml |
| 123 | +server: |
| 124 | + port: 8080 |
| 125 | + |
| 126 | +load_balancer: |
| 127 | + strategy: "least-connections" |
| 128 | + |
| 129 | +backends: |
| 130 | + - url: "http://service-1:8080" |
| 131 | + weight: 2 |
| 132 | + |
| 133 | +health_check: |
| 134 | + enabled: true |
| 135 | + interval: 30s |
| 136 | + timeout: 5s |
| 137 | + path: "/health" |
| 138 | + method: "GET" |
| 139 | + success_threshold: 5 |
| 140 | + failure_threshold: 2 |
| 141 | +``` |
| 142 | +
|
| 143 | +--- |
| 144 | +
|
| 145 | +## Health Endpoint Guidance |
| 146 | +
|
| 147 | +The load balancer marks a backend as *healthy* when the configured health endpoint returns an HTTP 2xx status. If your application responds with 200 OK for unknown or invalid routes, the health check will always succeed and give a false positive. |
| 148 | +
|
| 149 | +### Recommendations: |
| 150 | +- Expose a dedicated, lightweight health endpoint (e.g. /health) that returns 200 only when the service is actually healthy. |
| 151 | +- Return 404/4xx for unknown or invalid paths. |
| 152 | +- Keep health checks fast — avoid expensive operations. |
| 153 | +
|
| 154 | +### Quick test: |
| 155 | +
|
| 156 | +```bash |
| 157 | +curl -i http://your-backend/health # must return 200 |
| 158 | +curl -i http://your-backend/invalid-path # must NOT return 200 |
| 159 | +``` |
| 160 | + |
| 161 | +**Go Example:** |
| 162 | +```go |
| 163 | +http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { |
| 164 | + w.Header().Set("Content-Type", "application/json") |
| 165 | + w.WriteHeader(http.StatusOK) |
| 166 | + w.Write([]byte(`{"status":"ok"}`)) |
| 167 | +}) |
| 168 | + |
| 169 | +http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { |
| 170 | + http.NotFound(w, r) |
| 171 | +}) |
| 172 | +``` |
| 173 | + |
| 174 | +--- |
| 175 | + |
| 176 | +## Load Balancing Strategies |
| 177 | + |
| 178 | +- `round-robin` |
| 179 | +- `weighted-round-robin` |
| 180 | +- `smooth-weighted-round-robin` |
| 181 | +- `least-connections` |
| 182 | +- `random` |
| 183 | + |
| 184 | +Set the strategy in your YAML config: |
| 185 | + |
| 186 | +```yaml |
| 187 | +load_balancer: |
| 188 | + strategy: "smooth-weighted-round-robin" |
| 189 | +``` |
| 190 | +
|
| 191 | +--- |
| 192 | +
|
| 193 | +## Health Checking |
| 194 | +
|
| 195 | +**Config:** |
| 196 | +```yaml |
| 197 | +health_check: |
| 198 | + enabled: true |
| 199 | + interval: 10s |
| 200 | + timeout: 5s |
| 201 | + path: "/health" |
| 202 | + method: "GET" |
| 203 | +``` |
| 204 | +
|
| 205 | +**Best Practices:** |
| 206 | +- Enable health checking for auto-recovery |
| 207 | +- Use a dedicated health endpoint |
| 208 | +- Set proper intervals and timeouts |
| 209 | +
|
| 210 | +--- |
| 211 | +
|
| 212 | +## Monitoring & Metrics |
| 213 | +
|
| 214 | +- **Logging:** |
| 215 | + Logs show strategy, backend states, health results, routing decisions. |
| 216 | +
|
| 217 | +``` |
| 218 | +2025/09/10 10:50:24 [SYSTEM] Starting Load Balancer... |
| 219 | +2025/09/10 10:50:24 [SYSTEM] Added backend: http://localhost:3002 (weight: 1) |
| 220 | +2025/09/10 10:50:24 [HEALTH] Registered backend for health checking: http://localhost:3002 |
| 221 | +2025/09/10 10:50:24 [HEALTH] Health checker started with 1 backends |
| 222 | +2025/09/10 10:50:24 [HEALTH] Health checking enabled (interval: 10s) |
| 223 | +2025/09/10 10:50:24 [SYSTEM] Load Balancer running on ::8080 |
| 224 | +2025/09/10 10:50:24 [SYSTEM] Strategy: Smooth Weighted Round Robin |
| 225 | +2025/09/10 10:50:24 [SYSTEM] Admin API: http://localhost::8080/admin/health |
| 226 | +2025/09/10 10:50:29 [HEALTH] Backend http://localhost:3002 health check passed (latency: 5.055478666s) |
| 227 | +2025/09/10 10:51:39 [HEALTH] Backend http://localhost:3002 health check failed: unexpected HTTP status from backend: 404 |
| 228 | +``` |
| 229 | +
|
| 230 | +--- |
| 231 | +
|
| 232 | +## Architecture |
| 233 | +
|
| 234 | +The diagram below shows the overall structure and flow: |
| 235 | +
|
| 236 | +``` |
| 237 | + Load Balancer |
| 238 | + │ |
| 239 | + ┌────────────────┼────────────────┐ |
| 240 | + │ │ │ |
| 241 | + Strategies Health Server |
| 242 | + Manager Checker Pool |
| 243 | + │ │ │ |
| 244 | + └────────────────┼────────────────┘ |
| 245 | + │ |
| 246 | + ProxyHandler |
| 247 | + │ |
| 248 | + ┌───────┼───────┐ |
| 249 | + │ │ │ |
| 250 | + Backend1 Backend2 Backend3 |
| 251 | +``` |
| 252 | + |
| 253 | +- **Load Balancer:** Orchestrates incoming traffic and applies load balancing logic. |
| 254 | +- **Strategies Manager:** Chooses the backend based on selected algorithm. |
| 255 | +- **Health Checker:** Continuously checks backend health and availability. |
| 256 | +- **Server Pool:** Maintains list and state of backend servers. |
| 257 | +- **Proxy Handler:** Handles request forwarding and error responses. |
| 258 | +- **Backends:** The actual application servers receiving requests. |
| 259 | + |
| 260 | +--- |
| 261 | + |
| 262 | +## Development |
| 263 | + |
| 264 | +**Project Structure:** |
| 265 | + |
| 266 | +``` |
| 267 | +load-balancer/ |
| 268 | +├── cmd/ |
| 269 | +│ └── server/ |
| 270 | +│ └── main.go # Application entry point |
| 271 | +├── internal/ |
| 272 | +│ ├── backend/ # Backend management |
| 273 | +│ ├── config/ # Configuration handling |
| 274 | +│ ├── handlers/ # HTTP handlers |
| 275 | +│ ├── health/ # Health checking |
| 276 | +│ ├── loadbalancer/ # Core load balancer |
| 277 | +│ └── strategies/ # Load balancing algorithms |
| 278 | +├── config.yaml # Default configuration |
| 279 | +└── README.md |
| 280 | +``` |
| 281 | + |
| 282 | +**Build & Run:** |
| 283 | +```bash |
| 284 | +go run ./cmd/server/main.go |
| 285 | +go build -o load-balancer ./cmd/server |
| 286 | +./load-balancer |
| 287 | +``` |
| 288 | + |
| 289 | +**Production Build:** |
| 290 | +```bash |
| 291 | +go build -ldflags="-w -s" -o load-balancer ./cmd/server |
| 292 | +GOOS=linux GOARCH=amd64 go build -o load-balancer-linux ./cmd/server |
| 293 | +``` |
| 294 | + |
| 295 | +**Roadmap:** |
| 296 | +- [ ] Unit tests implementation |
| 297 | +- [ ] Metrics endpoint (`/metrics`) |
| 298 | +- [ ] Docker Compose setup and examples |
| 299 | +- [ ] Performance benchmarks |
0 commit comments