Layer 2 modes (ARP and NDP) requires a single owner machine for each service IP. Currently we do this by running master election and having the winner own all IPs.
This is a little sub-optimal in several ways:
- Leader election in k8s is kinda expensive in terms of control plane qps
- Electing a machine regardless of what it's running means we are forced to use externalTrafficPolicy=Cluster, so we lose source IP information
- We cannot shard traffic load by IP (arguably this is a feature, but it's not a particularly compelling one)
So, here's a proposal: let's get rid of the leader election, and replace it with a deterministic node selection algorithm. The controller logic remains unchanged (allocates an IP). On the speaker, we would do the following:
- Based on the Endpoints object for the service, construct a list of nodes that have a pod for that service. In python pseudocode, that list would be
[x.node for x in endpoints]
- Hash the node names and service name together, to produce a service-dependent (but deterministic) set of hashes for the nodes.
- Do a weighted alphabetical sort of the hashes, such that the first element of the list is the alphabetically first hash with the largest number of local pods
- Pick that first element as the "owner" of this service, and make it announce that IP.
This algorithm results in a couple of properties:
- Each IP can be owned by different nodes. In fact, due to the service-dependent hashing, it's likely that services will uniformly distribute throughout the cluster.
- Services will prefer to attach to nodes that have multiple serving pods for the service, to better distribute load.
- There is no explicit locking, similar to consistent hashing in Maglev each speaker simply arrives independently at the same conclusions.
- We can once again allow
externalTrafficPolicy: Local for layer2 mode services, which removes one of the major downsides of using ARP/NDP today (no client IP visibility).
- One downside is that split-brain is more likely, because if a node gets cut off from the control plane it may not realize that conditions around it have changed, and so we might end up with multiple machines thinking that they own an IP. We can either accept this as a tradeoff (ARP and NDP behave somewhat gracefully in the presence of a split brain), or keep a concept similar to leader election that just pings a lease in the cluster, and speakers who don't see that lease increasing stop all advertisement on the assumption that they've lose communications with the control plane. This however has the significant downside that the cluster will stop all announcements if the control plane goes down, rather than gracefully keep announcing the last known state. I think I would prefer just accepting the split brain in that case.
@miekg @mdlayher Thoughts on this proposal?
Layer 2 modes (ARP and NDP) requires a single owner machine for each service IP. Currently we do this by running master election and having the winner own all IPs.
This is a little sub-optimal in several ways:
So, here's a proposal: let's get rid of the leader election, and replace it with a deterministic node selection algorithm. The controller logic remains unchanged (allocates an IP). On the speaker, we would do the following:
[x.node for x in endpoints]This algorithm results in a couple of properties:
externalTrafficPolicy: Localfor layer2 mode services, which removes one of the major downsides of using ARP/NDP today (no client IP visibility).@miekg @mdlayher Thoughts on this proposal?