GoLift: A Scalable Load Balancing Solution in Go
- Round Robin: Distributes requests evenly across all servers, regardless of their current load.
- Weighted Round Robin: Allocates more requests to servers with higher capacity, refining the Round Robin approach.
- Least Connections: Prefers servers with the fewest active connections, promoting fair load distribution.
The Least Connection strategy, enhanced with a Round Robin tiebreaker, combines efficiency and fairness, especially suitable for high-traffic conditions. It dynamically adapts to server load changes, ensuring optimal resource utilization and user experience without overwhelming any single server.
This approach excels in distributed environments where demand fluctuates, such as e-commerce sites during sales events. It ensures that incoming requests are evenly distributed, preventing server overload and maintaining smooth operation.
GoLift implements this refined strategy as follows:
- Identify Servers: Determines servers with the lowest active connections.
- Single Server Assignment: Directly assigns requests if one server has the fewest connections.
- Round-Robin Tiebreaker: When multiple servers have the same number of connections, it selects in a Round-Robin manner.
- Single Server Selection: For servers
{server3: 0, others: 1+}
,server3
is chosen. - Round-Robin Cycling: With
{all servers: 1 connection}
, it cycles fromserver1
toserver6
, ensuring equitable distribution. - No Servers Available: Returns
nil
if no servers are alive, indicating a need for intervention. - Multiple Servers with Least Connections: Given
{server5: 0, server6: 0, others: 2+}
, selectsserver5
orserver6
based on Round-Robin position. - Round-Robin Across All Servers: Continues cycling through all servers
{all servers: 1 connection}
, maintaining fairness.
- Reduced Server Overload: Smartly balances load to prevent any server from being overwhelmed.
- Enhanced Reliability: More reliable service delivery by evenly distributing requests based on server capacity and current load.
- Troubleshooting Complexity: The dynamic nature of the strategy can complicate issue diagnosis.
- Increased Processing: The need for constant computation of server loads and decision-making.
- Capacity Ignorance: Focuses on connection counts without considering the actual capacity of servers.
- Efficient Data Structures: Implemented optimized data handling to reduce processing overhead.
- Health Checks: Integrated server health checks to dynamically adjust the pool based on real-time server status, addressing capacity concerns.
- Logging and Monitoring: Enhanced diagnostics with detailed logging and monitoring for better insight and quicker troubleshooting.
To run the application using the Makefile:
- Open your terminal and navigate to the project's root directory.
- (Optional) Adjust the environment variables in the Makefile as necessary to fit your setup.
- Execute the command:
make run
Regardless of the method chosen to run the application, you should observe output similar to the following in your terminal, indicating that the servers and the load balancer are up and running:
server-1 | Server1 listening on port :8000
server-2 | Server2 listening on port :8001
server-3 | Server3 listening on port :8002
server-4 | Server4 listening on port :8003
server-5 | Server5 listening on port :8004
load_balancer | Load Balancer listening on port 8080
├── .github
│ └── workflows
│ └── go-ci.yaml ← GitHub Actions CI workflows (Build, Test, Lint).
├── internal
│ └── domain
│ ├── load_balancer.go ← Load balancer logic implementation(Least Connection Strategy).
│ ├── load_balancer_test.go ← Unit Tests for load balancer functionality.
│ ├── server.go ← Server instance definition and bheaviour.
│ └── server_test.go ← Unit Tests for server functionality.
│ ├── server_pool.go ← Server pool for maintaining a list of servers.
│ └── common
│ ├── env_vars.go ← Utility functions for environment variable management.
│ ├── env_vars_test.go ← Tests for environment variable utility functions.
│ ├── srvvidgen.go ← Server ID generation logic(Hash value Server URL and Port).
│ └── srvvidgen_test.go ← Unit Tests for server ID generation.
│ └── transport
│ └── handler.go ← Forwarded http Request with reverse proxy.
├── .gitignore ← Specifies intentionally untracked files to ignore.
├── .golangci.yaml ← Configuration for golangci-lint.
├── compose.yaml ← Docker service setup for development environments.
├── Dockerfile ← Dockerfile for building the GoLift:latest application image.
├── go.mod ← Go module dependencies.
├── main.go ← Entry point to start the application services.
├── Makefile ← Make commands for building and running the application.
└── readme.md ← Project documentation and setup instructions.
curl --location '127.0.0.1:8080'
GET -> 127.0.0.1:8080