{"id":36898172,"url":"https://github.com/aaydin-tr/divisor","last_synced_at":"2026-01-12T15:43:49.566Z","repository":{"id":109478908,"uuid":"558992198","full_name":"aaydin-tr/divisor","owner":"aaydin-tr","description":"A fast and easy-to-configure load balancer","archived":false,"fork":false,"pushed_at":"2025-12-10T21:57:36.000Z","size":7563,"stargazers_count":72,"open_issues_count":8,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-12-11T09:17:58.892Z","etag":null,"topics":["easy-to-use","fasthttp","friendly","go","load-balancer","performance"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aaydin-tr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-10-28T19:12:25.000Z","updated_at":"2025-12-09T01:48:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"44fce2d8-8e87-4ecb-90e0-32680205a0ab","html_url":"https://github.com/aaydin-tr/divisor","commit_stats":null,"previous_names":["aaydin-tr/balancer"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/aaydin-tr/divisor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aaydin-tr%2Fdivisor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aaydin-tr%2Fdivisor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aaydin-tr%2Fdivisor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aaydin-tr%2Fdivisor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aaydin-tr","download_url":"https://codeload.github.com/aaydin-tr/divisor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aaydin-tr%2Fdivisor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28341571,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T12:22:26.515Z","status":"ssl_error","status_checked_at":"2026-01-12T12:22:10.856Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["easy-to-use","fasthttp","friendly","go","load-balancer","performance"],"created_at":"2026-01-12T15:43:49.492Z","updated_at":"2026-01-12T15:43:49.552Z","avatar_url":"https://github.com/aaydin-tr.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cbr /\u003e\r\n\u003cdiv align=\"center\"\u003e\r\n  \u003ch3 align=\"center\"\u003eDivisor\u003c/h3\u003e\r\n\r\n  \u003cp align=\"center\"\u003e\r\n    A fast and easy-to-configure load balancer\r\n    \u003cbr /\u003e\r\n    \u003cbr /\u003e\r\n  \u003c/p\u003e\r\n\u003c/div\u003e\r\n\r\n\u003cdetails\u003e\r\n  \u003csummary\u003eTable of Contents\u003c/summary\u003e\r\n  \u003col\u003e\r\n    \u003cli\u003e\u003ca href=\"#about-the-project\"\u003eAbout The Project\u003c/a\u003e\u003c/li\u003e\r\n    \u003cli\u003e\u003ca href=\"#features\"\u003eFeatures\u003c/a\u003e\u003c/li\u003e\r\n    \u003cli\u003e\u003ca href=\"#installation\"\u003eInstallation\u003c/a\u003e\u003c/li\u003e\r\n    \u003cli\u003e\u003ca href=\"#usage\"\u003eUsage\u003c/a\u003e\u003c/li\u003e\r\n    \u003cli\u003e\u003ca href=\"#configuration\"\u003eConfiguration\u003c/a\u003e\u003c/li\u003e\r\n    \u003cli\u003e\u003ca href=\"#custom-middleware\"\u003eCustom Middleware\u003c/a\u003e\u003c/li\u003e\r\n    \u003cli\u003e\u003ca href=\"#limitations\"\u003eLimitations\u003c/a\u003e\u003c/li\u003e\r\n    \u003cli\u003e\u003ca href=\"#benchmark\"\u003eBenchmark\u003c/a\u003e\u003c/li\u003e\r\n    \u003cli\u003e\u003ca href=\"#todo\"\u003eTODO\u003c/a\u003e\u003c/li\u003e\r\n    \u003cli\u003e\u003ca href=\"#contributors\"\u003eContributors\u003c/a\u003e\u003c/li\u003e\r\n    \u003cli\u003e\u003ca href=\"#license\"\u003eLicense\u003c/a\u003e\u003c/li\u003e\r\n  \u003c/ol\u003e\r\n\u003c/details\u003e\r\n\r\n## About The Project\r\nThis project is designed to provide a fast and easy-to-configure load balancer in Go language. It currently includes **round-robin**, **weighted round-robin**, **least-connection**, **least-response-time**, **ip-hash** and **random** algorithms, but we have more to add to our [TODO](#todo) list.\r\n\r\nThe project is developed using the [fasthttp](https://github.com/valyala/fasthttp) library for HTTP/1.1, which ensures high performance. For HTTP/2 support, it uses the native Go `net/http` package with HTTP/2 configuration. Its purpose is to distribute the load evenly among multiple servers by routing incoming requests.\r\n\r\nThe project aims to simplify the configuration process for users while performing the essential functions of load balancers. Therefore, it offers several configuration options that can be adjusted to meet the users needs.\r\n\r\nThis project is particularly suitable for large-scale applications and websites. It can be used for any application that requires a load balancer, thanks to its high performance, ease of configuration, and support for different algorithms.\r\n\r\n\r\n## Features\r\n- Fast and easy-to-configure load balancer.\r\n- Supports round-robin, weighted round-robin, least-connection, least-response-time, IP hash, and random algorithms.\r\n- Supports TLS and HTTP/2 for the frontend server.\r\n- Support for custom middleware written in Go.\r\n- Uses the fasthttp library for HTTP/1.1 and native Go `net/http` package for HTTP/2, ensuring high performance and scalability.\r\n- Offers multiple configuration options to suit user needs.\r\n- Can handle large-scale applications and websites.\r\n- Includes a built-in monitoring system that displays real-time information on the system's CPU usage, RAM usage, number of Goroutines, and open connections.\r\n- Prometheus support for monitoring. (`http://monitoring-host:monitoring-port/metrics` can be used to get prometheus metrics)\r\n- Provides information on each server's average response time, total request count, and last time used.\r\n- Lightweight and efficient implementation for minimal resource usage.\r\n\r\n## Installation\r\n\r\n#### Downloading the Release\r\nThe latest release of Divisor can be downloaded from the [releases](https://github.com/aaydin-tr/divisor/releases) page. Choose the suitable binary for your system, download and extract the archive, and then move the binary to a directory in your system's $PATH variable (e.g. /usr/local/bin).\r\n\r\n#### Building from Source\r\nAlternatively, you can build Divisor from source by cloning this repository to your local machine and running the following commands:\r\n\r\n```bash\r\ngit clone https://github.com/aaydin-tr/divisor.git \u0026\u0026\r\ncd divisor \u0026\u0026\r\ngo build -o divisor \u0026\u0026\r\n./divisor\r\n```\r\n\r\n#### Using go install\r\nYou can also install Divisor using the `go install` command:\r\n\r\n```bash\r\ngo install github.com/aaydin-tr/divisor@latest\r\n```\r\n\r\nThis will install the divisor binary to your system's `$GOPATH/bin` directory. Make sure this directory is included in your system's `$PATH` variable to make the divisor accessible from anywhere.\r\n\r\nThat's it! You're now ready to use Divisor in your project.\r\n\r\n## Usage\r\n\r\nYou need a `config.yaml` file to use Divisor, you can give this file to Divisor to use with the `--config` flag, by default it will try to use a `config.yaml` file in the directory it is in. [Example config files](https://github.com/aaydin-tr/divisor/tree/main/examples)\r\n\u003e :warning: Please use absolute path for \"config.yaml\" while using \"--config\" flag\r\n\r\n## Configuration\r\n\r\n### Minimal Example\r\n```yaml\r\nport: 8000  # Required\r\nbackends:\r\n  - url: localhost:8080\r\n  - url: localhost:7070\r\n```\r\n\r\n### Core Settings\r\n\r\n| Name | Description | Type | Default | Required |\r\n| --- | --- | --- | --- | --- |\r\n| port | Server port | string | - | ⚠️ **Yes** |\r\n| host | Server host | string | `localhost` | No |\r\n| type | Load balancing algorithm | string | `round-robin` | No |\r\n| health_checker_time | Health check interval for backends | duration | `30s` | No |\r\n\r\n**Valid algorithm types**: `round-robin`, `w-round-robin`, `ip-hash`, `random`, `least-connection`, `least-response-time`\r\n\r\n### Backend Settings\r\n\r\n| Name | Description | Type | Default | Required |\r\n| --- | --- | --- | --- | --- |\r\n| backends | List of backend servers | array | - | ⚠️ **Yes** (min: 1) |\r\n| backends.url | Backend URL (without protocol) | string | - | ⚠️ **Yes** |\r\n| backends.health_check_path | Health check endpoint | string | `/` | No |\r\n| backends.weight | Backend weight (w-round-robin only) | int | - | ⚠️ **w-round-robin** |\r\n| backends.max_conn | Max connections per backend | int | `512` | No |\r\n| backends.max_conn_timeout | Max wait time for free connection | duration | `30s` | No |\r\n| backends.max_conn_duration | Connection keep-alive duration | duration | `10s` | No |\r\n| backends.max_idle_conn_duration | Idle connection timeout | duration | `10s` | No |\r\n| backends.max_idemponent_call_attempts | Retry attempts for idempotent calls | int | `5` | No |\r\n\r\n### Monitoring Settings\r\n\r\n| Name | Description | Type | Default |\r\n| --- | --- | --- | --- |\r\n| monitoring.host | Metrics server host | string | `localhost` |\r\n| monitoring.port | Metrics server port | string | `8001` |\r\n\r\n### Server Settings\r\n\r\n| Name | Description | Type | Default |\r\n| --- | --- | --- | --- |\r\n| server.http_version | HTTP protocol version (`http1` or `http2`) | string | `http1` |\r\n| server.cert_file | TLS certificate file path | string | - |\r\n| server.key_file | TLS private key file path | string | - |\r\n| server.max_idle_worker_duration | Worker pool idle timeout | duration | `10s` |\r\n| server.tcp_keepalive_period | TCP keep-alive interval (OS default if unset) | duration | - |\r\n| server.concurrency | Max concurrent connections | int | `262144` |\r\n| server.read_timeout | Request read timeout | duration | unlimited |\r\n| server.write_timeout | Response write timeout | duration | unlimited |\r\n| server.idle_timeout | Keep-alive idle timeout | duration | unlimited |\r\n| server.disable_keepalive | Force connection close after response | bool | `false` |\r\n| server.disable_header_names_normalizing | Preserve original header name casing | bool | `false` |\r\n\r\n### Custom Headers\r\n\r\n| Name | Description | Type |\r\n| --- | --- | --- |\r\n| custom_headers | Headers injected into backend requests | map |\r\n| custom_headers.`\u003cname\u003e` | Header value (special variables supported) | string |\r\n\r\n**Special variables**: `$remote_addr` (client IP), `$time` (request timestamp), `$uuid` (request UUID), `$incremental` (per-backend counter)\r\n\r\n**Example**:\r\n```yaml\r\ncustom_headers:\r\n  x-client-ip: $remote_addr\r\n  x-request-id: $uuid\r\n```\r\n\r\n### Middlewares\r\n\r\n| Name | Description | Type | Default | Required |\r\n| --- | --- | --- | --- | --- |\r\n| middlewares | List of custom middleware | array | - | No |\r\n| middlewares.name | Middleware identifier | string | - | ⚠️ **Yes** |\r\n| middlewares.disabled | Skip middleware execution | bool | `false` | No |\r\n| middlewares.code | Inline Go code | string | - | ⚠️ **Yes** (or file) |\r\n| middlewares.file | Path to Go code file | string | - | ⚠️ **Yes** (or code) |\r\n| middlewares.config | Config passed to middleware constructor | map | - | No |\r\n\r\n### Important Notes\r\n\r\n- **Protocol stripping**: Backend URLs automatically have `http://` or `https://` removed\r\n- **HTTP/2 requirement**: `server.http_version: http2` requires both `cert_file` and `key_file`\r\n- **Weighted round-robin**: Single backend auto-converts to regular round-robin\r\n- **Middleware validation**: Must specify either `code` OR `file` (not both), unless `disabled: true`\r\n- **Custom header validation**: Only accepts the 4 special variables listed above\r\n- **Default algorithm**: If `type` is omitted or invalid, defaults to `round-robin`\r\n\r\n\r\nPlease see [example config files](https://github.com/aaydin-tr/divisor/tree/main/examples)\r\n\r\n## Custom Middleware\r\n\r\nDivisor supports custom middleware written in Go. You can define middleware to intercept requests and responses, allowing you to implement custom logic such as authentication, logging, header manipulation, etc.\r\n\r\nThe middleware is executed using the [Yaegi](https://github.com/traefik/yaegi) interpreter.\r\n\r\n### Usage\r\n\r\nYour middleware must implement the `Middleware` interface and provide a `New` function constructor.\r\n\r\n\u003e :warning: Make sure you run `go get github.com/aaydin-tr/divisor/middleware` to import the middleware package. \r\n\r\n```go\r\npackage middleware\r\n\r\nimport (\r\n    \"github.com/aaydin-tr/divisor/middleware\"\r\n    \"fmt\"\r\n)\r\n\r\ntype MyMiddleware struct {\r\n    config map[string]any\r\n}\r\n\r\nfunc New(config map[string]any) middleware.Middleware {\r\n    return \u0026MyMiddleware{config: config}\r\n}\r\n\r\nfunc (m *MyMiddleware) OnRequest(ctx *middleware.Context) error {\r\n    // Logic to execute before request reached to backend server\r\n    // e.g. ctx.Request.Header.Set(\"X-Custom-Header\", \"Value\")\r\n    fmt.Println(\"OnRequest\")\r\n    return nil\r\n}\r\n\r\nfunc (m *MyMiddleware) OnResponse(ctx *middleware.Context, err error) error {\r\n    // Logic to execute after response is received from backend server\r\n    fmt.Println(\"OnResponse\")\r\n    return nil\r\n}\r\n```\r\n\r\n### Configuration\r\n\r\nYou can configure middlewares in `config.yaml` using either inline code or a file path.\r\n\r\n**Using a file:**\r\n\r\n```yaml\r\nmiddlewares:\r\n  - name: \"my-logger\"\r\n    file: \"./middleware/logger.go\"\r\n    config:\r\n      prefix: \"[LOG]\"\r\n```\r\n\r\n**Using inline code:**\r\n\r\n```yaml\r\nmiddlewares:\r\n  - name: \"simple-header\"\r\n    code: |\r\n      package middleware\r\n      \r\n      import \"github.com/aaydin-tr/divisor/middleware\"\r\n\r\n      type HeaderMiddleware struct {}\r\n\r\n      func New(config map[string]any) middleware.Middleware {\r\n          return \u0026HeaderMiddleware{}\r\n      }\r\n\r\n      func (h *HeaderMiddleware) OnRequest(ctx *middleware.Context) error {\r\n          ctx.Request.Header.Set(\"X-Divisor\", \"True\")\r\n          return nil\r\n      }\r\n\r\n      func (h *HeaderMiddleware) OnResponse(ctx *middleware.Context, err error) error {\r\n          return nil\r\n      }\r\n```\r\n\r\n### Request/Response Lifecycle\r\n\r\nThe middleware execution flow allows you to intercept and control the complete request/response lifecycle. Here's exactly what happens when a request is processed:\r\n\r\n#### Complete Request Flow\r\n\r\n1.  **Pre-Request Setup**\r\n    -   Internal request preprocessing occurs\r\n    -   Headers and request context are prepared\r\n\r\n2.  **OnRequest Middleware Execution**\r\n    -   Executed **before** the request is sent to the backend\r\n    -   Receives the middleware context with full access to request/response\r\n    -   **If `OnRequest` returns an error:**\r\n        -   ⛔ The execution chain stops **immediately**\r\n        -   ⛔ The request is **NOT** sent to the backend\r\n        -   ⛔ `OnResponse` is **NOT** called\r\n        -   ⛔ Post-response cleanup occurs\r\n        -   ⛔ The error is returned to the client\r\n    -   **If `OnRequest` succeeds (returns `nil`):**\r\n        -   ✅ Execution continues to backend proxy\r\n\r\n3.  **Backend Proxy**\r\n    -   The request is forwarded to the selected backend server\r\n    -   The response (or error) is captured and stored\r\n    -   **Important:** Even if the backend fails, execution continues to `OnResponse`\r\n\r\n4.  **OnResponse Middleware Execution**\r\n    -   **Always** executed after the proxy attempt (success or failure)\r\n    -   Receives **two arguments:**\r\n        1. The middleware context\r\n        2. The backend error (if any) - will be `nil` on success\r\n    -   You can inspect the backend error and decide how to handle it\r\n    -   **If `OnResponse` returns an error:**\r\n        -   ⚠️ It **overrides** any backend error\r\n        -   ⚠️ Post-response cleanup occurs\r\n        -   ⚠️ This error is returned to the client\r\n        -   ⚠️ The standard error response is replaced\r\n    -   **If `OnResponse` returns `nil`:**\r\n        -   Execution continues normally\r\n        -   If backend error exists, standard 500 error response is generated\r\n        -   If no error, the backend response is sent to client\r\n\r\n5.  **Post-Response Cleanup**\r\n    -   Internal response postprocessing occurs\r\n    -   Always executed regardless of success or failure\r\n\r\n6.  **Response Sent**\r\n    -   Final response is sent to the client\r\n\r\n#### Key Takeaways\r\n\r\n-   🎯 **OnRequest** acts as a gatekeeper - it can block requests before they reach the backend\r\n-   🔄 **OnResponse** always runs after the proxy attempt, giving you a chance to handle backend errors\r\n-   🛡️ **OnResponse** can override backend errors, allowing custom error handling and responses\r\n-   ⏱️ Both middlewares have access to the full request/response context for inspection and modification\r\n\r\n### Request/Response Diagram\r\n\r\n```mermaid\r\nflowchart TD\r\n    Start([Client Request]) --\u003e PreReq[Pre-Request Setup]\r\n    PreReq --\u003e OnReq{OnRequest Middleware}\r\n    \r\n    OnReq --\u003e|Returns Error| PostRes1[Post-Response Cleanup]\r\n    PostRes1 --\u003e ReturnErr([Return OnRequest Error])\r\n    \r\n    OnReq --\u003e|Returns nil| Proxy[Forward to Backend Server]\r\n    \r\n    Proxy --\u003e CaptureErr[Capture Backend Response/Error]\r\n    CaptureErr --\u003e OnRes{OnResponse Middleware}\r\n    \r\n    OnRes --\u003e|Returns Error| PostRes2[Post-Response Cleanup]\r\n    PostRes2 --\u003e ReturnMwErr([Return OnResponse Error\u003cbr/\u003eBackend error overridden])\r\n    \r\n    OnRes --\u003e|Returns nil| PostRes3[Post-Response Cleanup]\r\n    PostRes3 --\u003e CheckBackendErr{Backend Error Exists?}\r\n    \r\n    CheckBackendErr --\u003e|Yes| GenerateErr[Generate 500 Error Response]\r\n    GenerateErr --\u003e ReturnServerErr([Return Server Error])\r\n    \r\n    CheckBackendErr --\u003e|No| ReturnOK([Return Success Response])\r\n```\r\n\r\n## Limitations\r\nWhile Divisor has several features and benefits, it also has some limitations to be aware of:\r\n\r\n- Divisor currently operates at layer 7, meaning it is specifically designed for HTTP(S) load balancing. It does not support other protocols, such as TCP or UDP.\r\n- Divisor does not support HTTP/3, which may be important for some applications.\r\n- Divisor does not support HTTPS for backend servers. HTTPS only available for frontend server.\r\n\r\nPlease keep these limitations in mind when considering whether this load balancer is the right choice for your project.\r\n\r\n## Benchmark\r\nPlease see the [benchmark folder](https://github.com/aaydin-tr/divisor/tree/main/benchmark) for detail explanation \r\n\r\n## TODO\r\nWhile Divisor has several features, there are also some areas for improvement that are planned for future releases:\r\n\r\n- [ ] Add support for other protocols, such as TCP or UDP.\r\n- [x] Add TLS support for frontend.\r\n- [x] Support HTTP/2 in frontend server.\r\n- [ ] Add more load balancing algorithms, such as,\r\n  - [x] least connection\r\n  - [x] least-response-time\r\n  - [ ] sticky round-robin\r\n- [ ] Improve performance and scalability for high-traffic applications.\r\n- [x] Expand monitoring capabilities to provide more detailed metrics and analytics.\r\n\r\nBy addressing these issues and adding new features, we aim to make Divisor an even more versatile and powerful tool for managing traffic in modern web applications.\r\n\r\n## Contributors\r\n\u003ca href = \"https://github.com/aaydin-tr/divisor/graphs/contributors\"\u003e\r\n  \u003cimg src = \"https://contrib.rocks/image?repo=aaydin-tr/divisor\"/\u003e\r\n\u003c/a\u003e\r\n\r\n## License\r\nThis project is licensed under the MIT License. See the LICENSE file for more information.\r\n\r\nThe MIT License is a permissive open-source software license that allows users to modify and redistribute the code, as long as the original license and copyright notice are included. This means that you are free to use Divisor for any purpose, including commercial projects, without having to pay any licensing fees or royalties. However, it is provided \"as is\" and without warranty of any kind, so use it at your own risk.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faaydin-tr%2Fdivisor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faaydin-tr%2Fdivisor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faaydin-tr%2Fdivisor/lists"}