hashicorp / hashicorp/consul

Investigate: Gossip queue pruning is ineffective at scale

Open
#9,927 0 comments 0 reactions 0 assignees View on GitHub
theme/reliability type/umbrella-☂️
Dominant language
Go
Stars
30.1k
Forks
4.6k
Avg merge
1d 18h
Merged PRs (30d)
39

Description

Working with some users with large clusters, we've observed that although Consul sets a maximum intent queue depth for Serf-level intent messages (node "join" and "leave"), it is not effectively enforced at some scale.

This is technically a Serf issue but the overall effect is most import to Consul users so we are tracking the higher level issue here. There are also ramifications for memberlist too as that is where the actual queue is implemented.

Consul sets Serf's [Max.min queue depth](https://github.com/hashicorp/serf/blob/7faa1b06262f70780c3c35ac25a4c96d754f06f3/serf/config.go#L132-L141) such that the queue will be limited to the smaller of 4096 or 2*`SizeOfCluster`. So for a 20k node cluster, the Intent queues should never exceed 40k messages to prevent unbounded growth.

Problems:

1. In real-world scenarios with ~20k nodes and high levels of churn, we see intent queues growing effectively unboundedly - up to 160k messages.
* We enforce this in Serf by periodically (30s default, not configurable) calling `Prune` on the queue which pulls off the oldest (lowest priority) messages until it's back to the limit. This prune operation contends for the queue's lock with both enqueue and dequeue operations which are pretty frequent. We assume that it's just not able to clean up fast enough.
* We experimented in one case with tuning the period down to attempting to prune every 1 second. While this did seem to improve things on one node, other nodes (e.g. servers) who tend to have higher gossip requirements since all new nodes typically announce themselves to servers first still could't keep the queue size in check.
* There may be other reasons this appeared not to be effective, including that the depth metric is also being sampled at the same rate as the pruning which could mean we always sample exactly at the worst point before prune is called. We did not observe a "sawtooth" though only a steady climb which seemed to suggest prune just wasn't keeping up with enqueues at all.
2. The Serf-level intent queue is only one of the queues in the system. Memberlist itself also has a broadcast queue which has no limit at all. We should probably find a way to bound the size of that queue too otherwise arbitrarily stale messages in memberlist will still take priority over newer messages in Serf.

Possible next steps:

* Attempt to validate the contention hypothesis in a benchmark where we subject `memberlist.TransmistLimitedQueue` to an extreme rate of enqueue/dequeue with a high restransmit number say 20. Call `Prune` every 30 seconds and see if it is effective.
* Consider alternative enforcement, for example can we check the limit every time we enqueue a new message and if we went over, pop one off while still under lock? This might slow down enqueue but that seems reasonable quantifying how much with a microbenchmark might make sense but I expect it to be a good tradeoff for properly bounding resource usage.
* Consider adding a limit to memberlist's broadcast queue too. This may need some experimentation as it changes gossip behaviour at scale, but at least in theory it should be OK for the same reason it's OK in Serf - dropping messages that have already been transmitted a few times probably doesn't impact convergence significantly and if it does that's a reasonable tradeoff for bounded resource usage. Anti-entropy should ensure eventual convergence.

Contributor guide

Open the contributing guide

Research direction

Start with memberlist.TransmistLimitedQueue, its Prune operation, and the Serf intent-queue limit described in the issue. Build the proposed extreme enqueue/dequeue benchmark with retransmit rate 20, then investigate contention and the unbounded memberlist broadcast queue. Done means the cause is validated and queue growth is bounded under the reported high-churn workload, with supporting benchmark coverage.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
distributed-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.