- 
                Notifications
    
You must be signed in to change notification settings  - Fork 25.6k
 
Export current node allocation stats as APM metrics #116585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Export current node allocation stats as APM metrics #116585
Conversation
226d443    to
    57c526a      
    Compare
  
    | public static final String CURRENT_NODE_UNDESIRED_SHARD_COUNT_METRIC_NAME = | ||
| "es.allocator.allocations.node_undesired_shard_count.current"; | ||
| public static final String CURRENT_NODE_FORECASTED_DISK_USAGE_METRIC_NAME = | ||
| "es.allocator.allocations.node_forecasted_disk_usage_bytes.current"; | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NodeAllocationStats gives these two more compared to the DESIRED_BALANCE_... metrics above. Not sure if they're needed, but I have exported all of them.
57c526a    to
    6c84cfe      
    Compare
  
    | 
           Pinging @elastic/es-distributed-coordination (Team:Distributed Coordination)  | 
    
        
          
                server/src/main/java/org/elasticsearch/cluster/routing/allocation/AllocationStatsService.java
          
            Show resolved
            Hide resolved
        
              
          
                ...in/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceReconciler.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
      | assert node != null; | ||
| nodeAllocationStats.put(node, entry.getValue()); | ||
| } | ||
| desiredBalanceMetrics.updateMetrics(allocationStats, desiredBalance.weightsPerNode(), nodeAllocationStats); | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think I am following.
New stats claim they represent the current state of the nodes and are populated from allocationStatsPerNodeRef that is set from nodeAllocationStats or the last argument here.
In its turn the last argument is effectively copied from stats entries that represent the desired state.
How are current stats different from desired stats?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you say stats represents desired state? To me it seems to be based on the current cluster state in org.elasticsearch.cluster.routing.allocation.AllocationStatsService.NodeStatsProvider#stats? Either I'm missing something or the naming is confusing! :))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh, maybe I am confused. We pass the desiredBalance to the call above but not the current cluster state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is just to manage the dependencies to be able to reuse AllocationStatsService. There, we used to pass the entire Allocator only to get the desired balance out of it, which seems to be used for calculating undesired shard count. (git tells me it's your code actually!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... so if you find a different approach to reuse that code more useful/readable, or see some comments missing or renames, please let me know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. That component was originally created to expose stats via endpoint and was not originally used in reconciler.
The first one (minor) is that it accesses the cluster state via clusterService.state() and not from allocation. They should be the same as this is happening during cluster state update computation, but that is not immediately obvious.
The second one (more substantial) is the set of metric it provides. It does not produce the same metrics as we have for computed balance. This might introduce confusing while comparing them and opens a possibility of publishing different metrics under similar names. Also since this service is used in public API, we will be limited in how we can change it. This might become relevant as we discuss the imbalance measurements and experiment with different balancing functions.
Based on this I suggest not to rely on it and instead implement an apm specific service that is used in both computer and reconciler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first one (minor) is that it accesses the cluster state via clusterService.state()
I can change that and make it accept also a state.
It does not produce the same metrics as we have for computed balance.
Not sure I follow. The three node-level metrics from the desired balance that we currently have are shard_count, write_load and disk_usage. We have in this PR those three calculated based on current cluster state. There are two more here, that as I mentioned I chose to export, but we can drop them.
Also since this service is used in public API, we will be limited in how we can change it.
That code is now refactored into its own class. For now we're reusing it because it provides what we need. If we need to later, we can duplicate it, extend it or whatever is appropriate based on what we need.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We discussed this thread offline,
Re
It does not produce the same metrics as we have for computed balance.
It misses weights, but we discussed that they are not necessary for now.
We also discussed the possibility of weight computations diverging. This aspect could be addressed in future when this problem arises.
| public static final String DESIRED_BALANCE_NODE_DISK_USAGE_METRIC_NAME = | ||
| "es.allocator.desired_balance.allocations.node_disk_usage_bytes.current"; | ||
| 
               | 
          ||
| public static final String CURRENT_NODE_SHARD_COUNT_METRIC_NAME = "es.allocator.allocations.node.shard_count.current"; | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
originally, I had these as es.allocator.allocations.node_ but APM complained that it is too long so I changed to this.
        
          
                .../main/java/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceMetrics.java
          
            Show resolved
            Hide resolved
        
      | currentDiskUsage | ||
| ) | ||
| ); | ||
| public static class NodeStatsProvider implements StatsProvider { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find it a bit confusing with the inner class for reuse, could we just add an overload to AllocationStatsService that took a desired balance to use in the computation, and everyone just gets given a reference to a single instance of it?
e.g. add
public Map<String, NodeAllocationStats> stats(DesiredBalance desiredBalance) {
   // ...
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh there would be a circular dependency between allocator and stats service then.
I reckon it'd be clearer if the thing that calculated the stats just became a separate shared piece of infrastructure that took a DesiredBalance from somewhere and returned the stats. The inner class and the interface makes it a bit tricky to read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the dependencies here are not straight-forward and largely the reason I came up with this. But how is your suggestion different than what's in the PR? I can move out the inner class and get rid of the interface. Other than that, it is the same, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed a5381e1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fine to me but I think we should just refactor to tidy up the reuse of AllocationStatsService
        
          
                ...va/org/elasticsearch/cluster/routing/allocation/allocator/DesiredBalanceReconcilerTests.java
              
                Outdated
          
            Show resolved
            Hide resolved
        
      There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's easier to read. You could probably share an instance of NodeAllocationStatsProvider, which might make the shared dependency a bit clearer, but if that's tricky with the wiring you could also not.
LGTM assuming @idegtiarenko is OK with the current vs desired logic
At the end of each reconciliation round, also export the current allocation stats for each node. This is intended to show the gradual progress (or divergence!) towards the desired values exported in elastic#115854, and relies on the existing `AllocationStatsService`. Relates ES-9873
At the end of each reconciliation round, also export the current allocation stats for each node. This is intended to show the gradual progress (or divergence!) towards the desired values exported in #115854, and relies on the existing `AllocationStatsService`. Relates ES-9873
At the end of each reconciliation round, also export the current allocation stats for each node. This is intended to show the gradual progress (or divergence!) towards the desired values exported in elastic#115854, and relies on the existing `AllocationStatsService`. Relates ES-9873
At the end of each reconciliation round, also export the current allocation stats for each node. This is intended to show the gradual progress (or divergence!) towards the desired values exported in elastic#115854, and relies on the existing `AllocationStatsService`. Relates ES-9873
At the end of each reconciliation round, also export the current allocation stats for each node. This is intended to show the gradual progress (or divergence!) towards the desired values exported in #115854, and relies on the existing
AllocationStatsService.Relates ES-9873