feat: add blocked nodes metric to scrape-time collector - #431
feat: add blocked nodes metric to scrape-time collector#431rawadhossain wants to merge 3 commits into
Conversation
Signed-off-by: Rawad Hossain <rawad.hossain00@gmail.com>
✅ Deploy Preview for node-readiness-controller canceled.
|
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: rawadhossain The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Hi @rawadhossain. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Tip We noticed you've done this a few times! Consider joining the org to skip this step and gain Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
|
/ok-to-test |
AvineshTripathi
left a comment
There was a problem hiding this comment.
did my initial round of reviewing, please have a look at the comments!
|
|
||
| // Collect implements prometheus.Collector. | ||
| func (c *ReadinessCollector) Collect(ch chan<- prometheus.Metric) { | ||
| ctx, cancel := context.WithTimeout(context.Background(), collectTimeout) |
There was a problem hiding this comment.
5sec to do ListNodes, ListRuleNodeStates and ListBlockedNodes can feel little less. wdyt?
There was a problem hiding this comment.
I wasn't fully sure about this. Kept it at 5s since it's below Prometheus's default scrape timeout (10s), so we can fail and log before the scrape times out. I also tested it with larger node counts and it seemed fine. Do you think it'd be better to increase?
e72d1ac to
367985d
Compare
| defer cancel() | ||
|
|
||
| counts, err := c.lister.ListRuleNodeStates(ctx) | ||
| nodes, err := c.lister.ListNodes(ctx) |
There was a problem hiding this comment.
I have a high level suggestion. Why does this collector list nodes twice? If the node list results have different snapshots (in the single scrape) between the two list time. This could result confusing results
There was a problem hiding this comment.
Can your forEachRuleNode be a single list computation for all needs?
There was a problem hiding this comment.
yeah missed on that one, actually it wasn't the node list, it was rule list being fetched twice, which had the same risk you described. Fixed that now so the rules are fetched once per scrape and the same snapshot is passed to both computations.
and for forEachRuleNode, I did try combining the two forEachRuleNode passes into a single computation and benchmarked it with different node/rule counts, improvement was pretty small, but it made the deletion case a bit harder to handle correctly. Like a deleting rule still needs to count for held/released nodes but not for blocked nodes. So kept the two computations separate for now to keep logic simpler.
|
Looked through the collector changes and noticed two small items in
|
|
AvineshTripathi
left a comment
There was a problem hiding this comment.
I tried this locally, didn't see any issue there for now. Left some minor comments. PHAL
| var errors []string | ||
| for _, node := range nodeList.Items { | ||
| if !r.ruleAppliesTo(ctx, rule, &node) { | ||
| applies, held := r.ruleAppliesToWithTaint(ctx, rule, &node) |
There was a problem hiding this comment.
Internally this parses nodeselector for every node which can be avoided.
There was a problem hiding this comment.
right, didn't notice that. Moved the parsing outside the loop so it only happens once per rule now, and removed ruleAppliesToWithTaint since it's not needed anymore
| for rule, rc := range counts { | ||
| ch <- prometheus.MustNewConstMetric(ruleNodesDesc, prometheus.GaugeValue, rc.Held, rule, string(RuleNodeStateHeld)) | ||
| ch <- prometheus.MustNewConstMetric(ruleNodesDesc, prometheus.GaugeValue, rc.Released, rule, string(RuleNodeStateReleased)) | ||
| counts, err := c.lister.ListRuleNodeStates(ctx, nodes, rules) |
There was a problem hiding this comment.
I think we should rename counts to nodeStatesByRule or something intuitive
There was a problem hiding this comment.
yes renamed to nodeStatesByRule
| nodeList := &corev1.NodeList{} | ||
| if err := r.List(ctx, nodeList); err != nil { | ||
| // ListRules returns the current list of NodeReadinessRules. | ||
| func (r *RuleReadinessController) ListRules(ctx context.Context) ([]*readinessv1alpha1.NodeReadinessRule, error) { |
There was a problem hiding this comment.
why ListRule is returning []*readinessv1alpha1.NodeReadinessRule while ListNode returns []corev1.NodeList. One is a pointer while other is a copy
There was a problem hiding this comment.
yeah, actually followed the existing pattern. Rules are used as pointers everywhere else in this file, so ListRules follows the same pattern. Whereas nodes are only read here and handled as values, so I left this as is to stay consistent with the existing usage.
844bd82 to
2745dc4
Compare
Description
Adds
node_readiness_blocked_nodes{rule, condition}for tracking the number of currently-held nodes blocked by each unsatisfied condition for eachNodeReadinessRule. Ref. New Scrape-Time Collector SurfaceThe metric is collected directly from the controller runtime cache on each Prometheus scrape, sharing the same Node snapshot with
node_readiness_rule_nodes.Changes
node_readiness_blocked_nodesmetric withruleandconditionlabels.ListBlockedNodesto calculate blocked nodes from the live Node state.DefaultStatuswhen a condition is missing from the Node, same as the controller.ListNodeswithnode_readiness_rule_nodesduring each scrape.Related to #397
Type of Change
/kind feature
Testing
make test,make lint,go test ./... -raceall passDefaultStatusbehavior.Checklist
make testpassesmake lintpasses