kubo/core/node/libp2p/rcmgr_metrics.go
Marten Seemann 514411bedb
feat: opt-in Swarm.ResourceMgr (go-libp2p v0.18) (#8680)
* update go-libp2p to v0.18.0

* initialize the resource manager

* add resource manager stats/limit commands

* load limit file when building resource manager

* log absent limit file

* write rcmgr to file when IPFS_DEBUG_RCMGR is set

* fix: mark swarm limit|stats as experimental

* feat(cfg): opt-in Swarm.ResourceMgr

This ensures we can safely test the resource manager without impacting
default behavior.

- Resource manager is disabled by default
    - Default for Swarm.ResourceMgr.Enabled is false for now
- Swarm.ResourceMgr.Limits allows user to tweak limits per specific
  scope in a way that is persisted across restarts
- 'ipfs swarm limit system' outputs human-readable json
- 'ipfs swarm limit system new-limits.json' sets new runtime limits
  (but does not change Swarm.ResourceMgr.Limits in the config)

Conventions to make libp2p devs life easier:
- 'IPFS_RCMGR=1 ipfs daemon' overrides the config and enables resource manager
- 'limit.json' overrides implicit defaults from libp2p (if present)

* docs(config): small tweaks

* fix: skip libp2p.ResourceManager if disabled

This ensures 'ipfs swarm limit|stats' work only when enabled.

* fix: use NullResourceManager when disabled

This reverts commit b19f7c9eca.
after clarification feedback from
https://github.com/ipfs/go-ipfs/pull/8680#discussion_r841680182

* style: rename IPFS_RCMGR to LIBP2P_RCMGR

preexisting libp2p toggles use LIBP2P_ prefix

* test: Swarm.ResourceMgr

* fix: location of opt-in limit.json and rcmgr.json.gz

Places these files inside of IPFS_PATH

* Update docs/config.md

* feat: expose rcmgr metrics when enabled (#8785)

* add metrics for the resource manager
* export protocol and service name in Prometheus metrics
* fix: expose rcmgr metrics only when enabled

Co-authored-by: Marcin Rataj <lidel@lidel.org>

* refactor: rcmgr_metrics.go

* refactor: rcmgr_defaults.go

This file defines implicit limit defaults used when Swarm.ResourceMgr.Enabled

We keep vendored copy to ensure go-ipfs is not impacted when go-libp2p
decides to change defaults in any of the future releases.

* refactor: adjustedDefaultLimits

Cleans up the way we initialize defaults and adds a fix for case
when connection manager runs with high limits.

It also hides `Swarm.ResourceMgr.Limits` until we have a better
understanding what syntax makes sense.

* chore: cleanup after a review

* fix: restore go-ipld-prime v0.14.2

* fix: restore go-ds-flatfs v0.5.1

Co-authored-by: Lucas Molas <schomatis@gmail.com>
Co-authored-by: Marcin Rataj <lidel@lidel.org>
2022-04-07 21:06:35 -04:00

240 lines
6.2 KiB
Go

package libp2p
import (
"strconv"
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-core/protocol"
rcmgr "github.com/libp2p/go-libp2p-resource-manager"
"github.com/prometheus/client_golang/prometheus"
)
func createRcmgrMetrics() rcmgr.MetricsReporter {
const (
direction = "direction"
usesFD = "usesFD"
protocol = "protocol"
service = "service"
)
connAllowed := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "libp2p_rcmgr_conns_allowed_total",
Help: "allowed connections",
},
[]string{direction, usesFD},
)
prometheus.MustRegister(connAllowed)
connBlocked := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "libp2p_rcmgr_conns_blocked_total",
Help: "blocked connections",
},
[]string{direction, usesFD},
)
prometheus.MustRegister(connBlocked)
streamAllowed := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "libp2p_rcmgr_streams_allowed_total",
Help: "allowed streams",
},
[]string{direction},
)
prometheus.MustRegister(streamAllowed)
streamBlocked := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "libp2p_rcmgr_streams_blocked_total",
Help: "blocked streams",
},
[]string{direction},
)
prometheus.MustRegister(streamBlocked)
peerAllowed := prometheus.NewCounter(prometheus.CounterOpts{
Name: "libp2p_rcmgr_peers_allowed_total",
Help: "allowed peers",
})
prometheus.MustRegister(peerAllowed)
peerBlocked := prometheus.NewCounter(prometheus.CounterOpts{
Name: "libp2p_rcmgr_peer_blocked_total",
Help: "blocked peers",
})
prometheus.MustRegister(peerBlocked)
protocolAllowed := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "libp2p_rcmgr_protocols_allowed_total",
Help: "allowed streams attached to a protocol",
},
[]string{protocol},
)
prometheus.MustRegister(protocolAllowed)
protocolBlocked := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "libp2p_rcmgr_protocols_blocked_total",
Help: "blocked streams attached to a protocol",
},
[]string{protocol},
)
prometheus.MustRegister(protocolBlocked)
protocolPeerBlocked := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "libp2p_rcmgr_protocols_for_peer_blocked_total",
Help: "blocked streams attached to a protocol for a specific peer",
},
[]string{protocol},
)
prometheus.MustRegister(protocolPeerBlocked)
serviceAllowed := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "libp2p_rcmgr_services_allowed_total",
Help: "allowed streams attached to a service",
},
[]string{service},
)
prometheus.MustRegister(serviceAllowed)
serviceBlocked := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "libp2p_rcmgr_services_blocked_total",
Help: "blocked streams attached to a service",
},
[]string{service},
)
prometheus.MustRegister(serviceBlocked)
servicePeerBlocked := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "libp2p_rcmgr_service_for_peer_blocked_total",
Help: "blocked streams attached to a service for a specific peer",
},
[]string{service},
)
prometheus.MustRegister(servicePeerBlocked)
memoryAllowed := prometheus.NewCounter(prometheus.CounterOpts{
Name: "libp2p_rcmgr_memory_allocations_allowed_total",
Help: "allowed memory allocations",
})
prometheus.MustRegister(memoryAllowed)
memoryBlocked := prometheus.NewCounter(prometheus.CounterOpts{
Name: "libp2p_rcmgr_memory_allocations_blocked_total",
Help: "blocked memory allocations",
})
prometheus.MustRegister(memoryBlocked)
return rcmgrMetrics{
connAllowed,
connBlocked,
streamAllowed,
streamBlocked,
peerAllowed,
peerBlocked,
protocolAllowed,
protocolBlocked,
protocolPeerBlocked,
serviceAllowed,
serviceBlocked,
servicePeerBlocked,
memoryAllowed,
memoryBlocked,
}
}
// Failsafe to ensure interface from go-libp2p-resource-manager is implemented
var _ rcmgr.MetricsReporter = rcmgrMetrics{}
type rcmgrMetrics struct {
connAllowed *prometheus.CounterVec
connBlocked *prometheus.CounterVec
streamAllowed *prometheus.CounterVec
streamBlocked *prometheus.CounterVec
peerAllowed prometheus.Counter
peerBlocked prometheus.Counter
protocolAllowed *prometheus.CounterVec
protocolBlocked *prometheus.CounterVec
protocolPeerBlocked *prometheus.CounterVec
serviceAllowed *prometheus.CounterVec
serviceBlocked *prometheus.CounterVec
servicePeerBlocked *prometheus.CounterVec
memoryAllowed prometheus.Counter
memoryBlocked prometheus.Counter
}
func getDirection(d network.Direction) string {
switch d {
default:
return ""
case network.DirInbound:
return "inbound"
case network.DirOutbound:
return "outbound"
}
}
func (r rcmgrMetrics) AllowConn(dir network.Direction, usefd bool) {
r.connAllowed.WithLabelValues(getDirection(dir), strconv.FormatBool(usefd)).Inc()
}
func (r rcmgrMetrics) BlockConn(dir network.Direction, usefd bool) {
r.connBlocked.WithLabelValues(getDirection(dir), strconv.FormatBool(usefd)).Inc()
}
func (r rcmgrMetrics) AllowStream(_ peer.ID, dir network.Direction) {
r.streamAllowed.WithLabelValues(getDirection(dir)).Inc()
}
func (r rcmgrMetrics) BlockStream(_ peer.ID, dir network.Direction) {
r.streamBlocked.WithLabelValues(getDirection(dir)).Inc()
}
func (r rcmgrMetrics) AllowPeer(_ peer.ID) {
r.peerAllowed.Inc()
}
func (r rcmgrMetrics) BlockPeer(_ peer.ID) {
r.peerBlocked.Inc()
}
func (r rcmgrMetrics) AllowProtocol(proto protocol.ID) {
r.protocolAllowed.WithLabelValues(string(proto)).Inc()
}
func (r rcmgrMetrics) BlockProtocol(proto protocol.ID) {
r.protocolBlocked.WithLabelValues(string(proto)).Inc()
}
func (r rcmgrMetrics) BlockProtocolPeer(proto protocol.ID, _ peer.ID) {
r.protocolPeerBlocked.WithLabelValues(string(proto)).Inc()
}
func (r rcmgrMetrics) AllowService(svc string) {
r.serviceAllowed.WithLabelValues(svc).Inc()
}
func (r rcmgrMetrics) BlockService(svc string) {
r.serviceBlocked.WithLabelValues(svc).Inc()
}
func (r rcmgrMetrics) BlockServicePeer(svc string, _ peer.ID) {
r.servicePeerBlocked.WithLabelValues(svc).Inc()
}
func (r rcmgrMetrics) AllowMemory(_ int) {
r.memoryAllowed.Inc()
}
func (r rcmgrMetrics) BlockMemory(_ int) {
r.memoryBlocked.Inc()
}