Skip to content
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

Improve performance of Cat Nodes API #99744

Closed
NEUpanning opened this issue Sep 21, 2023 · 15 comments
Closed

Improve performance of Cat Nodes API #99744

NEUpanning opened this issue Sep 21, 2023 · 15 comments
Labels
:Data Management/Stats Statistics tracking and retrieval APIs >enhancement Team:Data Management Meta label for data/management team

Comments

@NEUpanning
Copy link
Contributor

NEUpanning commented Sep 21, 2023

Description

We found that executing the Cat Nodes API (query parameters do not matter) on the coordinate node of a large cluster can require a huge amount of CPU.This could have a significant impact on cluster stability.I reproduced this problem in the cluster with 200 data nodes and 140k shards.
When I used the 'top' command to query, the result showed that CPU usage fluctuated between 726% and 1173% for 3 seconds.
The most CPU usage comes from ShardStats.<init> and DiscoveryNode.writeTo. ShardStats.<init> is called when coordinate node deserializes response that is responded by other nodes. DiscoveryNode.writeTo is called when coordinate node serializes request that will be sent to other nodes.Here is Flame Graph
Screen Shot 2023-09-21 at 4 42 53 PM

Several superficial ideas try to solve this issue:

  1. Coordinate node could construct NodesStatsRequest#indices based on query parameters to filter indices stats rather than calling NodesStatsRequest.indices(true) that contains all indices stats.For instance if users call _cat/nodes?h=m,coordinate node should not fetch indices stats from other nodes.This would avoid a lot of unnecessary deserialization of the response content from ShardStats.<init>.
  2. Set NodeInfoRequest#concreteNodes to null after using NodeInfoRequest#concreteNodes to build iterator that used to send requests.This would avoid unnecessary serialization of the request content from DiscoveryNode.writeTo.
@NEUpanning NEUpanning added >enhancement needs:triage Requires assignment of a team area label labels Sep 21, 2023
@arteam arteam added the :Distributed Indexing/CRUD A catch all label for issues around indexing, updating and getting a doc by id. Not search. label Sep 21, 2023
@elasticsearchmachine elasticsearchmachine added the Team:Distributed (Obsolete) Meta label for distributed team (obsolete). Replaced by Distributed Indexing/Coordination. label Sep 21, 2023
@elasticsearchmachine
Copy link
Collaborator

Pinging @elastic/es-distributed (Team:Distributed)

@elasticsearchmachine elasticsearchmachine removed the needs:triage Requires assignment of a team area label label Sep 21, 2023
@DaveCTurner DaveCTurner added :Data Management/Stats Statistics tracking and retrieval APIs and removed :Distributed Indexing/CRUD A catch all label for issues around indexing, updating and getting a doc by id. Not search. Team:Distributed (Obsolete) Meta label for distributed team (obsolete). Replaced by Distributed Indexing/Coordination. labels Sep 22, 2023
@elasticsearchmachine elasticsearchmachine added the Team:Data Management Meta label for data/management team label Sep 22, 2023
@elasticsearchmachine
Copy link
Collaborator

Pinging @elastic/es-data-management (Team:Data Management)

@DaveCTurner
Copy link
Contributor

The _cat APIs are intended to be convenient wrappers around the more flexible JSON APIs, intended for occasional use by humans. I'm a little impressed that it only takes 3s to respond in such a huge cluster. If you need more control over the execution, use the JSON APIs directly.

For instance if users call _cat/nodes?h=m, coordinate node should not fetch indices stats from other nodes. This would avoid a lot of unnecessary deserialization of the response content from ShardStats..

This seems like a nice idea but it would be fragile, we'd need to keep track of the columns that included stats to know whether or not the stats request was needed, and make sure to keep that list up to date as the columns change over time. Also the _cat APIs generally don't have a way to get a list of the requested columns when processing the request. So this idea seems possible but a little tricky and requiring quite some effort.

Set NodeInfoRequest#concreteNodes to null

IMO this is a valid point, although I would not want to solve it as described. Today every node-level TransportNodesInfoAction.NodeInfoRequest carries the entire top-level NodesInfoRequest, but it only needs to carry the metrics. We should trim these things down for sure.

@DaveCTurner
Copy link
Contributor

Just to add: another idea would be to indicate in the stats request that we don't care about stats for individual shards, we are only going to use a summary. That'd save a bunch of effort and network traffic with the nodes stats and indices stats APIs too.

@NEUpanning
Copy link
Contributor Author

@DaveCTurner Thanks for the reply.

In the most scenarios we will use the JSON APIs instead of _cat/nodes.

If you need more control over the execution, use the JSON APIs directly.

This is a great idea that is more elegant than i think and avoids unnecessary serialization of the request content from DiscoveryNode.writeTo.

Today every node-level TransportNodesInfoAction.NodeInfoRequest carries the entire top-level NodesInfoRequest, but it only needs to carry the metrics. We should trim these things down for sure.

This is also a great idea that would trim useless shard stats from responses and avoid unnecessary deserialization of ShardStats.<init>.

another idea would be to indicate in the stats request that we don't care about stats for individual shards, we are only going to use a summary.

I think implementaion of these ideas could solve this issue.

@NEUpanning
Copy link
Contributor Author

I don't quite understand why indices stats APIs can be optimized.I see coordinate node needs shard stats to build indices stats.

That'd save a bunch of effort and network traffic with the nodes stats and indices stats APIs too.

@NEUpanning
Copy link
Contributor Author

I would like to do it, do you think I could give it a try?

I think implementaion of these ideas could solve this issue.

@DaveCTurner
Copy link
Contributor

I see coordinate node needs shard stats to build indices stats.

I think we can reduce the work here if the user specifies ?level=cluster, but I'm not sure it's worth the effort.

I would like to do it, do you think I could give it a try?

Sure, go for it. I recommend you don't do it all in one PR tho, try and separate the independent changes out to make them easier to review.

@NEUpanning
Copy link
Contributor Author

@DaveCTurner I've opened a pull request(#99938) for this idea . Could you please have a look when you have some time? Thanks

Today every node-level TransportNodesInfoAction.NodeInfoRequest carries the entire top-level NodesInfoRequest, but it only needs to carry the metrics.

DaveCTurner pushed a commit that referenced this issue Oct 2, 2023
…equest (#99938)

There's no need to include the whole top-level `NodesInfoRequest` in the
requests for info from individual nodes, and this can add substantial
overhead if there are lots of nodes in the cluster. With this commit we
drop the wrapper in favour of just the parts of the top-level request
needed for the node-level processing.

Relates #99744
jakelandis pushed a commit to jakelandis/elasticsearch that referenced this issue Oct 2, 2023
…equest (elastic#99938)

There's no need to include the whole top-level `NodesInfoRequest` in the
requests for info from individual nodes, and this can add substantial
overhead if there are lots of nodes in the cluster. With this commit we
drop the wrapper in favour of just the parts of the top-level request
needed for the node-level processing.

Relates elastic#99744
@NEUpanning
Copy link
Contributor Author

another idea would be to indicate in the stats request that we don't care about stats for individual shards, we are only going to use a summary.

I've opened a pull request for this idea in #100466.

@DaveCTurner
Copy link
Contributor

Thanks @NEUpanning, I'll take a look next week. You might also be interested in #90631 which is kind of the same thing but for the GET _cluster/health API.

@NEUpanning
Copy link
Contributor Author

I would like to resolve this issue. After that PR is merged, I will try it using the similar approach.

elasticsearchmachine pushed a commit that referenced this issue Oct 13, 2023
@NEUpanning
Copy link
Contributor Author

NEUpanning commented Oct 13, 2023

After we have implemented these ideas mentioned above, the CPU usage and cost time of fetching nodes stats (without shards-level stats) reduce to 1/1000th of their original levels in the cluster with 200 data nodes and 140k shards. So this issue is closed as completed.

@DaveCTurner
Copy link
Contributor

Nice work @NEUpanning, thanks for the report, the fixes, and for confirming that the problems are fixed.

@NEUpanning
Copy link
Contributor Author

Thanks again David. Thanks for your help and patience in code review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Data Management/Stats Statistics tracking and retrieval APIs >enhancement Team:Data Management Meta label for data/management team
Projects
None yet
Development

No branches or pull requests

4 participants