refactor limiters

This commit is contained in:
vyzo 2022-01-06 12:57:37 +02:00
parent cd110100ca
commit 066de7c0c9
3 changed files with 241 additions and 216 deletions

289
limit.go
View File

@ -4,9 +4,6 @@ import (
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-core/protocol"
"github.com/elastic/gosigar"
"github.com/pbnjay/memory"
)
// Limit is an object that specifies basic resource limits.
@ -28,37 +25,6 @@ type Limiter interface {
GetConnLimits() Limit
}
type BaseLimit struct {
StreamsInbound int
StreamsOutbound int
ConnsInbound int
ConnsOutbound int
FD int
}
// StaticLimit is a limit with static values.
type StaticLimit struct {
BaseLimit
Memory int64
}
var _ Limit = (*StaticLimit)(nil)
// DynamicLimit is a limit with dynamic memory values, based on available memory
type DynamicLimit struct {
BaseLimit
// MinMemory is the minimum memory for this limit
MinMemory int64
// MaxMemory is the maximum memory for this limit
MaxMemory int64
// MemoryFraction is the fraction of available memory allowed for this limit,
// bounded by [MinMemory, MaxMemory]
MemoryFraction int
}
var _ Limit = (*DynamicLimit)(nil)
// BasicLimiter is a limiter with fixed limits.
type BasicLimiter struct {
SystemLimits Limit
@ -75,188 +41,13 @@ type BasicLimiter struct {
var _ Limiter = (*BasicLimiter)(nil)
// NewStaticLimiter creates a limiter with default limits and a system memory cap; if the
// system memory cap is 0, then 1/8th of the total memory is used.
func NewStaticLimiter(memoryCap int64) *BasicLimiter {
if memoryCap == 0 {
memoryCap = int64(memory.TotalMemory() / 8)
}
system := &StaticLimit{
Memory: memoryCap,
BaseLimit: BaseLimit{
StreamsInbound: 4096,
StreamsOutbound: 16384,
ConnsInbound: 256,
ConnsOutbound: 512,
FD: 512,
},
}
transient := &StaticLimit{
Memory: memoryCap / 16,
BaseLimit: BaseLimit{
StreamsInbound: 128,
StreamsOutbound: 512,
ConnsInbound: 32,
ConnsOutbound: 128,
FD: 128,
},
}
svc := &StaticLimit{
Memory: memoryCap / 2,
BaseLimit: BaseLimit{
StreamsInbound: 2048,
StreamsOutbound: 8192,
},
}
proto := &StaticLimit{
Memory: memoryCap / 4,
BaseLimit: BaseLimit{
StreamsInbound: 1024,
StreamsOutbound: 4096,
},
}
peer := &StaticLimit{
Memory: memoryCap / 16,
BaseLimit: BaseLimit{
StreamsInbound: 512,
StreamsOutbound: 2048,
ConnsInbound: 8,
ConnsOutbound: 16,
FD: 8,
},
}
conn := &StaticLimit{
Memory: 16 << 20,
BaseLimit: BaseLimit{
ConnsInbound: 1,
ConnsOutbound: 1,
FD: 1,
},
}
stream := &StaticLimit{
Memory: 16 << 20,
BaseLimit: BaseLimit{
StreamsInbound: 1,
StreamsOutbound: 1,
},
}
return &BasicLimiter{
SystemLimits: system,
TransientLimits: transient,
DefaultServiceLimits: svc,
DefaultProtocolLimits: proto,
DefaultPeerLimits: peer,
ConnLimits: conn,
StreamLimits: stream,
}
}
// NewDynamicLimiter creates a limiter with default limits and a memory cap dynamically computed
// based on available memory. minMemory and maxMemory specify the system memory bounds,
// while memFraction specifies the fraction of available memory available for the system, within
// the specified bounds.
func NewDynamicLimiter(minMemory, maxMemory int64, memFraction int) *BasicLimiter {
system := &DynamicLimit{
MinMemory: minMemory,
MaxMemory: maxMemory,
MemoryFraction: memFraction,
BaseLimit: BaseLimit{
StreamsInbound: 4096,
StreamsOutbound: 16384,
ConnsInbound: 256,
ConnsOutbound: 512,
FD: 512,
},
}
transient := &DynamicLimit{
MinMemory: minMemory / 16,
MaxMemory: maxMemory / 16,
MemoryFraction: memFraction * 16,
BaseLimit: BaseLimit{
StreamsInbound: 128,
StreamsOutbound: 512,
ConnsInbound: 32,
ConnsOutbound: 128,
FD: 128,
},
}
svc := &DynamicLimit{
MinMemory: minMemory / 2,
MaxMemory: maxMemory / 2,
MemoryFraction: memFraction * 2,
BaseLimit: BaseLimit{
StreamsInbound: 2048,
StreamsOutbound: 8192,
},
}
proto := &DynamicLimit{
MinMemory: minMemory / 4,
MaxMemory: maxMemory / 4,
MemoryFraction: memFraction * 4,
BaseLimit: BaseLimit{
StreamsInbound: 1024,
StreamsOutbound: 4096,
},
}
peer := &DynamicLimit{
MinMemory: minMemory / 16,
MaxMemory: maxMemory / 16,
MemoryFraction: memFraction * 16,
BaseLimit: BaseLimit{
StreamsInbound: 512,
StreamsOutbound: 2048,
ConnsInbound: 8,
ConnsOutbound: 16,
FD: 8,
},
}
conn := &StaticLimit{
Memory: 16 << 20,
BaseLimit: BaseLimit{
ConnsInbound: 1,
ConnsOutbound: 1,
FD: 1,
},
}
stream := &StaticLimit{
Memory: 16 << 20,
BaseLimit: BaseLimit{
StreamsInbound: 1,
StreamsOutbound: 1,
},
}
return &BasicLimiter{
SystemLimits: system,
TransientLimits: transient,
DefaultServiceLimits: svc,
DefaultProtocolLimits: proto,
DefaultPeerLimits: peer,
ConnLimits: conn,
StreamLimits: stream,
}
}
func (l *StaticLimit) GetMemoryLimit() int64 {
return l.Memory
}
func (l *DynamicLimit) GetMemoryLimit() int64 {
var mem gosigar.Mem
if err := mem.Get(); err != nil {
panic(err)
}
limit := int64(mem.ActualFree) / int64(l.MemoryFraction)
if limit < l.MinMemory {
limit = l.MinMemory
} else if limit > l.MaxMemory {
limit = l.MaxMemory
}
return limit
// BaseLimit is a mixin type for basic resource limits.
type BaseLimit struct {
StreamsInbound int
StreamsOutbound int
ConnsInbound int
ConnsOutbound int
FD int
}
func (l *BaseLimit) GetStreamLimit(dir network.Direction) int {
@ -318,3 +109,69 @@ func (l *BasicLimiter) GetStreamLimits(p peer.ID) Limit {
func (l *BasicLimiter) GetConnLimits() Limit {
return l.ConnLimits
}
// DefaultSystemBaseLimit returns the default BaseLimit for the System Scope.
func DefaultSystemBaseLimit() BaseLimit {
return BaseLimit{
StreamsInbound: 4096,
StreamsOutbound: 16384,
ConnsInbound: 256,
ConnsOutbound: 512,
FD: 512,
}
}
// DefaultTransientBaseLimit returns the default BaseLimit for the Transient Scope.
func DefaultTransientBaseLimit() BaseLimit {
return BaseLimit{
StreamsInbound: 128,
StreamsOutbound: 512,
ConnsInbound: 32,
ConnsOutbound: 128,
FD: 128,
}
}
// DefaultServiceBaseLimit returns the default BaseLimit for Service Scopes.
func DefaultServiceBaseLimit() BaseLimit {
return BaseLimit{
StreamsInbound: 2048,
StreamsOutbound: 8192,
}
}
// DefaultProtocolBaseLimit returns the default BaseLimit for Protocol Scopes.
func DefaultProtocolBaseLimit() BaseLimit {
return BaseLimit{
StreamsInbound: 1024,
StreamsOutbound: 4096,
}
}
// DefaultPeerBaseLimit returns the default BaseLimit for Peer Scopes.
func DefaultPeerBaseLimit() BaseLimit {
return BaseLimit{
StreamsInbound: 512,
StreamsOutbound: 2048,
ConnsInbound: 8,
ConnsOutbound: 16,
FD: 8,
}
}
// ConnBaseLimit returns the BaseLimit for Connection Scopes.
func ConnBaseLimit() BaseLimit {
return BaseLimit{
ConnsInbound: 1,
ConnsOutbound: 1,
FD: 1,
}
}
// StreamBaseLimit returns the BaseLimit for Stream Scopes.
func StreamBaseLimit() BaseLimit {
return BaseLimit{
StreamsInbound: 1,
StreamsOutbound: 1,
}
}

91
limit_dynamic.go Normal file
View File

@ -0,0 +1,91 @@
package rcmgr
import (
"github.com/elastic/gosigar"
)
// DynamicLimit is a limit with dynamic memory values, based on available (free) memory
type DynamicLimit struct {
BaseLimit
// MinMemory is the minimum memory for this limit
MinMemory int64
// MaxMemory is the maximum memory for this limit
MaxMemory int64
// MemoryFraction is the fraction of available memory allowed for this limit,
// bounded by [MinMemory, MaxMemory]
MemoryFraction float64
}
var _ Limit = (*DynamicLimit)(nil)
func (l *DynamicLimit) GetMemoryLimit() int64 {
var mem gosigar.Mem
if err := mem.Get(); err != nil {
panic(err)
}
limit := int64(float64(mem.ActualFree) * l.MemoryFraction)
if limit < l.MinMemory {
limit = l.MinMemory
} else if limit > l.MaxMemory {
limit = l.MaxMemory
}
return limit
}
// NewDynamicLimiter creates a limiter with default limits and a memory cap dynamically computed
// based on available memory. minMemory and maxMemory specify the system memory bounds,
// while memFraction specifies the fraction of available memory available for the system, within
// the specified bounds.
func NewDynamicLimiter(memFraction float64, minMemory, maxMemory int64) *BasicLimiter {
system := &DynamicLimit{
MinMemory: minMemory,
MaxMemory: maxMemory,
MemoryFraction: memFraction,
BaseLimit: DefaultSystemBaseLimit(),
}
transient := &DynamicLimit{
MinMemory: minMemory / 16,
MaxMemory: maxMemory / 16,
MemoryFraction: memFraction / 16,
BaseLimit: DefaultTransientBaseLimit(),
}
svc := &DynamicLimit{
MinMemory: minMemory / 2,
MaxMemory: maxMemory / 2,
MemoryFraction: memFraction / 2,
BaseLimit: DefaultServiceBaseLimit(),
}
proto := &DynamicLimit{
MinMemory: minMemory / 4,
MaxMemory: maxMemory / 4,
MemoryFraction: memFraction / 4,
BaseLimit: DefaultProtocolBaseLimit(),
}
peer := &DynamicLimit{
MinMemory: minMemory / 16,
MaxMemory: maxMemory / 16,
MemoryFraction: memFraction / 16,
BaseLimit: DefaultPeerBaseLimit(),
}
conn := &StaticLimit{
Memory: 16 << 20,
BaseLimit: ConnBaseLimit(),
}
stream := &StaticLimit{
Memory: 16 << 20,
BaseLimit: StreamBaseLimit(),
}
return &BasicLimiter{
SystemLimits: system,
TransientLimits: transient,
DefaultServiceLimits: svc,
DefaultProtocolLimits: proto,
DefaultPeerLimits: peer,
ConnLimits: conn,
StreamLimits: stream,
}
}

77
limit_static.go Normal file
View File

@ -0,0 +1,77 @@
package rcmgr
import (
"github.com/pbnjay/memory"
)
// StaticLimit is a limit with static values.
type StaticLimit struct {
BaseLimit
Memory int64
}
var _ Limit = (*StaticLimit)(nil)
func (l *StaticLimit) GetMemoryLimit() int64 {
return l.Memory
}
// NewStaticLimiter creates a limiter with default base limits and a system memory cap specified as
// a fraction of total system memory. The assigned memory will not be less than minMemory or more
// than maxMemory.
func NewStaticLimiter(memFraction float64, minMemory, maxMemory int64) *BasicLimiter {
memoryCap := int64(float64(memory.TotalMemory()) * memFraction)
switch {
case memoryCap < minMemory:
memoryCap = minMemory
case memoryCap > maxMemory:
memoryCap = maxMemory
}
return newDefaultStaticLimiter(memoryCap)
}
// NewFixedLimiter creates a limiter with default base limits and a specified system memory cap.
func NewFixedLimiter(memoryCap int64) *BasicLimiter {
return newDefaultStaticLimiter(memoryCap)
}
func newDefaultStaticLimiter(memoryCap int64) *BasicLimiter {
system := &StaticLimit{
Memory: memoryCap,
BaseLimit: DefaultSystemBaseLimit(),
}
transient := &StaticLimit{
Memory: memoryCap / 16,
BaseLimit: DefaultTransientBaseLimit(),
}
svc := &StaticLimit{
Memory: memoryCap / 2,
BaseLimit: DefaultServiceBaseLimit(),
}
proto := &StaticLimit{
Memory: memoryCap / 4,
BaseLimit: DefaultProtocolBaseLimit(),
}
peer := &StaticLimit{
Memory: memoryCap / 16,
BaseLimit: DefaultPeerBaseLimit(),
}
conn := &StaticLimit{
Memory: 16 << 20,
BaseLimit: ConnBaseLimit(),
}
stream := &StaticLimit{
Memory: 16 << 20,
BaseLimit: StreamBaseLimit(),
}
return &BasicLimiter{
SystemLimits: system,
TransientLimits: transient,
DefaultServiceLimits: svc,
DefaultProtocolLimits: proto,
DefaultPeerLimits: peer,
ConnLimits: conn,
StreamLimits: stream,
}
}