Skip to content

[vtadmin] Aggregate schema sizes#7751

Merged
rafael merged 25 commits intovitessio:masterfrom
tinyspeck:am_vtadmin_aggregate_schema_sizes
Mar 31, 2021
Merged

[vtadmin] Aggregate schema sizes#7751
rafael merged 25 commits intovitessio:masterfrom
tinyspeck:am_vtadmin_aggregate_schema_sizes

Conversation

@ajm188
Copy link
Contributor

@ajm188 ajm188 commented Mar 26, 2021

Description

This PR enhances the Get/Find Schema(s) endpoints to aggregate row counts and data lengths (more broadly, "sizes") across tablets from all shards in a given keyspace, so that vtadmin can display them to the user.

To make this work, I refactored a lot (but not all) of the logic around orchestrating and making GetSchema vtctld rpcs from the API layer to the Cluster layer, including the addition of a cluster.GetSchemaOptions type to control the behavior of these cluster-level methods, as well as to allow us to continue to prefetch tablets as an optimization. We use that GetSchemaOptions type to also plumb through the size-aggregation options. There's extensive inline documentation about how the different options in this type affect the behavior, so I won't repeat them here.

I also pulled out our tablet filtering code to a public function as vtadminproto.FilterTablets and added some additional trace annotation helper functions.

Related Issue(s)

Checklist

  • Should this PR be backported? no
  • Tests were added or are not required
  • Documentation was added or is not required

Deployment Notes

Impacted Areas in Vitess

Components that this PR will affect:

  • Query Serving
  • VReplication
  • Cluster Management
  • Build/CI
  • VTAdmin

Andrew Mason added 20 commits March 13, 2021 08:14
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
… later)

Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Changes are to make it behave more similarly to the old `GetSchema`, so
that I could repurpose those tests. At this point, we can delete
`GetSchema` and rename `GetSchemaForKeyspace`

Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Copy link
Contributor

@doeg doeg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great to me!!! A handful of lil non-blocking comments. Thank you again because I know this was a ton of work.

So excited to use this on the front-end. 😈

BaseRequest *vtctldatapb.GetSchemaRequest
// SizeOpts control whether the (*Cluster).GetSchema method performs
// cross-shard table size aggregation (via the AggregateSizes field), and
// the behavior of that size aggregation (via the IncludeNonServingShards
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you help me understand the use cases for the two values of IncludeNonServingShards? (Thinking of vtadmin-web but maybe there are others!) An entirely non-blocking question, of course. :)

Like, maybe it's as simple as a checkbox in the UI, and operators will already know when they care about one vs the other....? And/or is the diff between the two values interesting to show? (Also, is true the best default value, you think?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had the same question. Wondering if we need this right now and maybe it is not worth having part of the API at the moment. My initial intuition is that only aggregating serving shards, seems sufficient. What other use cases you had in mind?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going to tag @rafael just to consolidate the discussion on this thread, since it's in at least two places now.

I'm actually having trouble articulating why we would ever want this (maybe if we were mid-split and wanted to see what the true total size of provisioned storage was vs what the logical size is (because in a split you would be double-counting between a source and its destination shards), but beyond that I'm not sure).

I think, though, that if we are going to keep it, false is the right default here. Because it's probably confusing if you weren't explicitly opting in to the potential double-counting.

Buttttt like I just said, maybe we should remove it entirely and just always skip non-serving shards. I'm curious to hear what you both think!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be in favor of always skipping non serving shards for now. If we see an use case in the future, then we iterate and add it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Omitting it sounds good to me, especially since it'll simplify the front-end a lil bit too. :)

Comment on lines +492 to +501
span, ctx := trace.NewSpan(ctx, "Cluster.FindAllShardsInKeyspace")

AnnotateSpan(c, span)
span.Annotate("keyspace", keyspace)

resp, err := c.Vtctld.FindAllShardsInKeyspace(ctx, &vtctldatapb.FindAllShardsInKeyspaceRequest{
Keyspace: keyspace,
})

span.Finish()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really minor + non-blocking point -- did you consider a (c *Cluster) FindAllShardsInKeyspace function? That might simplify this a tiny bit, especially with the annotations. (It took me 0.2 seconds to realize that in this case we don't want a defer span.Finish() call.) 😊

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, that sounds good! (i didn't because i didn't want to write more tests :shamebell:)

if len(keyspaceTablets) == 0 {
// consider how to include info about the tablets we looked at, but
// that's also potentially a very long list .... maybe we should
// just log it (yes, do that).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a formal TODO? Haha 🌻

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I uhh meant for this to be for my eyes only 😬


if _, ok = tableSize.ByShard[tablet.Tablet.Shard]; ok {
// We managed to query for the same shard twice, that's ...
// weird. but do we care? maybe just log? idk!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol I do truly love this comment, but it is somewhat out of character with the rest so I wanted to point it out just in case

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should error? That seems like it shouldn't happen, so if it does happen we better investigate??

Comment on lines +551 to +557
// Instead of starting at false, we start with whatever the base request
// specified. If we have exactly one tablet to query (i.e. we're not
// doing multi-shard aggregation), it's possible the request was to
// literally just get the table sizes; we shouldn't assume. If we have
// more than one tablet to query, then we are doing size aggregation,
// and we'll flip this to true after spawning the first GetSchema rpc.
sizesOnly = opts.BaseRequest.TableSizesOnly
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes a lot of sense + I appreciate you annotating it inline!

Copy link
Member

@rafael rafael left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did my initial pass! Let me know your thoughts.

// (described above) to find one SERVING tablet for each shard in the
// keyspace. If IncludeNonServingShards is false, then we will skip any
// shards for which IsMasterServing is false.
SizeOpts *vtadminpb.GetSchemaTableSizeOptions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Names are always hard. SizeOpts is a bit opaque to me. Maybe TableSizeAggregationOpts ? That is too mouthful...

I think we should come up with a better name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about just TableSizeOptions and have it mirror the type name? I think it's a reasonable tradeoff between clarity and verbosity. Let me know what you think!

BaseRequest *vtctldatapb.GetSchemaRequest
// SizeOpts control whether the (*Cluster).GetSchema method performs
// cross-shard table size aggregation (via the AggregateSizes field), and
// the behavior of that size aggregation (via the IncludeNonServingShards
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had the same question. Wondering if we need this right now and maybe it is not worth having part of the API at the moment. My initial intuition is that only aggregating serving shards, seems sufficient. What other use cases you had in mind?


if _, ok = tableSize.ByShard[tablet.Tablet.Shard]; ok {
// We managed to query for the same shard twice, that's ...
// weird. but do we care? maybe just log? idk!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should error? That seems like it shouldn't happen, so if it does happen we better investigate??

sizesOnly = opts.BaseRequest.TableSizesOnly
)

for _, tablet := range tabletsToQuery {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here similar to my other comment about throttling. I'm not too concern, because I think this should scale pretty well as it's rpc to different hosts. But it does makes a bit nervous that for large keyspaces we can be making too many of this in parallel.

Wondering if putting a guardrail where we say: we only do X amount of parallelism will be good to have in place early on.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think when we do the "bound topo RPCs to max concurrency" there should be two limits: tablet RPC max concurrency, and topo RPC max concurrency (maybe others). Then each of those gets configured (per cluster, so larger clusters could in theory have higher limits) and we spawn a waitgroup/pool/etc with that value as the capacity.

Andrew Mason added 4 commits March 26, 2021 22:55
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Signed-off-by: Andrew Mason <amason@slack-corp.com>
Copy link
Contributor

@doeg doeg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great + even more streamlined than before. :chef-kiss: Just one non-blocking question. :)

(I defer to you and Rafa on the parts on throttling.) :D

type FindAllShardsInKeyspaceOptions struct {
// SkipDial indicates that the cluster can assume the vtctldclient has
// already dialed up a connection to a vtctld.
SkipDial bool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious why SkipDial is exposed as an option given that all uses (so far) are true. Requiring the caller to dial a vtctld connection seems like a fair contract to me + it seems like it'd simplify the interface quite a bit. Let me know if I missed something though!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm of two minds about requiring callers to know the details enough to call Dial (though, this option just does the same thing, only one thin layer removed).

I think long term what I want is for a cluster to be smart about the last time it dialed, and "just do the right thing", and the caller doesn't need to know or care. I'd like to leave this as-is for now and noodle on that some more.

@rafael rafael merged commit b6a8acb into vitessio:master Mar 31, 2021
@rafael rafael deleted the am_vtadmin_aggregate_schema_sizes branch March 31, 2021 15:57
@askdba askdba added the Component: VTAdmin VTadmin interface label Apr 1, 2021
@askdba askdba added this to the v10.0 milestone Apr 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Component: VTAdmin VTadmin interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants