Improve Gossip Queue Observability
- Dominant language
- Go
- Stars
- 30.1k
- Forks
- 4.6k
- Avg merge
- 1d 18h
- Merged PRs (30d)
- 39
Description
Large consul clusters under heavy node churn can experience "gossip storms" where lots of gossip messages get exchanged in a short time. There are several layers of queuing involved and the queues are somewhat complicated in the way the both assign priority and retain messages at different priority levels until a certain number of broadcasts have been sent.
Currently Consul only provides metrics on one of the several queues involved, and not enough to understand if long queue backlogs represent serious problems or are benign.
The actual changes involved require updates to both hashicorp/memberlist which has one of the layers of queuing, and hashicorp/serf which has the others, however we're creating this issue here so Consul users can see and track it.
---
### Current State:
1. `consul.serf.queue.Intent` provides a sample/summary of the length of the queue every 30s by default. Monitoring the max of this summary lets you know how many queued Serf "join" or "leave" intent messages exist. Other serf-level queues also emit stats but are generally not relevant to significant churn events since those relate to nodes coming and going. **Significantly, this queue is only serviced (i.e. drained) by memberlist _after_ memberlist's own internal queue of alive/dead/suspect messages had nothing to fill a packet. During large churn events, there are also many thousands of messages at the memberlist layer which take up the limited packet space available and so cause serf join/leave messages to backup.
2. `consul.serf.msgs` is s summary/sample of all Serf-level message sizes being sent. The count gives a "drain rate" for the intent queue while the average gives an average join/leave message size which can be useful for estimating how many messages might fit in the 1400 bytes available in a UDP packet (we don't allow for jumbo frames currently). There is no way to see the memberlist-level message rates or sizes though so it's impossible to estimate drain time.
3. Since the queues are not simple FIFOs the length is not sufficient to understand the draining behaviour:
* Each message broadcast (i.e. pushed into the queue) will be retransmitted R times where R is proportional to the base-10 logarithm of the cluster size multiplied by [gossip_lan.retransmit_mult](https://www.consul.io/docs/agent/options#retransmit_mult). See https://play.golang.org/p/zZ9a5M_1o7i .
* New messages are queued at priority level "0" and these are delivered with highest priority
* After delivery, the message is re-inserted at priority level n+1 until n+1 is greater than the number of required retransmits.
* So the majority of messages in a queue in a large cluster where number or retransmits is high (say 20) will be "low priority" messages that have already been transmitted some number of times and are waiting to finish.
* It also means that if there are 1000 messages in the queue that could mean anything from 1000 to 1000 * R messages actually need to be delivered before the queue is empty making it very hard to understand how long it might take to drain and whether the large backlog represents an unhealthy state or not.
4. Consul's telemetry page not only misses some of the metrics above, but offers no guidance on how to understand gossip health in these cases.
### Desired State:
1. To have sufficient metrics that cover _both_ the memberlist level broadcast queue and the Serf level ones so a complete picture of the work being done by gossip can be understood.
2. For both levels of queue,
* breakdown metrics by number of retransmits/priority so that operators can reason about what portion of a backlog is "old" and what portion is actually churning.
* provide a meaningful overview of "work left to do" e.g. something like number of message at each level * number of retransmits left for those messages.
3. Document the new metrics on the telemetry page with details on how to understand them
There are other possible behaviour changes we could make around this that might help resolve things, e.g. have memberlist yield more space to Serf messages when both queues have messages to broadcast. This would require more significant changes and thorough testing so will be considered separately.
Contributor guide
Research direction
Start by tracing the existing consul.serf.queue.Intent and consul.serf.msgs metrics through the Serf and memberlist queue layers. Review how both projects represent priority and retransmits, then define metrics covering queue levels and remaining work. Done means both queue layers expose the needed observability and the Consul telemetry page explains how to interpret it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- distributed-systems, observability-sre
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100