Skip to content

Commit 4a79972

Browse files
committed
stability enhancement during overload conditions
Signed-off-by: shenmu.wy <[email protected]>
1 parent 05b8563 commit 4a79972

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

server/etcdserver/util.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"fmt"
1919
"time"
2020

21+
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
2122
"go.etcd.io/etcd/client/pkg/v3/types"
2223
"go.etcd.io/etcd/server/v3/etcdserver/api/membership"
2324
"go.etcd.io/etcd/server/v3/etcdserver/api/rafthttp"
@@ -42,6 +43,25 @@ func isConnectedFullySince(transport rafthttp.Transporter, since time.Time, self
4243
return numConnectedSince(transport, since, self, members) == len(members)
4344
}
4445

46+
// exceedsRequestLimit checks if the committed index is too far ahead of
47+
// the applied index. Priority requests are allowed up to 10% extra gap.
48+
func exceedsRequestLimit(ai, ci uint64, r *pb.InternalRaftRequest) bool {
49+
if ci <= ai+maxGapBetweenApplyAndCommitIndex {
50+
return false
51+
}
52+
// allow up to 10% extra gap for priority requests
53+
if ci <= ai+maxGapBetweenApplyAndCommitIndex*110/100 {
54+
if isPriorityRequest(r) {
55+
return false
56+
}
57+
}
58+
return true
59+
}
60+
61+
func isPriorityRequest(r *pb.InternalRaftRequest) bool {
62+
return r != nil && r.LeaseRevoke != nil
63+
}
64+
4565
// numConnectedSince counts how many members are connected to the local member
4666
// since the given time.
4767
func numConnectedSince(transport rafthttp.Transporter, since time.Time, self types.ID, members []*membership.Member) int {

server/etcdserver/util_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ import (
1919
"testing"
2020
"time"
2121

22+
"github.com/stretchr/testify/assert"
2223
"go.uber.org/zap/zaptest"
2324

25+
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
2426
"go.etcd.io/etcd/client/pkg/v3/types"
2527
"go.etcd.io/etcd/server/v3/etcdserver/api/membership"
2628
"go.etcd.io/etcd/server/v3/etcdserver/api/rafthttp"
@@ -110,3 +112,55 @@ type testStringerFunc func() string
110112
func (s testStringerFunc) String() string {
111113
return s()
112114
}
115+
116+
func TestExceedsRequestLimit(t *testing.T) {
117+
tests := []struct {
118+
name string
119+
ci uint64
120+
ai uint64
121+
expectedResult bool
122+
req *pb.InternalRaftRequest
123+
}{
124+
{
125+
ci: 1 + maxGapBetweenApplyAndCommitIndex,
126+
ai: 1,
127+
expectedResult: false,
128+
req: nil,
129+
name: "Test nil InternalRaftRequest",
130+
},
131+
{
132+
ci: 1 + maxGapBetweenApplyAndCommitIndex,
133+
ai: 1,
134+
expectedResult: false,
135+
req: &pb.InternalRaftRequest{},
136+
name: "Test non-critical request and gap is not larger than maxGapBetweenApplyAndCommitIndex",
137+
},
138+
{
139+
ci: 1 + maxGapBetweenApplyAndCommitIndex + 1,
140+
ai: 1,
141+
expectedResult: true,
142+
req: &pb.InternalRaftRequest{},
143+
name: "Test non-critical request and gap is larger than maxGapBetweenApplyAndCommitIndex",
144+
},
145+
{
146+
ci: 1 + maxGapBetweenApplyAndCommitIndex + 1,
147+
ai: 1,
148+
expectedResult: false,
149+
req: &pb.InternalRaftRequest{LeaseRevoke: &pb.LeaseRevokeRequest{}},
150+
name: "Test critical request and gap is larger than maxGapBetweenApplyAndCommitIndex",
151+
},
152+
{
153+
ci: 1 + maxGapBetweenApplyAndCommitIndex + 1 + maxGapBetweenApplyAndCommitIndex/10,
154+
ai: 1,
155+
expectedResult: true,
156+
req: &pb.InternalRaftRequest{LeaseRevoke: &pb.LeaseRevokeRequest{}},
157+
name: "Test critical request and gap is larger than 110% maxGapBetweenApplyAndCommitIndex",
158+
},
159+
}
160+
161+
for _, tc := range tests {
162+
t.Run(tc.name, func(t *testing.T) {
163+
assert.Equal(t, tc.expectedResult, exceedsRequestLimit(tc.ai, tc.ci, tc.req))
164+
})
165+
}
166+
}

server/etcdserver/v3_server.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,8 @@ func (s *EtcdServer) doSerialize(ctx context.Context, chk func(*auth.AuthInfo) e
792792
func (s *EtcdServer) processInternalRaftRequestOnce(ctx context.Context, r pb.InternalRaftRequest) (*apply2.Result, error) {
793793
ai := s.getAppliedIndex()
794794
ci := s.getCommittedIndex()
795-
if ci > ai+maxGapBetweenApplyAndCommitIndex {
795+
796+
if exceedsRequestLimit(ai, ci, &r) {
796797
return nil, errors.ErrTooManyRequests
797798
}
798799

0 commit comments

Comments
 (0)