Sticky Sessions Load-Balancer Algorithm #11930
Replies: 5 comments 10 replies
-
Consistent hashing is an ideal choice if there is no fixed user provided input. By taking a techincal property we can ensure consistency. However in this case I think basing it on the least-connections handler makes more sense. The essence here is: Consistent-hashing prefers load-distribution over connection stability. In this case the requirement is to prefer connection stability over load-distribution. Since every connection is fixed over its lifetime to a specific backend (no matter the load), and the information is carried in the request (by means of a cookie). That is easily solved. The problem however is that over time the load gets skewed towards the longest running nodes. If we use the consistent-hashing balancer as the base, then any new client would be randomly distributed over all nodes (including the long-running heavily loaded ones). By using the least-connections algorithm, we can ensure proper load distribution, since the newer empty nodes will get all the new connections until they are at the same capacity. Depending on the complexity of the implementation, this might even be implemented as a feature of the least-connections algorithm. Note: one thing not explicitly called out (only seen in the example) is that the cookie value should not leak any backend info, like hostnames, ports, etc. That value MUST be opaque. |
Beta Was this translation helpful? Give feedback.
-
@scrudge I think you might be interested on this proposal. |
Beta Was this translation helpful? Give feedback.
-
This algorithm seems to require cookies and has no header-based equivalent to the "consistent-hashing" algorithm's |
Beta Was this translation helpful? Give feedback.
-
How will this mapping be consistant across proxies in dbless mode? |
Beta Was this translation helpful? Give feedback.
-
This proposal is really well written, thanks! |
Beta Was this translation helpful? Give feedback.
-
Context
Some applications require that the client hits the same backend service on every requecost. To achieve that, Kong offers the consistent-hashing load-balancing algorithm. This algorithm assures that, based on an input string selected by the Kong Operator, the same client will hit the same upstream target on every request, as long as the upstream target list is fix. Furthermore, Kong's consistent-hashing algorithm is loosely based on the Ketama algorithm, meaning that adding or removing targets will affect a minimum set of clients.
But for some users, a minimum set of clients is still too much. Those users want/need their clients to never face session drops. More than that, in some environments growing and shrinking the list of targets is a constant process, meaning that even if the load-balancing algorithm changes the least amount of client-target relations, the changes are so frequent that the relations are almost non-existent.
For those cases we need a new load-balancing algorithm, which will guarantee that after an specific client initiates a request with an specific upstream target, that relation will continue to exist as long as the upstream target is available, even if this behavior overcomes the configured upstream targets weights.
Proposed solution: Sticky Sessions Algorithm
The sticky sessions algorithm will allow us to achieve that behavior by sticking a client to an upstream target.
Description
When the first request from a client is received, no previous upstream target was used by this client. So a target must be chosen from the target list, as it happens with other existent algorithms. After selecting the upstream target and before issuing the request to the proxied server, an HTTP cookie must be set in the request header, containing a reference to the upstream target.
1st request - no cookie set
When the load-balancer is in
getPeer()
it must check forngx.var["cookie_" .. <cookie_name>]
. During the client's first request, this value isnil
. The upstream target must be selected using the same algorithm as theconsistent-hashing algorithmleast-connections algorithm (algorithm changed according to @Tieske input here).Next, a
Set-Cookie
header must be added:ngx.req.set_header("Set-Cookie", <cookie_name> .. "=" .. <target_reference>)
.Next client's requests
The next client's requests will include the sticky sessions cookie. When the
getPeer()
function runs, it will check for the cookie<cookie_name>
and use its value. If the referenced upstream target is available, it must be used. If it's not, the process of the 1st request must be done again, but instead of setting the headerSet-Cookie
, the contents of ``ngx.var["cookie_" .. <cookie_name>]` must be overwritten.Implementation details
Most of the code will be shared with the least-connections algorithm. The easiest way of doing that is inheriting the
lc
class and reusing the existent methods where it is possible.Upstream target reference
The sticky sessions cookie must not contain a clear direct reference to the upstream target, as the hostname or the IP. To avoid that, a translate table may be created:
And the cookie header will contain:
<cookie_name>=reference_1
.This translate table must be populated when adding and removing upstream targets, in the
afterHostUpdate()
function, using a consistent method among all workers and nodes. This will make sure any Kong node will contain the same references.When using this translate table, as the index is the cookie value, virtually no time will be added:
return translate[cookie_value]
.More configurations
Some configuration options that might be interesting but not required on the first version.
Keep existent sticky session or keep connectivity
For the cases where an upstream target is unavailable, we could give to the Kong Operator the option to choose between:
Beta Was this translation helpful? Give feedback.
All reactions