{"@context":"https://w3id.org/codemeta/3.0","@type":"SoftwareSourceCode","identifier":"pkg:golang/github.com/rudderlabs/cslb","name":"github.com/rudderlabs/cslb","description":"Package cslb provides transparent HTTP/HTTPS Client Side Load Balancing for Go programs.\n\nCslb intercepts \"net/http\" Dial Requests and re-directs them to a preferred set of target hosts\nbased on the load balancing configuration expressed in DNS SRV and TXT Resource Records (RRs).\n\nOnly one trivial change is required to client applications to benefit from cslb which is to import\nthis package and (if needed) enabling it for non-default http.Transport instances. Cslb processing\nis triggered by the presence of SRV RRs. If no SRVs exist cslb is benign which means you can deploy\nyour application with cslb and independently activate and deactivate cslb processing for each\nservice at any time.\n\nNo server-side changes are required at all - apart for possibly dispensing with your server-side\nload-balancers!\n\nImporting cslb automatically enables interception for http.DefaultTransport. In this program\nsnippet:\n\nthe Dial Request made by http.Get is intercepted and processed by cslb.\n\nIf the application uses its own http.Transport then cslb processing needs to be activated by calling\nthe cslb.Enable() function, i.e.:\n\nThe cslb.Enable() function replaces http.Transport.DialContext with its own intercept function.\n\nServer-side load-balancers are no panacea. They add deployment and diagnostic complexity, cost,\nthroughput constraints and become an additional point of possible failure.\n\nCslb can help you achieve good load-balancing and fail-over behaviour without the need for *any*\nserver-side load-balancers. This is particularly useful in enterprise and micro-service deployments\nas well as smaller application deployments where configuring and managing load-balancers is a\nsignificant resource drain.\n\nCslb can be used to load-balance across geographically dispersed targets or where \"hot stand-by\"\nsystems are purposely deployed on diverse infrastructure.\n\nWhen cslb intercepts a http.Transport Dial Request to port 80 or port 443 it looks up SRV RRs as\nprescribed by RFC2782. That is, _http._tcp.$domain and _https._tcp.$domain respectively. Cslb\ndirects the Dial Request to the highest preference target based on the SRV algorithm. If that Dial\nRequest fails, it tries the next lower preference target until a successful connection is returned\nor all unique targets fail or it runs out of time.\n\nCslb caches the SRV RRs (or their non-existence) as well as the result of Dial Requests to the SRV\ntargets to optimize subequent intercepted calls and the selection of preferred targets. If no SRV\nRRs exist, cslb passes the Dial Request on to net.DialContext.\n\nCslb has specific rules about when interception occurs. It normally only considers intercepting port\n80 and port 443 however if the \"cslb_allports\" environment variable is set, cslb intercepts\nnon-standard HTTP ports and maps them to numeric service names. For example http://example.net:8080\ngets mapped to _8080._tcp.example.net as the SRV name to resolve.\n\nWhile cslb runs passively by caching the results of previous Dial Requests, it can also run actively\nby periodically performing health checks on targets. This is useful as an administrator can control\nhealth check behaviour to move a target \"in and out of rotation\" without changing DNS entries and\nwaiting for TTLs to age out. Health checks are also likely to make the application a little more\nresponsive as they are less likely to make a dial attempt to a target that is not working.\n\nActive health checking is enabled by the presence of a TXT RR in the sub-domain \"_$port._cslb\" of\nthe target. E.g. if the SRV target is \"s1.example.net:80\" then cslb looks for the TXT RR at\n\"_80._cslb.s1.example.net\". If that TXT RR contains a URL then it becomes the health check URL. If\nno TXT RR exists or the contents do not form a valid URL then no active health check is performed\nfor that target.\n\nThe health check URL does not have to be related to the target in any particular way. It could be a\nURL to a central monitoring system which performs complicated application level tests and\nperformance monitoring. Or it could be a URL on the target system itself.\n\nA health check is considered successful when a GET of the URL returns a 200 status and the content\ncontains the uppercase text \"OK\" somewhere in the body (See the \"cslb_hc_ok\" environment variable\nfor how this can be modified). Unless both those conditions are met the target is considered\nunavailable.\n\nActive health checks cease once a target becomes idle for too long and health check Dial Requests\nare *not* get intercepted by cslb.\n\nIf your current service exists on a single server called \"s1.example.net\" and you want to spread the\nload across additional servers \"s2.example.net\" and \"s3.example.net\" and assuming you've added the\n\"cslb\" package to your application then the following DNS changes active cslb processing:\n\nCurrent DNS\n\nAdditional DNS\n\nA number of observations about this DNS setup:\n\nCslb maintains a cache of SRV lookups and the health status of targets. Cache entries automatically\nage out as a form of garbage collection. Removed cache entries stop any associated active health\nchecks. Unfortunately the cache ageing does not have access to the DNS TTLs associated with the SRV\nRRs so it makes a best-guess at reasonable time-to-live values.\n\nThe important point to note is that *all* values get periodically refreshed from the DNS. Nothing\npersists internally forever regardless of the level of activity. This means you can be sure that any\nchanges to your DNS will be noticed by cslb in due course.\n\nCslb optional runs a web server which presents internal statistics on its performance and\nactivity. This web service has *no* access controls so it's best to only run it on a loopback\naddress. Setting the environment variable \"cslb_listen\" to a listen address activates the status\nserver. E.g.:\n\nOn initialization the cslb package examines the \"cslb_options\" environment variable for single\nletter options which have the following meaning:\n\nAn example of how this might by used from a shell:\n\nMany internal configuration values can be over-ridden with environment variables as shown in this\ntable:\n\nAny values which are invalid or fall outside a reasonable range are ignored.\n\nCslb only knows about the results of network connection attempts made by DialContext and the results\nof any configured health checks. If a service is accepting network connections but not responding to\nHTTP requests - or responding negatively - the client experiences failures but cslb will be unaware\nof these failures. The result is that cslb will continue to direct future Dial Requests to that\nfaulty service in accordance with the SRV priorities. If your service is vulnerable to this\nscenario, active health checks are recommended. This could be something ss simple as an on-service\nhealth check which responds based on recent \"200 OK\" responses in the service log file.\nAlternatively an on-service monitor which closes the listen socket will also work.\n\nIn general, defining a failing service is a complicated matter that only the application truly\nunderstands. For this reason health checks are used as an intermediary which does understand\napplication level failures and converts them to simple language which cslb groks.\n\nWhile every service is different there are a few general guidelines which apply to most services\nwhen using cslb. First of all, run simple health checks if you can and configure them for use by\ncslb. Second, have each target configured with both ipv4 and ipv6 addresses. This affords two\npotentially independent network paths to the targets. Furthermore, net.Dialer attempts both ipv4 and\nipv6 connections simultaneously which maximizes responsiveness for the client.\n\nThird, consider a \"canary\" target as a low preference (highest numeric value SRV priority)\ntarget. If this \"canary\" target is accessed by cslb clients it tells you they are having trouble\nreaching their \"real\" targets. Being able to run a \"canary\" service is one of the side-benefits of\ncslb and SRVs.\n\nWhan analyzing the Status Web Page or watching the Run Time Control output, observers need to be\naware of caching by the http (and possibly other) packages. For example not every call to http.Get()\nresults in a Dial Request as httpClient tries to re-use connections.\n\nIn a similar vein if you change a DNS entry and don't believe cslb has noticed this change within an\nappropriate TTL amount of time, be aware that on some platforms the intervening recursive resolvers\nadjust TTLs as they see fit. For example some home-gamer routers are known to increase short TTLs to\nvalues they believe to be a more \"appropriate\" in an attempt to reduce their cache churn.\n\nPerhaps the biggest caveat of all is that cslb relies on being enabled for all http.Transports in\nuse by your application. If you are importing a package (either directly or indirectly) which\nconstructs its own http.Transports then you'll need to modify that package to call cslb.Enable()\notherwise those http requests will not be intercepted. Of course if the package is making requests\nincidental to the core functionality of your application then maybe it doesn't matter and you can\nleave them be. Something to be aware of.\n\n-----","license":"https://spdx.org/licenses/BSD-2-Clause","codeRepository":"https://github.com/rudderlabs/cslb","issueTracker":"https://github.com/rudderlabs/cslb/issues","url":"https://github.com/rudderlabs/cslb","programmingLanguage":{"@type":"ComputerLanguage","name":"Go"},"dateModified":"2026-02-03","datePublished":"2026-02-03","softwareHelp":{"@type":"WebSite","url":"https://pkg.go.dev/github.com/rudderlabs/cslb#section-documentation"},"applicationCategory":"go","runtimePlatform":"go","developmentStatus":"active","sameAs":["https://pkg.go.dev/github.com/rudderlabs/cslb"]}