Skip to content

server: do not initialize cluster version to minimum supported#127170

Merged
craig[bot] merged 1 commit intocockroachdb:masterfrom
renatolabs:rc/delete-bad-version-initialize-shared-process
Jul 30, 2024
Merged

server: do not initialize cluster version to minimum supported#127170
craig[bot] merged 1 commit intocockroachdb:masterfrom
renatolabs:rc/delete-bad-version-initialize-shared-process

Conversation

@renatolabs
Copy link
Copy Markdown

Previously, shared-process tenants would initialize their view of the cluster version early and set it to the MinSupportedVersion as a "safe" option. However, that setting can likely be wrong, especially now that we plan to support skip-version upgrades.

In this commit, we remove that code and rely on the initialization that happens from storage in preStart. This means that we now expose a non-negligible amount of code to a state where we don't have an initialized cluster version. However, having that error out is better than have code assume a potentially wrong version.

A similar discussion and approach happened for separate process tenants a while ago: see #100684 and #104859.

Fixes: #126754

Release note: None

@blathers-crl
Copy link
Copy Markdown

blathers-crl bot commented Jul 15, 2024

It looks like your PR touches production code but doesn't add or edit any test code. Did you consider adding tests to your PR?

🦉 Hoot! I am a Blathers, a bot for CockroachDB. My owner is dev-inf.

@cockroach-teamcity
Copy link
Copy Markdown
Member

This change is Reviewable

@renatolabs
Copy link
Copy Markdown
Author

@stevendanna this change has hilariously caused the RPC port that the tenant binds to in cockroach demo to change, and so there's an acceptance test failing. I haven't looked too deeply into how this could be yet; thought I'd check with you if you had any hunches.

@renatolabs renatolabs force-pushed the rc/delete-bad-version-initialize-shared-process branch 2 times, most recently from 4d0d894 to 5d287ee Compare July 22, 2024 14:00
@stevendanna
Copy link
Copy Markdown
Collaborator

No idea how the cluster version is impacting this port hint code.

@renatolabs renatolabs marked this pull request as ready for review July 22, 2024 14:35
@renatolabs renatolabs requested a review from a team as a code owner July 22, 2024 14:35
@renatolabs
Copy link
Copy Markdown
Author

Summary of the events:

Removing the clusterversion initialization to the minimum supported version in shared-process tenants here led to the RPC port the tenant binds to to change, and as a consequence test_demo_networking.tcl failed.

The reason for this is that we now attempt to read the cluster version from storage earlier (in the preStart function). When we're starting the tenant servers in a retry loop, the first run of the loop will typically fail because the tenant is not quite initialized yet:

551:W240722 14:28:34.503933 3508 server/server_controller_channel_orchestrator.go:406 ⋮ [n2,tenant-orchestration,tenant=‹demoapp›] 542 unable to start server for tenant ‹"demoapp"› (attempt 0, will retry): while starting server: initializing cluster version: ba: ‹Get [/Tenant/2/Table/6/1/"version"/0], [txn: ca774a03], [can-forward-ts]› RPC error: grpc: ‹operation not allowed when in service mode "none"› [code 16/Unauthenticated]

However, the implementation of the newServerForOrchestrator function had a different assumption builtin: it would increment an "index" each time it was called, and pass that index as an offset to a port range. These two layers are, therefore, a little incompatible: the outer layer performs retries, presumably for situations when there are concurrent initialization tasks that need to complete in order for the tenant server to be able to start. At the same time, the orchestrator would assume every call to newServerForOrchestrator is linked to a different tenant.

Given that servers will scan the port range until they find an open port anyway, there was never a strong guarantee that ports are deterministic (as the test suggests). For this reason, this commit implements an approach where we drop the "index" concept from the orchestrator, and just let servers bind to the first port in the range they find available.

If there's a strong reason to keep the "index" idea around, let me know and we can take a different route.

@stevendanna
Copy link
Copy Markdown
Collaborator

stevendanna commented Jul 22, 2024

Uff. It's a rather unfortunate side-effect of the current architecture that we can start trying to start up the tenant's sql server before the rest of the system has seen the tenant's state change.

If there's a strong reason to keep the "index" idea around, let me know and we can take a different route.

I think my main reason for keeping it as the time of adding the port-finding code was just to reduce the amount of time we spend searching through ports we likely already have used. I know that there is also this oddness over in demo_cluster.go:

// The code in NewDemoCluster put the KV ports higher so
// we need to subtract the number of nodes to get back
// to the "good" ports.
//
// We reduce lower bound of the port range by 1 because
// the server controller uses 1-based indexing for
// servers.
args.ApplicationInternalRPCPortMin = rpcPort - (demoCtx.NumNodes + 1)
args.ApplicationInternalRPCPortMax = args.ApplicationInternalRPCPortMin + 1024

But I don't think your change here will change that that is trying to do.

@stevendanna
Copy link
Copy Markdown
Collaborator

I kinda wonder if we should follow up with something that does one or two retries around that initial version look up in the case of particular errors. If we are starting s SQL server for a tenant, then there is a good reason to suspect that this should work if we were to retry quickly.

@renatolabs
Copy link
Copy Markdown
Author

We can do that, I'll take a stab at it.

That said, I'm still not sure whether we should keep the index idea around. I understand it's not ideal to have multiple tenants race to bind to the same ports but also find it quite error-prone/confusing to have a function that assumes one-tenant-per-call (newServerForOrchestrator) being called in a retry loop. But I'm fine to keep it the index around until we have a better solution for all of this.

@renatolabs
Copy link
Copy Markdown
Author

something that does one or two retries around that initial version look up in the case of particular errors

I knew this sounded familiar 😄

allowedFailures := 10
// Kick off the rangefeedcache which will retry until the stopper stops.
if err := rangefeedcache.Start(ctx, s.stopper, c, func(err error) {
if !initialScan.done {
// TODO(dt): ideally the auth checker, which makes rejection decisions
// based on cached data that is updated async via rangefeed, would block
// for some amount of time before rejecting a request if it can determine
// that its information is old/maybe stale, to avoid spurious rejections
// while making correct rejection potentially slightly slower to return.
if strings.Contains(err.Error(), `operation not allowed when in service mode "none"`) && allowedFailures > 0 {
allowedFailures--

@renatolabs renatolabs force-pushed the rc/delete-bad-version-initialize-shared-process branch from 5d287ee to f393011 Compare July 22, 2024 17:59
@renatolabs
Copy link
Copy Markdown
Author

@stevendanna let me know if something like this is what you had in mind.

@renatolabs
Copy link
Copy Markdown
Author

@stevendanna friendly ping.

Comment on lines +1497 to +1499
// When initializing the cluster version for tenants, we retry on certain
// errors that could happen if the tenant has not transitioned to
// its actual service mode yet.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[nit] I think we can be a bit more explicit here. We retry if the error indicates that the KV authoriser hasn't seen our service-mode transition. This is possible because both the service controller and authoriser received tenant mode updates asynchronously via rangefeeds.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks, updated.

Previously, shared-process tenants would initialize their view of the
cluster version early and set it to the `MinSupportedVersion` as a
"safe" option. However, that setting can likely be wrong, especially
now that we plan to support skip-version upgrades.

In this commit, we remove that code and rely on the initialization
that happens from storage in `preStart`. This means that we now expose
a non-negligible amount of code to a state where we don't have an
initialized cluster version. However, having that error out is better
than have code assume a potentially wrong version.

A similar discussion and approach happened for separate process
tenants a while ago: see cockroachdb#100684 and cockroachdb#104859.

Fixes: cockroachdb#126754

Release note: None
@renatolabs renatolabs force-pushed the rc/delete-bad-version-initialize-shared-process branch from f393011 to e36acf8 Compare July 30, 2024 19:50
@renatolabs
Copy link
Copy Markdown
Author

TFTR!

bors r=stevendanna

@craig
Copy link
Copy Markdown
Contributor

craig bot commented Jul 30, 2024

@blathers-crl
Copy link
Copy Markdown

blathers-crl bot commented Jul 30, 2024

Based on the specified backports for this PR, I applied new labels to the following linked issue(s). Please adjust the labels as needed to match the branches actually affected by the issue(s), including adding any known older branches.


Issue #126754: branch-release-24.2.


🦉 Hoot! I am a Blathers, a bot for CockroachDB. My owner is dev-inf.

xinhaoz added a commit to xinhaoz/cockroach that referenced this pull request Jan 6, 2025
Previously the http routes were set up after sql version
initialization. As of cockroachdb#127170, the version initialization
occurs in the sql server prestart, which occurs just after
router setup. It became possible to hit the http routes before
the version was set, leading to panics as the http routes
rely on the sql version being set.

Epic: none
Fixes: cockroachdb#138342
DarrylWong pushed a commit to DarrylWong/fork that referenced this pull request Jan 7, 2025
Previously the http routes were set up after sql version
initialization. As of cockroachdb#127170, the version initialization
occurs in the sql server prestart, which occurs just after
router setup. It became possible to hit the http routes before
the version was set, leading to panics as the http routes
rely on the sql version being set.

Epic: none
Fixes: cockroachdb#138342
xinhaoz added a commit to xinhaoz/cockroach that referenced this pull request Jan 8, 2025
Previously the http routes for secondary tenants were set up
after sql version initialization. As of cockroachdb#127170, the version
initialization occurs in the sql server prestart, which occurs
just after the router setup. It became possible to hit the http
routes before the version was set, leading to fatal errors as
the http routes rely on the sql version being set.

Epic: none
Fixes: cockroachdb#138342

Release note (bug fix): Secondary tenants will not fatal when
issuing HTTP requests during tenant startup.
craig bot pushed a commit that referenced this pull request Jan 9, 2025
138343: sql: setup http router after version initialization r=xinhaoz a=xinhaoz

Previously the http routes were set up after sql version initialization. As of #127170, the version initialization occurs in the sql server prestart, which occurs just after router setup. It became possible to hit the http routes before the version was set, leading to panics as the http routes rely on the sql version being set.

Epic: none
Fixes: #138342

Co-authored-by: Xin Hao Zhang <xzhang@cockroachlabs.com>
blathers-crl bot pushed a commit that referenced this pull request Jan 9, 2025
Previously the http routes for secondary tenants were set up
after sql version initialization. As of #127170, the version
initialization occurs in the sql server prestart, which occurs
just after the router setup. It became possible to hit the http
routes before the version was set, leading to fatal errors as
the http routes rely on the sql version being set.

Epic: none
Fixes: #138342

Release note (bug fix): Secondary tenants will not fatal when
issuing HTTP requests during tenant startup.
xinhaoz added a commit that referenced this pull request Jan 13, 2025
Previously the http routes for secondary tenants were set up
after sql version initialization. As of #127170, the version
initialization occurs in the sql server prestart, which occurs
just after the router setup. It became possible to hit the http
routes before the version was set, leading to fatal errors as
the http routes rely on the sql version being set.

Epic: none
Fixes: #138342

Release note (bug fix): Secondary tenants will not fatal when
issuing HTTP requests during tenant startup.
xinhaoz added a commit that referenced this pull request Jan 13, 2025
Previously the http routes for secondary tenants were set up
after sql version initialization. As of #127170, the version
initialization occurs in the sql server prestart, which occurs
just after the router setup. It became possible to hit the http
routes before the version was set, leading to fatal errors as
the http routes rely on the sql version being set.

Epic: none
Fixes: #138342

Release note (bug fix): Secondary tenants will not fatal when
issuing HTTP requests during tenant startup.
xinhaoz added a commit that referenced this pull request Jan 13, 2025
Previously the http routes for secondary tenants were set up
after sql version initialization. As of #127170, the version
initialization occurs in the sql server prestart, which occurs
just after the router setup. It became possible to hit the http
routes before the version was set, leading to fatal errors as
the http routes rely on the sql version being set.

Epic: none
Fixes: #138342

Release note (bug fix): Secondary tenants will not fatal when
issuing HTTP requests during tenant startup.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

multitenant: shared-process tenant auto upgrades even if preserve_downgrade_option was set prior to restart

3 participants