-
Notifications
You must be signed in to change notification settings - Fork 24.9k
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
Introduce SNAPSHOT_META Threadpool for Fetching Repository Metadata #73172
Introduce SNAPSHOT_META Threadpool for Fetching Repository Metadata #73172
Conversation
Adds new snapshot meta pool that is used to speed up the get snapshots API by making `SnapshotInfo` load in parallel. Also use this pool to load `RepositoryData`. A follow-up to this would expand the use of this pool to the snapshot status API and make it run in parallel as well.
Pinging @elastic/es-distributed (Team:Distributed) |
@@ -189,6 +191,8 @@ public ThreadPool(final Settings settings, final ExecutorBuilder<?>... customBui | |||
builders.put(Names.REFRESH, new ScalingExecutorBuilder(Names.REFRESH, 1, halfProcMaxAt10, TimeValue.timeValueMinutes(5))); | |||
builders.put(Names.WARMER, new ScalingExecutorBuilder(Names.WARMER, 1, halfProcMaxAt5, TimeValue.timeValueMinutes(5))); | |||
builders.put(Names.SNAPSHOT, new ScalingExecutorBuilder(Names.SNAPSHOT, 1, halfProcMaxAt5, TimeValue.timeValueMinutes(5))); | |||
builders.put(Names.SNAPSHOT_META, new ScalingExecutorBuilder(Names.SNAPSHOT_META, 1, 2 * allocatedProcessors, |
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 only used 5 min here because we're using it everywhere else for now. It seems like this should really be less.
Twice the allocated processors seemed like a reasonable guess here since this is exclusively going to run on master nodes pretty much that don't have endless cores available. This might be a little low though in some cases. We could also go for an absolute value here I guess but in the end these threads will also be doing some heavy deserialisation work here and there so going way beyond the CPU count is questionable. OTOH depending on the repo implementation an upper bound may make sense too due to e.g. S3 SDK connection limits.
=> Happy to hear opinions here or discuss this :)
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 have the feeling that having a fixed default upper bound would make it easier to reason about the snapshots related thread pools. Something like halfProcMaxAt5
maybe, so that we don't exceed the number of CPUs ad we don't either exceed by too much the default connection pool size.
// put snapshot info downloads into a task queue instead of pushing them all into the queue to not completely monopolize the | ||
// snapshot meta pool for a single request | ||
final int workers = Math.min(threadPool.info(ThreadPool.Names.SNAPSHOT_META).getMax(), snapshotIdsToIterate.size()); | ||
final Executor executor = threadPool.executor(ThreadPool.Names.SNAPSHOT_META); |
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.
Used the same logic here that we use for file uploads and I believe also pre-warming where we do this kind of fake work-stealing-pool. This could be dried up in a follow-up since we have that same logic in a few places now.
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.
LGTM, I only left minor comments.
} | ||
|
||
private void getOneSnapshotInfo(boolean ignoreUnavailable, | ||
Repository repository, |
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 wonder if we should retrieve the Repository
from the the RepositoriesService
for each SnapshotInfo
to load, so that if the repository is gone the RepositoryMissing is easier to propagate through listeners (and grouped listener which clears the queue etc). Otherwise a RepositoryMissing might be thrown I think and will be caught at a higher level but we keep fetching snapshot info here.
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 could I guess but it's not going to be a big cleanup/win since this situation is somewhat broken to begin with.
The behavior of the repository after close isn't well defined currently. Depending on the repo implementation the requests can either start failing or in case of FsRepository
will just keep going actually because close is a noop there.
Might be worth just fixing that in general at some point?
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 agree but I still think it is worth not mixing thrown exceptions and listeners here.
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.
oh 🤦 now I get your comment. Sorry, I completely misread it for no good reason :( => Fix coming right up.
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 fb55daa to address this (and random formatting noise) now :) I went with this instead of looking up the repo in the loop, because the latter would be caught and suppressed by ignoreUnvailable
which I found weird (albeit practically irrelevant).
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.
fb55daa looks good, thanks! And sorry if I wasn't clear at first :)
} | ||
} | ||
|
||
private void getOneSnapshotInfo(boolean ignoreUnavailable, |
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.
nit: can we add a bit of Javadoc?
@@ -189,6 +191,8 @@ public ThreadPool(final Settings settings, final ExecutorBuilder<?>... customBui | |||
builders.put(Names.REFRESH, new ScalingExecutorBuilder(Names.REFRESH, 1, halfProcMaxAt10, TimeValue.timeValueMinutes(5))); | |||
builders.put(Names.WARMER, new ScalingExecutorBuilder(Names.WARMER, 1, halfProcMaxAt5, TimeValue.timeValueMinutes(5))); | |||
builders.put(Names.SNAPSHOT, new ScalingExecutorBuilder(Names.SNAPSHOT, 1, halfProcMaxAt5, TimeValue.timeValueMinutes(5))); | |||
builders.put(Names.SNAPSHOT_META, new ScalingExecutorBuilder(Names.SNAPSHOT_META, 1, 2 * allocatedProcessors, |
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 have the feeling that having a fixed default upper bound would make it easier to reason about the snapshots related thread pools. Something like halfProcMaxAt5
maybe, so that we don't exceed the number of CPUs ad we don't either exceed by too much the default connection pool size.
@@ -96,6 +96,7 @@ private int expectedSize(final String threadPoolName, final int numberOfProcesso | |||
sizes.put(ThreadPool.Names.REFRESH, ThreadPool::halfAllocatedProcessorsMaxTen); | |||
sizes.put(ThreadPool.Names.WARMER, ThreadPool::halfAllocatedProcessorsMaxFive); | |||
sizes.put(ThreadPool.Names.SNAPSHOT, ThreadPool::halfAllocatedProcessorsMaxFive); | |||
sizes.put(ThreadPool.Names.SNAPSHOT_META, ThreadPool::twiceAllocatedProcessors); |
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.
Can we document this thread pool?
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.
One minor question inline.
Should we also move TransportSnapshotsStatusAction
and/or TransportMountSearchableSnapshotAction
and/or restore operations from GENERIC
to SNAPSHOT_META
too?
BlockingQueue<SnapshotId> queue, | ||
Collection<SnapshotInfo> snapshotInfos, | ||
CancellableTask task, | ||
Executor executor, |
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.
This is always the same executor, just wondering why not get it from the threadPool
each time rather than passing it in.
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.
Right, not sure why I did it this way initially, fixed in 24cf149
The snapshot status I was going to move to the pool as well and parallelize on it in a follow-up. I don't have a strong opinion either way when it comes to the mount action. Though maybe it would be nice to get it off the generic pool as well in case of massively concurrent calls actually. I'd also do that in a separate PR though as I just found an edge case bug in its threading anyway (PR incoming today, maybe just discuss it there?). Update: see #73196 for the mentioned bug |
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.
LGTM
Thanks David and Tanguy! |
Small and obvious oversight from elastic#73172
Small and obvious oversight from #73172
) Backport of the recently introduced snapshot pagination and scalability improvements listed below. Merged as a single backport because the `7.x` and master snapshot status API logic had massively diverged between master and 7.x. With the work in the below PRs, the logic in master and 7.x once again has been aligned very closely again. #72842 #73172 #73199 #73570 #73952 #74236 #74451 (this one is only partly applicable as it was mainly a change to master to align `master` and `7.x` branches)
Adds new snapshot meta pool that is used to speed up the get snapshots API
by making
SnapshotInfo
load in parallel. Also use this pool to loadRepositoryData
.A follow-up to this would expand the use of this pool to the snapshot status
API and make it run in parallel as well.