-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Pattern ingesters add a limiter for high eviction rate (#13464)
- Loading branch information
1 parent
845359d
commit e08b4a7
Showing
13 changed files
with
210 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package drain | ||
|
||
import ( | ||
"time" | ||
) | ||
|
||
type limiter struct { | ||
added int64 | ||
evicted int64 | ||
maxPercentage float64 | ||
blockedUntil time.Time | ||
} | ||
|
||
func newLimiter(maxPercentage float64) *limiter { | ||
return &limiter{ | ||
maxPercentage: maxPercentage, | ||
} | ||
} | ||
|
||
func (l *limiter) Allow() bool { | ||
if !l.blockedUntil.IsZero() { | ||
if time.Now().Before(l.blockedUntil) { | ||
return false | ||
} | ||
l.reset() | ||
} | ||
if l.added == 0 { | ||
l.added++ | ||
return true | ||
} | ||
if float64(l.evicted)/float64(l.added) > l.maxPercentage { | ||
l.block() | ||
return false | ||
} | ||
l.added++ | ||
return true | ||
} | ||
|
||
func (l *limiter) Evict() { | ||
l.evicted++ | ||
} | ||
|
||
func (l *limiter) reset() { | ||
l.added = 0 | ||
l.evicted = 0 | ||
l.blockedUntil = time.Time{} | ||
} | ||
|
||
func (l *limiter) block() { | ||
l.blockedUntil = time.Now().Add(10 * time.Minute) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package drain | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestNewLimiter(t *testing.T) { | ||
maxPercentage := 0.5 | ||
l := newLimiter(maxPercentage) | ||
require.NotNil(t, l, "expected non-nil limiter") | ||
require.Equal(t, maxPercentage, l.maxPercentage, "expected maxPercentage to match") | ||
require.Equal(t, int64(0), l.added, "expected added to be 0") | ||
require.Equal(t, int64(0), l.evicted, "expected evicted to be 0") | ||
require.True(t, l.blockedUntil.IsZero(), "expected blockedUntil to be zero") | ||
} | ||
|
||
func TestLimiterAllow(t *testing.T) { | ||
maxPercentage := 0.5 | ||
l := newLimiter(maxPercentage) | ||
|
||
// Test allowing when no evictions | ||
require.True(t, l.Allow(), "expected Allow to return true initially") | ||
|
||
// Test allowing until evictions exceed maxPercentage | ||
for i := 0; i < 2; i++ { | ||
require.True(t, l.Allow(), "expected Allow to return true %d", i) | ||
l.Evict() | ||
} | ||
|
||
// Evict to exceed maxPercentage | ||
l.Evict() | ||
require.False(t, l.Allow(), "expected Allow to return false after evictions exceed maxPercentage") | ||
|
||
// Test blocking time | ||
require.False(t, l.blockedUntil.IsZero(), "expected blockedUntil to be set") | ||
|
||
// Fast forward time to simulate block duration passing | ||
l.blockedUntil = time.Now().Add(-1 * time.Minute) | ||
require.True(t, l.Allow(), "expected Allow to return true after block duration") | ||
} | ||
|
||
func TestLimiterEvict(t *testing.T) { | ||
l := newLimiter(0.5) | ||
l.Evict() | ||
require.Equal(t, int64(1), l.evicted, "expected evicted to be 1") | ||
l.Evict() | ||
require.Equal(t, int64(2), l.evicted, "expected evicted to be 2") | ||
} | ||
|
||
func TestLimiterReset(t *testing.T) { | ||
l := newLimiter(0.5) | ||
l.added = 10 | ||
l.evicted = 5 | ||
l.blockedUntil = time.Now().Add(10 * time.Minute) | ||
l.reset() | ||
require.Equal(t, int64(0), l.added, "expected added to be 0") | ||
require.Equal(t, int64(0), l.evicted, "expected evicted to be 0") | ||
require.True(t, l.blockedUntil.IsZero(), "expected blockedUntil to be zero") | ||
} | ||
|
||
func TestLimiterBlock(t *testing.T) { | ||
l := newLimiter(0.5) | ||
l.block() | ||
require.False(t, l.blockedUntil.IsZero(), "expected blockedUntil to be set") | ||
require.False(t, l.Allow()) | ||
require.True(t, l.blockedUntil.After(time.Now()), "expected blockedUntil to be in the future") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.