Skip to content

Commit d3ede01

Browse files
committed
http2: fix lock contention slowdown due to gracefulShutdownCh
gracefulShutdownCh is shared by all connections in a server. When a server accumulates many connections (e.g., 5000 in the kubemark-5000 benchmark), we have 5000 serverConn.serve goroutines selecting on this channel. This means 5000 goroutines hammer the channel's lock, which causes severe lock contention. The fix in this CL is to make a local proxy for gracefulShutdownCh in each connection so that each connection selects on gracefulShutdownCh at most once per connection rather than once per serverConn.serve loop iteration. This fix is intended to be backported quickly into Go 1.8.2. The downside of this fix is 2KB extra stack usage per connection. A better fix will be implemented in Go 1.9. Unfortunately, I have been unable to reproduce this problem locally. This fix was verified by the kubernetes team. See: kubernetes/kubernetes#45216 (comment) Updates golang/go#20302 Change-Id: I19ab19268a6ccab9b6e9dffa0cfbc89b8c7d0f19
1 parent c9b681d commit d3ede01

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

http2/server.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -753,9 +753,13 @@ func (sc *serverConn) serve() {
753753
sc.idleTimerCh = sc.idleTimer.C
754754
}
755755

756-
var gracefulShutdownCh <-chan struct{}
756+
var gracefulShutdownCh chan struct{}
757757
if sc.hs != nil {
758-
gracefulShutdownCh = h1ServerShutdownChan(sc.hs)
758+
ch := h1ServerShutdownChan(sc.hs)
759+
if ch != nil {
760+
gracefulShutdownCh = make(chan struct{})
761+
go sc.awaitGracefulShutdown(ch, gracefulShutdownCh)
762+
}
759763
}
760764

761765
go sc.readFrames() // closed by defer sc.conn.Close above
@@ -808,6 +812,14 @@ func (sc *serverConn) serve() {
808812
}
809813
}
810814

815+
func (sc *serverConn) awaitGracefulShutdown(sharedCh <-chan struct{}, privateCh chan struct{}) {
816+
select {
817+
case <-sc.doneServing:
818+
case <-sharedCh:
819+
close(privateCh)
820+
}
821+
}
822+
811823
// readPreface reads the ClientPreface greeting from the peer
812824
// or returns an error on timeout or an invalid greeting.
813825
func (sc *serverConn) readPreface() error {

0 commit comments

Comments
 (0)