Skip to content

Commit e477efd

Browse files
use autoscaling limits (#1637)
1 parent 19090e5 commit e477efd

File tree

5 files changed

+134
-153
lines changed

5 files changed

+134
-153
lines changed

defaults.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,17 @@ var DefaultEnableRelay = func(cfg *Config) error {
8787

8888
var DefaultResourceManager = func(cfg *Config) error {
8989
// Default memory limit: 1/8th of total memory, minimum 128MB, maximum 1GB
90-
limiter := rcmgr.NewDefaultLimiter()
91-
SetDefaultServiceLimits(limiter)
92-
93-
mgr, err := rcmgr.NewResourceManager(limiter)
90+
limits := rcmgr.DefaultLimits
91+
SetDefaultServiceLimits(&limits)
92+
mgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(limits.AutoScale()))
9493
if err != nil {
9594
return err
9695
}
9796

9897
return cfg.Apply(ResourceManager(mgr))
9998
}
10099

101-
// DefaultConnManager creates a default connection manager
100+
// DefaultConnectionManager creates a default connection manager
102101
var DefaultConnectionManager = func(cfg *Config) error {
103102
mgr, err := connmgr.NewConnManager(160, 192)
104103
if err != nil {

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ require (
2222
github.com/libp2p/go-libp2p-asn-util v0.2.0
2323
github.com/libp2p/go-libp2p-core v0.19.0
2424
github.com/libp2p/go-libp2p-peerstore v0.7.1
25-
github.com/libp2p/go-libp2p-resource-manager v0.4.0
25+
github.com/libp2p/go-libp2p-resource-manager v0.5.0
2626
github.com/libp2p/go-libp2p-testing v0.10.0
2727
github.com/libp2p/go-mplex v0.7.0
2828
github.com/libp2p/go-msgio v0.2.0

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,8 @@ github.com/libp2p/go-libp2p-core v0.19.0 h1:KDw7hanmh0EuVdZqsHCAzmkdiYMk5uR5h0UG
362362
github.com/libp2p/go-libp2p-core v0.19.0/go.mod h1:AkA+FUKQfYt1FLNef5fOPlo/naAWjKy/RCjkcPjqzYg=
363363
github.com/libp2p/go-libp2p-peerstore v0.7.1 h1:7FpALlqR+3+oOBXdzm3AVt0vjMYLW1b7jM03E4iEHlw=
364364
github.com/libp2p/go-libp2p-peerstore v0.7.1/go.mod h1:cdUWTHro83vpg6unCpGUr8qJoX3e93Vy8o97u5ppIM0=
365-
github.com/libp2p/go-libp2p-resource-manager v0.4.0 h1:+/gSDLSJ+n8qHVdMoY7wfrk3EvvL9Ktw6sAyKKZPQRw=
366-
github.com/libp2p/go-libp2p-resource-manager v0.4.0/go.mod h1:+5QPxFLRXYlRDZ0P1bPKE7zyZDvex5TLVOqePwRmwfc=
365+
github.com/libp2p/go-libp2p-resource-manager v0.5.0 h1:se7dW2dCpa+KISlxmKCK2hCzOTtxCmdt/9b16KFKhbk=
366+
github.com/libp2p/go-libp2p-resource-manager v0.5.0/go.mod h1:CggtV6EZb+Y0dGh41q5ezO4udcVKyhcEFpydHD8EMe0=
367367
github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
368368
github.com/libp2p/go-libp2p-testing v0.10.0 h1:LO7wuUPPNAe1D1s0HZ+9WoROaGIn/MEl1wtugXuTRzg=
369369
github.com/libp2p/go-libp2p-testing v0.10.0/go.mod h1:jJ4fiJwyZ3UlPTLcnz/sEmPPSviQ79Q0MVD/CykzrP0=

limits.go

+93-122
Original file line numberDiff line numberDiff line change
@@ -15,143 +15,114 @@ import (
1515
)
1616

1717
// SetDefaultServiceLimits sets the default limits for bundled libp2p services
18-
//
19-
// More specifically this sets the following limits:
20-
// - identify:
21-
// 128 streams in, 128 streams out, 256 streams total, 4MB min, 64MB max svc memory
22-
// 16/16/32 streams per peer
23-
// - ping:
24-
// 128 streams in, 128 sreams out, 256 streasms total, 4MB min, 64MB max svc memory
25-
// 2/3/4 streams per peer
26-
// - autonat
27-
// 128 streams in, 128 streams out, 128 streams total, 4MB min, 64MB max svc memory
28-
// 2/2/2 streams per peer
29-
// - holepunch
30-
// 128 streams in, 128 streams out, 128 streams total, 4MB min, 64MB max svc memory
31-
// 2/2/2 streams per peer
32-
// - relay v1 and v2 (separate services)
33-
// 1024 streams in, 1024 streams out, 1024 streams total, 4MB min, 64MB max svc memory
34-
// 64/64/64 streams per peer
35-
func SetDefaultServiceLimits(limiter *rcmgr.BasicLimiter) {
36-
if limiter.ServiceLimits == nil {
37-
limiter.ServiceLimits = make(map[string]rcmgr.Limit)
38-
}
39-
if limiter.ServicePeerLimits == nil {
40-
limiter.ServicePeerLimits = make(map[string]rcmgr.Limit)
41-
}
42-
if limiter.ProtocolLimits == nil {
43-
limiter.ProtocolLimits = make(map[protocol.ID]rcmgr.Limit)
44-
}
45-
if limiter.ProtocolPeerLimits == nil {
46-
limiter.ProtocolPeerLimits = make(map[protocol.ID]rcmgr.Limit)
47-
}
48-
18+
func SetDefaultServiceLimits(config *rcmgr.ScalingLimitConfig) {
4919
// identify
50-
setServiceLimits(limiter, identify.ServiceName,
51-
limiter.DefaultServiceLimits.
52-
WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory
53-
WithStreamLimit(128, 128, 256), // max 256 streams -- symmetric
54-
peerLimit(16, 16, 32))
55-
56-
setProtocolLimits(limiter, identify.ID,
57-
limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 32<<20),
58-
peerLimit(16, 16, 32))
59-
setProtocolLimits(limiter, identify.IDPush,
60-
limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 32<<20),
61-
peerLimit(16, 16, 32))
62-
setProtocolLimits(limiter, identify.IDDelta,
63-
limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 32<<20),
64-
peerLimit(16, 16, 32))
20+
config.AddServiceLimit(
21+
identify.ServiceName,
22+
rcmgr.BaseLimit{StreamsInbound: 64, StreamsOutbound: 64, Streams: 128, Memory: 4 << 20},
23+
rcmgr.BaseLimitIncrease{StreamsInbound: 64, StreamsOutbound: 64, Streams: 128, Memory: 4 << 20},
24+
)
25+
config.AddServicePeerLimit(
26+
identify.ServiceName,
27+
rcmgr.BaseLimit{StreamsInbound: 16, StreamsOutbound: 16, Streams: 32, Memory: 1 << 20},
28+
rcmgr.BaseLimitIncrease{},
29+
)
30+
for _, id := range [...]protocol.ID{identify.ID, identify.IDDelta, identify.IDPush} {
31+
config.AddProtocolLimit(
32+
id,
33+
rcmgr.BaseLimit{StreamsInbound: 64, StreamsOutbound: 64, Streams: 128, Memory: 4 << 20},
34+
rcmgr.BaseLimitIncrease{StreamsInbound: 64, StreamsOutbound: 64, Streams: 128, Memory: 4 << 20},
35+
)
36+
config.AddProtocolPeerLimit(
37+
id,
38+
rcmgr.BaseLimit{StreamsInbound: 16, StreamsOutbound: 16, Streams: 32, Memory: 32 * (256<<20 + 16<<10)},
39+
rcmgr.BaseLimitIncrease{},
40+
)
41+
}
6542

66-
// ping
67-
setServiceLimits(limiter, ping.ServiceName,
68-
limiter.DefaultServiceLimits.
69-
WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory
70-
WithStreamLimit(128, 128, 128), // max 128 streams - asymmetric
71-
peerLimit(2, 3, 4))
72-
setProtocolLimits(limiter, ping.ID,
73-
limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 64<<20),
74-
peerLimit(2, 3, 4))
43+
// ping
44+
addServiceAndProtocolLimit(config,
45+
ping.ServiceName, ping.ID,
46+
rcmgr.BaseLimit{StreamsInbound: 64, StreamsOutbound: 64, Streams: 64, Memory: 4 << 20},
47+
rcmgr.BaseLimitIncrease{StreamsInbound: 64, StreamsOutbound: 64, Streams: 64, Memory: 4 << 20},
48+
)
49+
addServicePeerAndProtocolPeerLimit(
50+
config,
51+
ping.ServiceName, ping.ID,
52+
rcmgr.BaseLimit{StreamsInbound: 2, StreamsOutbound: 3, Streams: 4, Memory: 32 * (256<<20 + 16<<10)},
53+
rcmgr.BaseLimitIncrease{},
54+
)
7555

7656
// autonat
77-
setServiceLimits(limiter, autonat.ServiceName,
78-
limiter.DefaultServiceLimits.
79-
WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory
80-
WithStreamLimit(128, 128, 128), // max 128 streams - asymmetric
81-
peerLimit(2, 2, 2))
82-
setProtocolLimits(limiter, autonat.AutoNATProto,
83-
limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 64<<20),
84-
peerLimit(2, 2, 2))
57+
addServiceAndProtocolLimit(config,
58+
autonat.ServiceName, autonat.AutoNATProto,
59+
rcmgr.BaseLimit{StreamsInbound: 64, StreamsOutbound: 64, Streams: 64, Memory: 4 << 20},
60+
rcmgr.BaseLimitIncrease{StreamsInbound: 4, StreamsOutbound: 4, Streams: 4, Memory: 2 << 20},
61+
)
62+
addServicePeerAndProtocolPeerLimit(
63+
config,
64+
autonat.ServiceName, autonat.AutoNATProto,
65+
rcmgr.BaseLimit{StreamsInbound: 2, StreamsOutbound: 2, Streams: 2, Memory: 1 << 20},
66+
rcmgr.BaseLimitIncrease{},
67+
)
8568

8669
// holepunch
87-
setServiceLimits(limiter, holepunch.ServiceName,
88-
limiter.DefaultServiceLimits.
89-
WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory
90-
WithStreamLimit(128, 128, 256), // max 256 streams - symmetric
91-
peerLimit(2, 2, 2))
92-
setProtocolLimits(limiter, holepunch.Protocol,
93-
limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 64<<20),
94-
peerLimit(2, 2, 2))
70+
addServiceAndProtocolLimit(config,
71+
holepunch.ServiceName, holepunch.Protocol,
72+
rcmgr.BaseLimit{StreamsInbound: 32, StreamsOutbound: 32, Streams: 64, Memory: 4 << 20},
73+
rcmgr.BaseLimitIncrease{StreamsInbound: 8, StreamsOutbound: 8, Streams: 16, Memory: 4 << 20},
74+
)
75+
addServicePeerAndProtocolPeerLimit(config,
76+
holepunch.ServiceName, holepunch.Protocol,
77+
rcmgr.BaseLimit{StreamsInbound: 2, StreamsOutbound: 2, Streams: 2, Memory: 1 << 20},
78+
rcmgr.BaseLimitIncrease{},
79+
)
9580

9681
// relay/v1
97-
setServiceLimits(limiter, relayv1.ServiceName,
98-
limiter.DefaultServiceLimits.
99-
WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory
100-
WithStreamLimit(1024, 1024, 1024), // max 1024 streams - asymmetric
101-
peerLimit(64, 64, 64))
82+
config.AddServiceLimit(
83+
relayv1.ServiceName,
84+
rcmgr.BaseLimit{StreamsInbound: 256, StreamsOutbound: 256, Streams: 256, Memory: 16 << 20},
85+
rcmgr.BaseLimitIncrease{StreamsInbound: 256, StreamsOutbound: 256, Streams: 256, Memory: 16 << 20},
86+
)
87+
config.AddServicePeerLimit(
88+
relayv1.ServiceName,
89+
rcmgr.BaseLimit{StreamsInbound: 64, StreamsOutbound: 64, Streams: 64, Memory: 1 << 20},
90+
rcmgr.BaseLimitIncrease{},
91+
)
10292

10393
// relay/v2
104-
setServiceLimits(limiter, relayv2.ServiceName,
105-
limiter.DefaultServiceLimits.
106-
WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory
107-
WithStreamLimit(1024, 1024, 1024), // max 1024 streams - asymmetric
108-
peerLimit(64, 64, 64))
94+
config.AddServiceLimit(
95+
relayv2.ServiceName,
96+
rcmgr.BaseLimit{StreamsInbound: 256, StreamsOutbound: 256, Streams: 256, Memory: 16 << 20},
97+
rcmgr.BaseLimitIncrease{StreamsInbound: 256, StreamsOutbound: 256, Streams: 256, Memory: 16 << 20},
98+
)
99+
config.AddServicePeerLimit(
100+
relayv2.ServiceName,
101+
rcmgr.BaseLimit{StreamsInbound: 64, StreamsOutbound: 64, Streams: 64, Memory: 1 << 20},
102+
rcmgr.BaseLimitIncrease{},
103+
)
109104

110105
// circuit protocols, both client and service
111-
setProtocolLimits(limiter, circuit.ProtoIDv1,
112-
limiter.DefaultProtocolLimits.
113-
WithMemoryLimit(1, 4<<20, 64<<20).
114-
WithStreamLimit(1280, 1280, 1280),
115-
peerLimit(128, 128, 128))
116-
setProtocolLimits(limiter, circuit.ProtoIDv2Hop,
117-
limiter.DefaultProtocolLimits.
118-
WithMemoryLimit(1, 4<<20, 64<<20).
119-
WithStreamLimit(1280, 1280, 1280),
120-
peerLimit(128, 128, 128))
121-
setProtocolLimits(limiter, circuit.ProtoIDv2Stop,
122-
limiter.DefaultProtocolLimits.
123-
WithMemoryLimit(1, 4<<20, 64<<20).
124-
WithStreamLimit(1280, 1280, 1280),
125-
peerLimit(128, 128, 128))
126-
127-
}
128-
129-
func setServiceLimits(limiter *rcmgr.BasicLimiter, svc string, limit rcmgr.Limit, peerLimit rcmgr.Limit) {
130-
if _, ok := limiter.ServiceLimits[svc]; !ok {
131-
limiter.ServiceLimits[svc] = limit
132-
}
133-
if _, ok := limiter.ServicePeerLimits[svc]; !ok {
134-
limiter.ServicePeerLimits[svc] = peerLimit
106+
for _, proto := range [...]protocol.ID{circuit.ProtoIDv1, circuit.ProtoIDv2Hop, circuit.ProtoIDv2Stop} {
107+
config.AddProtocolLimit(
108+
proto,
109+
rcmgr.BaseLimit{StreamsInbound: 640, StreamsOutbound: 640, Streams: 640, Memory: 16 << 20},
110+
rcmgr.BaseLimitIncrease{StreamsInbound: 640, StreamsOutbound: 640, Streams: 640, Memory: 16 << 20},
111+
)
112+
config.AddProtocolPeerLimit(
113+
proto,
114+
rcmgr.BaseLimit{StreamsInbound: 128, StreamsOutbound: 128, Streams: 128, Memory: 32 << 20},
115+
rcmgr.BaseLimitIncrease{},
116+
)
135117
}
136118
}
137119

138-
func setProtocolLimits(limiter *rcmgr.BasicLimiter, proto protocol.ID, limit rcmgr.Limit, peerLimit rcmgr.Limit) {
139-
if _, ok := limiter.ProtocolLimits[proto]; !ok {
140-
limiter.ProtocolLimits[proto] = limit
141-
}
142-
if _, ok := limiter.ProtocolPeerLimits[proto]; !ok {
143-
limiter.ProtocolPeerLimits[proto] = peerLimit
144-
}
120+
func addServiceAndProtocolLimit(config *rcmgr.ScalingLimitConfig, service string, proto protocol.ID, limit rcmgr.BaseLimit, increase rcmgr.BaseLimitIncrease) {
121+
config.AddServiceLimit(service, limit, increase)
122+
config.AddProtocolLimit(proto, limit, increase)
145123
}
146124

147-
func peerLimit(numStreamsIn, numStreamsOut, numStreamsTotal int) rcmgr.Limit {
148-
return &rcmgr.StaticLimit{
149-
// memory: 256kb for window buffers plus some change for message buffers per stream
150-
Memory: int64(numStreamsTotal * (256<<10 + 16384)),
151-
BaseLimit: rcmgr.BaseLimit{
152-
StreamsInbound: numStreamsIn,
153-
StreamsOutbound: numStreamsOut,
154-
Streams: numStreamsTotal,
155-
},
156-
}
125+
func addServicePeerAndProtocolPeerLimit(config *rcmgr.ScalingLimitConfig, service string, proto protocol.ID, limit rcmgr.BaseLimit, increase rcmgr.BaseLimitIncrease) {
126+
config.AddServicePeerLimit(service, limit, increase)
127+
config.AddProtocolPeerLimit(proto, limit, increase)
157128
}

p2p/test/resource-manager/rcmgr_test.go

+34-23
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,15 @@ import (
1818
"github.com/stretchr/testify/require"
1919
)
2020

21-
func makeRcmgrOption(t *testing.T, limiter *rcmgr.BasicLimiter, test string) func(int) libp2p.Option {
21+
func makeRcmgrOption(t *testing.T, cfg rcmgr.LimitConfig, test string) func(int) libp2p.Option {
2222
return func(i int) libp2p.Option {
2323
var opts []rcmgr.Option
24-
2524
if os.Getenv("LIBP2P_TEST_RCMGR_TRACE") == "1" {
2625
opts = append(opts, rcmgr.WithTrace(fmt.Sprintf("%s-%d.json.gz", test, i)))
2726
}
2827

29-
mgr, err := rcmgr.NewResourceManager(limiter, opts...)
30-
if err != nil {
31-
t.Fatal(err)
32-
}
28+
mgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(cfg), opts...)
29+
require.NoError(t, err)
3330
return libp2p.ResourceManager(mgr)
3431
}
3532
}
@@ -50,11 +47,15 @@ func waitForConnection(t *testing.T, src, dest *Echo) {
5047
func TestResourceManagerConnInbound(t *testing.T) {
5148
// this test checks that we can not exceed the inbound conn limit at system level
5249
// we specify: 1 conn per peer, 3 conns total, and we try to create 4 conns
53-
limiter := rcmgr.NewDefaultLimiter()
54-
limiter.SystemLimits = limiter.SystemLimits.WithConnLimit(3, 1024, 1024)
55-
limiter.DefaultPeerLimits = limiter.DefaultPeerLimits.WithConnLimit(1, 1, 1)
56-
57-
echos := createEchos(t, 5, makeRcmgrOption(t, limiter, "TestResourceManagerConnInbound"))
50+
cfg := rcmgr.DefaultLimits.AutoScale()
51+
cfg.System.ConnsInbound = 3
52+
cfg.System.ConnsOutbound = 1024
53+
cfg.System.Conns = 1024
54+
cfg.PeerDefault.Conns = 1
55+
cfg.PeerDefault.ConnsInbound = 1
56+
cfg.PeerDefault.ConnsOutbound = 1
57+
58+
echos := createEchos(t, 5, makeRcmgrOption(t, cfg, "TestResourceManagerConnInbound"))
5859
defer closeEchos(echos)
5960
defer closeRcmgrs(echos)
6061

@@ -82,10 +83,14 @@ func TestResourceManagerConnInbound(t *testing.T) {
8283
func TestResourceManagerConnOutbound(t *testing.T) {
8384
// this test checks that we can not exceed the inbound conn limit at system level
8485
// we specify: 1 conn per peer, 3 conns total, and we try to create 4 conns
85-
limiter := rcmgr.NewDefaultLimiter()
86-
limiter.SystemLimits = limiter.SystemLimits.WithConnLimit(1024, 3, 1024)
87-
limiter.DefaultPeerLimits = limiter.DefaultPeerLimits.WithConnLimit(1, 1, 1)
88-
echos := createEchos(t, 5, makeRcmgrOption(t, limiter, "TestResourceManagerConnOutbound"))
86+
cfg := rcmgr.DefaultLimits.AutoScale()
87+
cfg.System.ConnsInbound = 1024
88+
cfg.System.ConnsOutbound = 3
89+
cfg.System.Conns = 1024
90+
cfg.PeerDefault.Conns = 1
91+
cfg.PeerDefault.ConnsInbound = 1
92+
cfg.PeerDefault.ConnsOutbound = 1
93+
echos := createEchos(t, 5, makeRcmgrOption(t, cfg, "TestResourceManagerConnOutbound"))
8994
defer closeEchos(echos)
9095
defer closeRcmgrs(echos)
9196

@@ -113,9 +118,11 @@ func TestResourceManagerConnOutbound(t *testing.T) {
113118
func TestResourceManagerServiceInbound(t *testing.T) {
114119
// this test checks that we can not exceed the inbound stream limit at service level
115120
// we specify: 3 streams for the service, and we try to create 4 streams
116-
limiter := rcmgr.NewDefaultLimiter()
117-
limiter.DefaultServiceLimits = limiter.DefaultServiceLimits.WithStreamLimit(3, 1024, 1024)
118-
echos := createEchos(t, 5, makeRcmgrOption(t, limiter, "TestResourceManagerServiceInbound"))
121+
cfg := rcmgr.DefaultLimits.AutoScale()
122+
cfg.ServiceDefault.StreamsInbound = 3
123+
cfg.ServiceDefault.StreamsOutbound = 1024
124+
cfg.ServiceDefault.Streams = 1024
125+
echos := createEchos(t, 5, makeRcmgrOption(t, cfg, "TestResourceManagerServiceInbound"))
119126
defer closeEchos(echos)
120127
defer closeRcmgrs(echos)
121128

@@ -164,11 +171,15 @@ func TestResourceManagerServiceInbound(t *testing.T) {
164171
func TestResourceManagerServicePeerInbound(t *testing.T) {
165172
// this test checks that we cannot exceed the per peer inbound stream limit at service level
166173
// we specify: 2 streams per peer for echo, and we try to create 3 streams
167-
limiter := rcmgr.NewDefaultLimiter()
168-
limiter.ServicePeerLimits = map[string]rcmgr.Limit{
169-
EchoService: limiter.DefaultPeerLimits.WithStreamLimit(2, 1024, 1024),
170-
}
171-
echos := createEchos(t, 5, makeRcmgrOption(t, limiter, "TestResourceManagerServicePeerInbound"))
174+
cfg := rcmgr.DefaultLimits
175+
cfg.AddServicePeerLimit(
176+
EchoService,
177+
rcmgr.BaseLimit{StreamsInbound: 2, StreamsOutbound: 1024, Streams: 1024, Memory: 9999999},
178+
rcmgr.BaseLimitIncrease{},
179+
)
180+
limits := cfg.AutoScale()
181+
182+
echos := createEchos(t, 5, makeRcmgrOption(t, limits, "TestResourceManagerServicePeerInbound"))
172183
defer closeEchos(echos)
173184
defer closeRcmgrs(echos)
174185

0 commit comments

Comments
 (0)