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

storage: use RWMutex in NodeLiveness #36316

Merged

Conversation

ajwerner
Copy link
Contributor

When at Mutex profiles for heavily loaded TPC-C clusters we noticed that a lot
of time was being spent blocked on a RWMutex held by Replica.leaseGoodToGo which
underneath was reading NodeLiveness state in a read-only way. This PR adds a
RWMutex to NodeLiveness to eliminate contention. Prior to this change we
observed nearly 60% of lock contention on leaseGoodToGo. After we observe
closer to 20%.

Release note: None

@ajwerner ajwerner requested review from nvanbenschoten and a team March 29, 2019 00:37
@cockroach-teamcity
Copy link
Member

This change is Reviewable

@ajwerner
Copy link
Contributor Author

Before:
Screenshot_2019-03-28 cockroach delay(1)

After:
Screenshot_2019-03-28 cockroach delay

Copy link
Member

@nvanbenschoten nvanbenschoten left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner and @nvanbenschoten)


pkg/storage/node_liveness.go, line 598 at r1 (raw file):

// a former liveness update on restart.
func (nl *NodeLiveness) Self() (*storagepb.Liveness, error) {
	nl.mu.Lock()

Read lock here as well?


pkg/storage/node_liveness.go, line 619 at r1 (raw file):

	nl.mu.RLock()
	defer nl.mu.RUnlock()
	lMap := IsLiveMap{}

Let's pull this allocation out of the lock.


pkg/storage/node_liveness.go, line 845 at r1 (raw file):

	}

	nl.mu.Lock()

Read lock?


pkg/storage/node_liveness.go, line 857 at r1 (raw file):

// registered callbacks if the node became live in the process.
func (nl *NodeLiveness) maybeUpdate(new storagepb.Liveness) {
	nl.mu.Lock()

While we're here, I wonder if we should improve this. There are a few easy wins. For starters, if shouldReplaceLiveness is false some non-negligible percent of time (I'm not sure about this) then it's probably worth initially grabbing a read-lock and only upgrading to a write-lock if necessary. Doing this would also give us the ability to optimistically allocate the callbacks slice outside of the lock.


pkg/storage/node_liveness.go, line 935 at r1 (raw file):

	maxOffset := nl.clock.MaxOffset()

	nl.mu.Lock()

Read lock?

@ajwerner ajwerner force-pushed the ajwerner/rw-mutex-for-nodeliveness branch from acd7c16 to d4e9c9c Compare April 2, 2019 13:08
Copy link
Contributor Author

@ajwerner ajwerner left a comment

Choose a reason for hiding this comment

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

Updated, PTAL.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained

Copy link
Member

@nvanbenschoten nvanbenschoten left a comment

Choose a reason for hiding this comment

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

:lgtm: mod the question about whether the optimistic read-locking in maybeUpdate could be a pessimization.

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @ajwerner)


pkg/storage/node_liveness.go, line 866 at r2 (raw file):

	// Note that this works fine even if `old` is empty.
	should := shouldReplaceLiveness(old, new)
	if !should {

Nice! Any idea how frequently we hit this path? Running a roachtest manually with a bit of instrumentation would be enough to get some feel for this.


pkg/storage/node_liveness.go, line 872 at r2 (raw file):

	callbacks := make([]IsLiveCallback, 0, numCallbacks)
	nl.mu.Lock()
	old = nl.mu.nodes[new.NodeID]

Drop a comment above this that we check shouldReplaceLiveness again now that we're under and exclusive lock.

@ajwerner
Copy link
Contributor Author

ajwerner commented Apr 2, 2019

Nice! Any idea how frequently we hit this path? Running a roachtest manually with a bit of instrumentation would be enough to get some feel for this.

It does indeed seem to be a pessimization. We seem to hit the fast path roughly 1/3rd of the time on a 3 node cluster and 1/9th of the time on a 9 node cluster (pattern?)

I'll rip it out

When at Mutex profiles for heavily loaded TPC-C clusters we noticed that a lot
of time was being spent blocked on a RWMutex held by Replica.leaseGoodToGo which
underneath was reading NodeLiveness state in a read-only way. This PR adds a
RWMutex to NodeLiveness to eliminate contention. Prior to this change we
observed nearly 60% of lock contention on leaseGoodToGo. After we observe
closer to 20%.

Release note: None
@ajwerner ajwerner force-pushed the ajwerner/rw-mutex-for-nodeliveness branch from d4e9c9c to a134caa Compare April 2, 2019 22:21
Copy link
Member

@nvanbenschoten nvanbenschoten left a comment

Choose a reason for hiding this comment

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

:lgtm:

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @ajwerner)

@ajwerner
Copy link
Contributor Author

ajwerner commented Apr 2, 2019

bors r+

craig bot pushed a commit that referenced this pull request Apr 2, 2019
36316: storage: use RWMutex in NodeLiveness r=ajwerner a=ajwerner

When at Mutex profiles for heavily loaded TPC-C clusters we noticed that a lot
of time was being spent blocked on a RWMutex held by Replica.leaseGoodToGo which
underneath was reading NodeLiveness state in a read-only way. This PR adds a
RWMutex to NodeLiveness to eliminate contention. Prior to this change we
observed nearly 60% of lock contention on leaseGoodToGo. After we observe
closer to 20%.

Release note: None

Co-authored-by: Andrew Werner <[email protected]>
@craig
Copy link
Contributor

craig bot commented Apr 2, 2019

Build succeeded

@craig craig bot merged commit a134caa into cockroachdb:master Apr 2, 2019
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.

3 participants