Skip to content

Keeper priority#622

Open
arssher wants to merge 2 commits into
sorintlab:masterfrom
postgrespro:keeper_priority
Open

Keeper priority#622
arssher wants to merge 2 commits into
sorintlab:masterfrom
postgrespro:keeper_priority

Conversation

@arssher
Copy link
Copy Markdown

@arssher arssher commented Mar 11, 2019

Add --priority keeper option.

Sentinel will promote keeper with higher priority than the current one if this
is possible. In async mode this is a bit non-deterministic because we always
elect node with highest LSN, and under heavy load prioritized node might never
report LSN higher than its stronger competitors. However, if nodes are equal
this should happen at some moment. In sync mode, we can just elect any of
synchronous standbies.

Implements #492

While here, make eyeballing of sentinel tests failures easier.

@arssher
Copy link
Copy Markdown
Author

arssher commented Mar 12, 2019

semaphoreci failed at config_test.go:541 in one of the configurations, but I don't think this is related to this pull request -- seems like the database just couldn't restart in 10 seconds. Is there a way to restart the test?

@rearden-steel
Copy link
Copy Markdown

Any updates on this PR? Need this feature.

Copy link
Copy Markdown
Member

@sgotti sgotti left a comment

Choose a reason for hiding this comment

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

@arssher Thanks for the PR and sorry for the delay. I haven't had time to deeply test it but it should be covered by the tests you added. Some comments inline.


// Return DB who can be new master. This function mostly takes care of
// sync mode; in async case, new master is just first element of findBestNewMasters.
func (s *Sentinel) findBestNewMaster(cd *cluster.ClusterData, curMasterDB *cluster.DB, logErrors bool) *cluster.DB {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

findBestNewMaster returns the db who can be the new master. This function ....

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.

Hm?

Comment thread cmd/sentinel/cmd/sentinel.go Outdated
}
if bestNewMasterDB == nil {
if logErrors {
log.Errorw("cannot choose synchronous standby since there's not match between the possible masters and the usable synchronousStandbys", "reported", curMasterDB.Status.SynchronousStandbys, "spec", curMasterDB.Spec.SynchronousStandbys, "common", commonSyncStandbys, "possibleMasters", bestNewMasters)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This previously was a log.Warnf

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.

Indeed, fixed.

Comment thread cmd/sentinel/cmd/sentinel.go Outdated
commonSyncStandbys := util.CommonElements(curMasterDB.Status.SynchronousStandbys, curMasterDB.Spec.SynchronousStandbys)
if len(commonSyncStandbys) == 0 {
if logErrors {
log.Errorw("cannot choose synchronous standby since there are no common elements between the latest master reported synchronous standbys and the db spec ones", "reported", curMasterDB.Status.SynchronousStandbys, "spec", curMasterDB.Spec.SynchronousStandbys)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This previously was a log.Warnf

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.

Indeed, fixed.

log.Infow("electing db as the new master", "db", bestNewMasterDB.UID, "keeper", bestNewMasterDB.Spec.KeeperUID)
// Even if current master is ok, we probably still
// want to change it if there is ready DB with higher
// keeper priority.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So the priority will be used also to changing primary also when there's no failure? This should probably be documented

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.

Yes. I have added some words to --priority help describing this.

Comment thread cmd/sentinel/cmd/sentinel_test.go Outdated
}
return reflect.DeepEqual(cd1, cd2)

equal, diff := util.DeepEqualVerbose(cd1, cd2)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since this change could be really useful (in other projects I also used github.com/google/go-cmp) to debug test failures but not strictly related to this feature, can you please remove from this PR and open a new dedicated PR?

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.

Done so; extracted to #679 and excluded here.

}
pi := cd.Keepers[dbs[i].Spec.KeeperUID].Status.Priority
pj := cd.Keepers[dbs[i].Spec.KeeperUID].Status.Priority
return pi < pj
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In Line 700,

pj := cd.Keepers[dbs[i].Spec.KeeperUID].Status.Priority

replace dbs[i] to dbs[j]

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.

Ups, good catch, thanks.

@rearden-steel
Copy link
Copy Markdown

@arssher can you update this PR?

@arssher
Copy link
Copy Markdown
Author

arssher commented Jun 26, 2019

Hi, I will try to look into this in a few days.

@arssher
Copy link
Copy Markdown
Author

arssher commented Jun 30, 2019

Sorry for the quite a delay. I have updated the PR:

  • Addressed comments above.
  • Rebased on current master.
  • Added facility to update keeper priority online (new command stolonctl setkeeperpriority). It allows to update priority without restarting the keeper (and underlying Postgres instance), which can be used for controlled failover. My colleague @maksm90 hinted me it would be a nice addition...

@arssher
Copy link
Copy Markdown
Author

arssher commented Jun 30, 2019

BTW, when generating docs (gen_commands_doc.sh) I have noticed that it wasn't updated for some lately added keeper options, e.g. pg-advertise-address. I have excluded those from this PR also as I believe they should go in separate commit.

Also, does it make sense to restamp all docs files with current date like "Auto generated by spf13/cobra on 30-Jun-2019"? I can revert them, leaving only ones who have really changed.

@arssher arssher force-pushed the keeper_priority branch from f39a2bd to 50601c5 Compare July 1, 2019 06:14
@arssher
Copy link
Copy Markdown
Author

arssher commented Jul 1, 2019

(Made a small cleanup just now, used DefaultPriority const and purged obsolete NotSpecifiedPriority const)

@arssher arssher force-pushed the keeper_priority branch from 50601c5 to b9f2b74 Compare July 1, 2019 07:50
@arssher
Copy link
Copy Markdown
Author

arssher commented Jul 1, 2019

One more minor fix/cleanup: forgot to add generated doc for setkeeperpriority command and used DefaultPriority const in keeper help.

Last CI build failed on Consul and passed all other stores. Looking at logs, I think this PR is not a reason of the failure again. Error was at ha_test.go:1574 in TestKeeperRemovalStolonCtl. removekeeper failed with:

    utils.go:881: executing stolonctl, args: [--cluster-name=fbfeb889-37b5-402a-89c3-e9acdaf0e248 --store-backend=consul --store-endpoints=127.0.0.1:2278 removekeeper 7c99557a]
    utils.go:897: [stolonctl]: cannot update cluster data: Unable to complete atomic operation, key modified
    ha_test.go:1576: unexpected err: exit status 1

So most probably stolonctl got interleaved with sentinel's clusterdata update.

@arssher
Copy link
Copy Markdown
Author

arssher commented Jul 1, 2019

Hm, now two builds failed. One of them is exactly as previous: TestKeeperRemovalStolonCtl at ha_test.go:1576.

Another is TestForceFailSyncReplStandbyCluster, at
ha_test.go:1893: expected master "1a1cd8ab" in cluster view
Which means sentinel failed to re-elect must after forcefail:

    utils.go:256: [sentinel dc41d2d6]: 2019-07-01T08:16:13.737Z	[34mINFO[0m	cmd/sentinel.go:1027	master db is failed	{"db": "1c4f397a", "keeper": "4a4c481b"}
    utils.go:256: [sentinel dc41d2d6]: 2019-07-01T08:16:13.738Z	[31mERROR[0m	cmd/sentinel.go:768	no eligible masters

It is unclear to me why this happened. Since I didn't touch findBestNewMasters function, most probably it is not me, but still... can we rerun the tests with debug log level enabled to see what's happening inside findBestNewMasters?

@rearden-steel
Copy link
Copy Markdown

@sgotti would you please check this PR?

@rearden-steel
Copy link
Copy Markdown

@sgotti Any updates on this?

@sgotti
Copy link
Copy Markdown
Member

sgotti commented Feb 14, 2020

@rearden-steel this PR requires an update/rebase and we have to understand if this will cover also #696. Are you willing to take care of this PR? @lawrencejones @maksm90

@ololobus ololobus force-pushed the keeper_priority branch 2 times, most recently from 6b7fdfb to ef591f2 Compare July 9, 2020 19:45
arssher and others added 2 commits July 10, 2020 13:02
Sentinel will promote keeper with higher priority than the current one if this
is possible. In async mode this is a bit non-deterministic because we always
elect node with highest LSN, and under heavy load prioritized node might never
report LSN higher than its stronger competitors. However, if nodes are equal
this should happen at some moment. In sync mode, we can just elect any of
synchronous standbies.

Priority can be set during keeper start (--priority) or later with new command
'stolonctl set keeperpriority'. The latter allows to update priority without
restarting the keeper (and its Postgres instance), which can be used for
controlled failover.

Implements sorintlab#492
@ololobus
Copy link
Copy Markdown

@sgotti, I've rebased this branch. I had to modify one place because of a linter error, now all existing tests pass and

make test
INTEGRATION=1 STOLON_TEST_STORE_BACKEND=etcdv3 ./test

works well for me. As for CI, I've found it to be quite unstable these days: first it failed on build / make test with zero output; after re-pushing the brach with --force without changes all tests passed; now, I modified only a single comment and TestProxyListening failed with

TestProxyListening: utils.go:1090: err: context deadline exceeded
TestProxyListening: proxy_test.go:164: error waiting on store up: timeout
TestProxyListening: utils.go:300: stopping etcd e82d334a

which seems to be not a matter of this PR and means that etcd just failed to start before timeout fired, doesn't it?

BTW, in the #696 you mentioned that it worth to check compatibility of this PR with 05b1b0f. I had a look on it, and it seems that everything works fine even without changes, since added in this PR findBestNewMaster uses findBestNewMasters, which simply skips master candidates with --can-be-master. That way, a keeper with both --priority=0 and --can-be-master=false wouldn't be promoted.

However, it may be a bit misleading for a user, so maybe we should restrict usages of both --priority=0 and --can-be-master=false simultaneously? What do you think, @sgotti @rearden-steel @arssher?

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.

5 participants