mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 06:42:16 +00:00
metrics: Add additional metrics to p2p and consensus (#2425)
* Add additional metrics to p2p and consensus Partially addresses https://github.com/cosmos/cosmos-sdk/issues/2169. * WIP * Updates from code review * Updates from code review * Add instrumentation namespace to configuration * Fix test failure * Updates from code review * Add quotes * Add atomic load * Use storeint64 * Use addInt64 in writePacketMsgTo
This commit is contained in:
parent
eb0da7f9cb
commit
587116dae1
@ -14,6 +14,8 @@ BREAKING CHANGES:
|
|||||||
FEATURES:
|
FEATURES:
|
||||||
|
|
||||||
IMPROVEMENTS:
|
IMPROVEMENTS:
|
||||||
|
- [consensus] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169) add additional metrics
|
||||||
|
- [p2p] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169) add additional metrics
|
||||||
|
|
||||||
BUG FIXES:
|
BUG FIXES:
|
||||||
- [node] \#2434 Make node respond to signal interrupts while sleeping for genesis time
|
- [node] \#2434 Make node respond to signal interrupts while sleeping for genesis time
|
||||||
|
@ -634,6 +634,9 @@ type InstrumentationConfig struct {
|
|||||||
// you increase your OS limits.
|
// you increase your OS limits.
|
||||||
// 0 - unlimited.
|
// 0 - unlimited.
|
||||||
MaxOpenConnections int `mapstructure:"max_open_connections"`
|
MaxOpenConnections int `mapstructure:"max_open_connections"`
|
||||||
|
|
||||||
|
// Tendermint instrumentation namespace.
|
||||||
|
Namespace string `mapstructure:"namespace"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultInstrumentationConfig returns a default configuration for metrics
|
// DefaultInstrumentationConfig returns a default configuration for metrics
|
||||||
@ -643,6 +646,7 @@ func DefaultInstrumentationConfig() *InstrumentationConfig {
|
|||||||
Prometheus: false,
|
Prometheus: false,
|
||||||
PrometheusListenAddr: ":26660",
|
PrometheusListenAddr: ":26660",
|
||||||
MaxOpenConnections: 3,
|
MaxOpenConnections: 3,
|
||||||
|
Namespace: "tendermint",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +284,9 @@ prometheus_listen_addr = "{{ .Instrumentation.PrometheusListenAddr }}"
|
|||||||
# you increase your OS limits.
|
# you increase your OS limits.
|
||||||
# 0 - unlimited.
|
# 0 - unlimited.
|
||||||
max_open_connections = {{ .Instrumentation.MaxOpenConnections }}
|
max_open_connections = {{ .Instrumentation.MaxOpenConnections }}
|
||||||
|
|
||||||
|
# Instrumentation namespace
|
||||||
|
namespace = "{{ .Instrumentation.Namespace }}"
|
||||||
`
|
`
|
||||||
|
|
||||||
/****** these are for test settings ***********/
|
/****** these are for test settings ***********/
|
||||||
|
@ -8,6 +8,8 @@ import (
|
|||||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const MetricsSubsystem = "consensus"
|
||||||
|
|
||||||
// Metrics contains metrics exposed by this package.
|
// Metrics contains metrics exposed by this package.
|
||||||
type Metrics struct {
|
type Metrics struct {
|
||||||
// Height of the chain.
|
// Height of the chain.
|
||||||
@ -38,74 +40,102 @@ type Metrics struct {
|
|||||||
BlockSizeBytes metrics.Gauge
|
BlockSizeBytes metrics.Gauge
|
||||||
// Total number of transactions.
|
// Total number of transactions.
|
||||||
TotalTxs metrics.Gauge
|
TotalTxs metrics.Gauge
|
||||||
|
// The latest block height.
|
||||||
|
CommittedHeight metrics.Gauge
|
||||||
|
// Whether or not a node is fast syncing. 1 if yes, 0 if no.
|
||||||
|
FastSyncing metrics.Gauge
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrometheusMetrics returns Metrics build using Prometheus client library.
|
// PrometheusMetrics returns Metrics build using Prometheus client library.
|
||||||
func PrometheusMetrics() *Metrics {
|
func PrometheusMetrics(namespace string) *Metrics {
|
||||||
return &Metrics{
|
return &Metrics{
|
||||||
Height: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
Height: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
Subsystem: "consensus",
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
Name: "height",
|
Name: "height",
|
||||||
Help: "Height of the chain.",
|
Help: "Height of the chain.",
|
||||||
}, []string{}),
|
}, []string{}),
|
||||||
Rounds: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
Rounds: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
Subsystem: "consensus",
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
Name: "rounds",
|
Name: "rounds",
|
||||||
Help: "Number of rounds.",
|
Help: "Number of rounds.",
|
||||||
}, []string{}),
|
}, []string{}),
|
||||||
|
|
||||||
Validators: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
Validators: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
Subsystem: "consensus",
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
Name: "validators",
|
Name: "validators",
|
||||||
Help: "Number of validators.",
|
Help: "Number of validators.",
|
||||||
}, []string{}),
|
}, []string{}),
|
||||||
ValidatorsPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
ValidatorsPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
Subsystem: "consensus",
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
Name: "validators_power",
|
Name: "validators_power",
|
||||||
Help: "Total power of all validators.",
|
Help: "Total power of all validators.",
|
||||||
}, []string{}),
|
}, []string{}),
|
||||||
MissingValidators: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
MissingValidators: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
Subsystem: "consensus",
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
Name: "missing_validators",
|
Name: "missing_validators",
|
||||||
Help: "Number of validators who did not sign.",
|
Help: "Number of validators who did not sign.",
|
||||||
}, []string{}),
|
}, []string{}),
|
||||||
MissingValidatorsPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
MissingValidatorsPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
Subsystem: "consensus",
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
Name: "missing_validators_power",
|
Name: "missing_validators_power",
|
||||||
Help: "Total power of the missing validators.",
|
Help: "Total power of the missing validators.",
|
||||||
}, []string{}),
|
}, []string{}),
|
||||||
ByzantineValidators: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
ByzantineValidators: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
Subsystem: "consensus",
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
Name: "byzantine_validators",
|
Name: "byzantine_validators",
|
||||||
Help: "Number of validators who tried to double sign.",
|
Help: "Number of validators who tried to double sign.",
|
||||||
}, []string{}),
|
}, []string{}),
|
||||||
ByzantineValidatorsPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
ByzantineValidatorsPower: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
Subsystem: "consensus",
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
Name: "byzantine_validators_power",
|
Name: "byzantine_validators_power",
|
||||||
Help: "Total power of the byzantine validators.",
|
Help: "Total power of the byzantine validators.",
|
||||||
}, []string{}),
|
}, []string{}),
|
||||||
|
|
||||||
BlockIntervalSeconds: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
BlockIntervalSeconds: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
Subsystem: "consensus",
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
Name: "block_interval_seconds",
|
Name: "block_interval_seconds",
|
||||||
Help: "Time between this and the last block.",
|
Help: "Time between this and the last block.",
|
||||||
}, []string{}),
|
}, []string{}),
|
||||||
|
|
||||||
NumTxs: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
NumTxs: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
Subsystem: "consensus",
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
Name: "num_txs",
|
Name: "num_txs",
|
||||||
Help: "Number of transactions.",
|
Help: "Number of transactions.",
|
||||||
}, []string{}),
|
}, []string{}),
|
||||||
BlockSizeBytes: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
BlockSizeBytes: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
Subsystem: "consensus",
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
Name: "block_size_bytes",
|
Name: "block_size_bytes",
|
||||||
Help: "Size of the block.",
|
Help: "Size of the block.",
|
||||||
}, []string{}),
|
}, []string{}),
|
||||||
TotalTxs: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
TotalTxs: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
Subsystem: "consensus",
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
Name: "total_txs",
|
Name: "total_txs",
|
||||||
Help: "Total number of transactions.",
|
Help: "Total number of transactions.",
|
||||||
}, []string{}),
|
}, []string{}),
|
||||||
|
CommittedHeight: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
|
Name: "latest_block_height",
|
||||||
|
Help: "The latest block height.",
|
||||||
|
}, []string{}),
|
||||||
|
FastSyncing: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
|
Name: "fast_syncing",
|
||||||
|
Help: "Whether or not a node is fast syncing. 1 if yes, 0 if no.",
|
||||||
|
}, []string{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,5 +158,7 @@ func NopMetrics() *Metrics {
|
|||||||
NumTxs: discard.NewGauge(),
|
NumTxs: discard.NewGauge(),
|
||||||
BlockSizeBytes: discard.NewGauge(),
|
BlockSizeBytes: discard.NewGauge(),
|
||||||
TotalTxs: discard.NewGauge(),
|
TotalTxs: discard.NewGauge(),
|
||||||
|
CommittedHeight: discard.NewGauge(),
|
||||||
|
FastSyncing: discard.NewGauge(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,16 +43,27 @@ type ConsensusReactor struct {
|
|||||||
mtx sync.RWMutex
|
mtx sync.RWMutex
|
||||||
fastSync bool
|
fastSync bool
|
||||||
eventBus *types.EventBus
|
eventBus *types.EventBus
|
||||||
|
|
||||||
|
metrics *Metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ReactorOption func(*ConsensusReactor)
|
||||||
|
|
||||||
// NewConsensusReactor returns a new ConsensusReactor with the given
|
// NewConsensusReactor returns a new ConsensusReactor with the given
|
||||||
// consensusState.
|
// consensusState.
|
||||||
func NewConsensusReactor(consensusState *ConsensusState, fastSync bool) *ConsensusReactor {
|
func NewConsensusReactor(consensusState *ConsensusState, fastSync bool, options ...ReactorOption) *ConsensusReactor {
|
||||||
conR := &ConsensusReactor{
|
conR := &ConsensusReactor{
|
||||||
conS: consensusState,
|
conS: consensusState,
|
||||||
fastSync: fastSync,
|
fastSync: fastSync,
|
||||||
|
metrics: NopMetrics(),
|
||||||
}
|
}
|
||||||
|
conR.updateFastSyncingMetric()
|
||||||
conR.BaseReactor = *p2p.NewBaseReactor("ConsensusReactor", conR)
|
conR.BaseReactor = *p2p.NewBaseReactor("ConsensusReactor", conR)
|
||||||
|
|
||||||
|
for _, option := range options {
|
||||||
|
option(conR)
|
||||||
|
}
|
||||||
|
|
||||||
return conR
|
return conR
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,6 +109,7 @@ func (conR *ConsensusReactor) SwitchToConsensus(state sm.State, blocksSynced int
|
|||||||
conR.mtx.Lock()
|
conR.mtx.Lock()
|
||||||
conR.fastSync = false
|
conR.fastSync = false
|
||||||
conR.mtx.Unlock()
|
conR.mtx.Unlock()
|
||||||
|
conR.metrics.FastSyncing.Set(0)
|
||||||
|
|
||||||
if blocksSynced > 0 {
|
if blocksSynced > 0 {
|
||||||
// dont bother with the WAL if we fast synced
|
// dont bother with the WAL if we fast synced
|
||||||
@ -850,6 +862,21 @@ func (conR *ConsensusReactor) StringIndented(indent string) string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (conR *ConsensusReactor) updateFastSyncingMetric() {
|
||||||
|
var fastSyncing float64
|
||||||
|
if conR.fastSync {
|
||||||
|
fastSyncing = 1
|
||||||
|
} else {
|
||||||
|
fastSyncing = 0
|
||||||
|
}
|
||||||
|
conR.metrics.FastSyncing.Set(fastSyncing)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReactorMetrics sets the metrics
|
||||||
|
func ReactorMetrics(metrics *Metrics) ReactorOption {
|
||||||
|
return func(conR *ConsensusReactor) { conR.metrics = metrics }
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -124,8 +124,8 @@ type ConsensusState struct {
|
|||||||
metrics *Metrics
|
metrics *Metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
// CSOption sets an optional parameter on the ConsensusState.
|
// StateOption sets an optional parameter on the ConsensusState.
|
||||||
type CSOption func(*ConsensusState)
|
type StateOption func(*ConsensusState)
|
||||||
|
|
||||||
// NewConsensusState returns a new ConsensusState.
|
// NewConsensusState returns a new ConsensusState.
|
||||||
func NewConsensusState(
|
func NewConsensusState(
|
||||||
@ -135,7 +135,7 @@ func NewConsensusState(
|
|||||||
blockStore sm.BlockStore,
|
blockStore sm.BlockStore,
|
||||||
mempool sm.Mempool,
|
mempool sm.Mempool,
|
||||||
evpool sm.EvidencePool,
|
evpool sm.EvidencePool,
|
||||||
options ...CSOption,
|
options ...StateOption,
|
||||||
) *ConsensusState {
|
) *ConsensusState {
|
||||||
cs := &ConsensusState{
|
cs := &ConsensusState{
|
||||||
config: config,
|
config: config,
|
||||||
@ -185,8 +185,8 @@ func (cs *ConsensusState) SetEventBus(b *types.EventBus) {
|
|||||||
cs.blockExec.SetEventBus(b)
|
cs.blockExec.SetEventBus(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithMetrics sets the metrics.
|
// StateMetrics sets the metrics.
|
||||||
func WithMetrics(metrics *Metrics) CSOption {
|
func StateMetrics(metrics *Metrics) StateOption {
|
||||||
return func(cs *ConsensusState) { cs.metrics = metrics }
|
return func(cs *ConsensusState) { cs.metrics = metrics }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1397,6 +1397,8 @@ func (cs *ConsensusState) recordMetrics(height int64, block *types.Block) {
|
|||||||
cs.metrics.NumTxs.Set(float64(block.NumTxs))
|
cs.metrics.NumTxs.Set(float64(block.NumTxs))
|
||||||
cs.metrics.BlockSizeBytes.Set(float64(block.Size()))
|
cs.metrics.BlockSizeBytes.Set(float64(block.Size()))
|
||||||
cs.metrics.TotalTxs.Set(float64(block.TotalTxs))
|
cs.metrics.TotalTxs.Set(float64(block.TotalTxs))
|
||||||
|
cs.metrics.CommittedHeight.Set(float64(block.Height))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -227,4 +227,7 @@ prometheus_listen_addr = ":26660"
|
|||||||
# you increase your OS limits.
|
# you increase your OS limits.
|
||||||
# 0 - unlimited.
|
# 0 - unlimited.
|
||||||
max_open_connections = 3
|
max_open_connections = 3
|
||||||
|
|
||||||
|
# Instrumentation namespace
|
||||||
|
namespace = "tendermint"
|
||||||
```
|
```
|
||||||
|
@ -3,7 +3,6 @@ package mempool
|
|||||||
import (
|
import (
|
||||||
"github.com/go-kit/kit/metrics"
|
"github.com/go-kit/kit/metrics"
|
||||||
"github.com/go-kit/kit/metrics/discard"
|
"github.com/go-kit/kit/metrics/discard"
|
||||||
|
|
||||||
prometheus "github.com/go-kit/kit/metrics/prometheus"
|
prometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
@ -16,9 +15,10 @@ type Metrics struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PrometheusMetrics returns Metrics build using Prometheus client library.
|
// PrometheusMetrics returns Metrics build using Prometheus client library.
|
||||||
func PrometheusMetrics() *Metrics {
|
func PrometheusMetrics(namespace string) *Metrics {
|
||||||
return &Metrics{
|
return &Metrics{
|
||||||
Size: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
Size: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
|
Namespace: namespace,
|
||||||
Subsystem: "mempool",
|
Subsystem: "mempool",
|
||||||
Name: "size",
|
Name: "size",
|
||||||
Help: "Size of the mempool (number of uncommitted transactions).",
|
Help: "Size of the mempool (number of uncommitted transactions).",
|
||||||
|
@ -105,7 +105,7 @@ type MetricsProvider func() (*cs.Metrics, *p2p.Metrics, *mempl.Metrics)
|
|||||||
func DefaultMetricsProvider(config *cfg.InstrumentationConfig) MetricsProvider {
|
func DefaultMetricsProvider(config *cfg.InstrumentationConfig) MetricsProvider {
|
||||||
return func() (*cs.Metrics, *p2p.Metrics, *mempl.Metrics) {
|
return func() (*cs.Metrics, *p2p.Metrics, *mempl.Metrics) {
|
||||||
if config.Prometheus {
|
if config.Prometheus {
|
||||||
return cs.PrometheusMetrics(), p2p.PrometheusMetrics(), mempl.PrometheusMetrics()
|
return cs.PrometheusMetrics(config.Namespace), p2p.PrometheusMetrics(config.Namespace), mempl.PrometheusMetrics(config.Namespace)
|
||||||
}
|
}
|
||||||
return cs.NopMetrics(), p2p.NopMetrics(), mempl.NopMetrics()
|
return cs.NopMetrics(), p2p.NopMetrics(), mempl.NopMetrics()
|
||||||
}
|
}
|
||||||
@ -303,13 +303,13 @@ func NewNode(config *cfg.Config,
|
|||||||
blockStore,
|
blockStore,
|
||||||
mempool,
|
mempool,
|
||||||
evidencePool,
|
evidencePool,
|
||||||
cs.WithMetrics(csMetrics),
|
cs.StateMetrics(csMetrics),
|
||||||
)
|
)
|
||||||
consensusState.SetLogger(consensusLogger)
|
consensusState.SetLogger(consensusLogger)
|
||||||
if privValidator != nil {
|
if privValidator != nil {
|
||||||
consensusState.SetPrivValidator(privValidator)
|
consensusState.SetPrivValidator(privValidator)
|
||||||
}
|
}
|
||||||
consensusReactor := cs.NewConsensusReactor(consensusState, fastSync)
|
consensusReactor := cs.NewConsensusReactor(consensusState, fastSync, cs.ReactorMetrics(csMetrics))
|
||||||
consensusReactor.SetLogger(consensusLogger)
|
consensusReactor.SetLogger(consensusLogger)
|
||||||
|
|
||||||
eventBus := types.NewEventBus()
|
eventBus := types.NewEventBus()
|
||||||
|
@ -585,9 +585,9 @@ func (c *MConnection) Status() ConnectionStatus {
|
|||||||
status.Channels[i] = ChannelStatus{
|
status.Channels[i] = ChannelStatus{
|
||||||
ID: channel.desc.ID,
|
ID: channel.desc.ID,
|
||||||
SendQueueCapacity: cap(channel.sendQueue),
|
SendQueueCapacity: cap(channel.sendQueue),
|
||||||
SendQueueSize: int(channel.sendQueueSize), // TODO use atomic
|
SendQueueSize: int(atomic.LoadInt32(&channel.sendQueueSize)),
|
||||||
Priority: channel.desc.Priority,
|
Priority: channel.desc.Priority,
|
||||||
RecentlySent: channel.recentlySent,
|
RecentlySent: atomic.LoadInt64(&channel.recentlySent),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return status
|
return status
|
||||||
@ -724,7 +724,7 @@ func (ch *Channel) nextPacketMsg() PacketMsg {
|
|||||||
func (ch *Channel) writePacketMsgTo(w io.Writer) (n int64, err error) {
|
func (ch *Channel) writePacketMsgTo(w io.Writer) (n int64, err error) {
|
||||||
var packet = ch.nextPacketMsg()
|
var packet = ch.nextPacketMsg()
|
||||||
n, err = cdc.MarshalBinaryWriter(w, packet)
|
n, err = cdc.MarshalBinaryWriter(w, packet)
|
||||||
ch.recentlySent += n
|
atomic.AddInt64(&ch.recentlySent, n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -756,7 +756,7 @@ func (ch *Channel) recvPacketMsg(packet PacketMsg) ([]byte, error) {
|
|||||||
func (ch *Channel) updateStats() {
|
func (ch *Channel) updateStats() {
|
||||||
// Exponential decay of stats.
|
// Exponential decay of stats.
|
||||||
// TODO: optimize.
|
// TODO: optimize.
|
||||||
ch.recentlySent = int64(float64(ch.recentlySent) * 0.8)
|
atomic.StoreInt64(&ch.recentlySent, int64(float64(atomic.LoadInt64(&ch.recentlySent)) * 0.8))
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
@ -3,25 +3,51 @@ package p2p
|
|||||||
import (
|
import (
|
||||||
"github.com/go-kit/kit/metrics"
|
"github.com/go-kit/kit/metrics"
|
||||||
"github.com/go-kit/kit/metrics/discard"
|
"github.com/go-kit/kit/metrics/discard"
|
||||||
|
|
||||||
prometheus "github.com/go-kit/kit/metrics/prometheus"
|
prometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const MetricsSubsystem = "p2p"
|
||||||
|
|
||||||
// Metrics contains metrics exposed by this package.
|
// Metrics contains metrics exposed by this package.
|
||||||
type Metrics struct {
|
type Metrics struct {
|
||||||
// Number of peers.
|
// Number of peers.
|
||||||
Peers metrics.Gauge
|
Peers metrics.Gauge
|
||||||
|
// Number of bytes received from a given peer.
|
||||||
|
PeerReceiveBytesTotal metrics.Counter
|
||||||
|
// Number of bytes sent to a given peer.
|
||||||
|
PeerSendBytesTotal metrics.Counter
|
||||||
|
// Pending bytes to be sent to a given peer.
|
||||||
|
PeerPendingSendBytes metrics.Gauge
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrometheusMetrics returns Metrics build using Prometheus client library.
|
// PrometheusMetrics returns Metrics build using Prometheus client library.
|
||||||
func PrometheusMetrics() *Metrics {
|
func PrometheusMetrics(namespace string) *Metrics {
|
||||||
return &Metrics{
|
return &Metrics{
|
||||||
Peers: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
Peers: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
Subsystem: "p2p",
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
Name: "peers",
|
Name: "peers",
|
||||||
Help: "Number of peers.",
|
Help: "Number of peers.",
|
||||||
}, []string{}),
|
}, []string{}),
|
||||||
|
PeerReceiveBytesTotal: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
|
||||||
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
|
Name: "peer_receive_bytes_total",
|
||||||
|
Help: "Number of bytes received from a given peer.",
|
||||||
|
}, []string{"peer_id"}),
|
||||||
|
PeerSendBytesTotal: prometheus.NewCounterFrom(stdprometheus.CounterOpts{
|
||||||
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
|
Name: "peer_send_bytes_total",
|
||||||
|
Help: "Number of bytes sent to a given peer.",
|
||||||
|
}, []string{"peer_id"}),
|
||||||
|
PeerPendingSendBytes: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||||
|
Namespace: namespace,
|
||||||
|
Subsystem: MetricsSubsystem,
|
||||||
|
Name: "peer_pending_send_bytes",
|
||||||
|
Help: "Number of pending bytes to be sent to a given peer.",
|
||||||
|
}, []string{"peer_id"}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,5 +55,8 @@ func PrometheusMetrics() *Metrics {
|
|||||||
func NopMetrics() *Metrics {
|
func NopMetrics() *Metrics {
|
||||||
return &Metrics{
|
return &Metrics{
|
||||||
Peers: discard.NewGauge(),
|
Peers: discard.NewGauge(),
|
||||||
|
PeerReceiveBytesTotal: discard.NewCounter(),
|
||||||
|
PeerSendBytesTotal: discard.NewCounter(),
|
||||||
|
PeerPendingSendBytes: discard.NewGauge(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
57
p2p/peer.go
57
p2p/peer.go
@ -13,6 +13,8 @@ import (
|
|||||||
tmconn "github.com/tendermint/tendermint/p2p/conn"
|
tmconn "github.com/tendermint/tendermint/p2p/conn"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const metricsTickerDuration = 10 * time.Second
|
||||||
|
|
||||||
var testIPSuffix uint32
|
var testIPSuffix uint32
|
||||||
|
|
||||||
// Peer is an interface representing a peer connected on a reactor.
|
// Peer is an interface representing a peer connected on a reactor.
|
||||||
@ -99,8 +101,13 @@ type peer struct {
|
|||||||
|
|
||||||
// User data
|
// User data
|
||||||
Data *cmn.CMap
|
Data *cmn.CMap
|
||||||
|
|
||||||
|
metrics *Metrics
|
||||||
|
metricsTicker *time.Ticker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PeerOption func(*peer)
|
||||||
|
|
||||||
func newPeer(
|
func newPeer(
|
||||||
pc peerConn,
|
pc peerConn,
|
||||||
mConfig tmconn.MConnConfig,
|
mConfig tmconn.MConnConfig,
|
||||||
@ -108,12 +115,15 @@ func newPeer(
|
|||||||
reactorsByCh map[byte]Reactor,
|
reactorsByCh map[byte]Reactor,
|
||||||
chDescs []*tmconn.ChannelDescriptor,
|
chDescs []*tmconn.ChannelDescriptor,
|
||||||
onPeerError func(Peer, interface{}),
|
onPeerError func(Peer, interface{}),
|
||||||
|
options ...PeerOption,
|
||||||
) *peer {
|
) *peer {
|
||||||
p := &peer{
|
p := &peer{
|
||||||
peerConn: pc,
|
peerConn: pc,
|
||||||
nodeInfo: nodeInfo,
|
nodeInfo: nodeInfo,
|
||||||
channels: nodeInfo.Channels,
|
channels: nodeInfo.Channels,
|
||||||
Data: cmn.NewCMap(),
|
Data: cmn.NewCMap(),
|
||||||
|
metricsTicker: time.NewTicker(metricsTickerDuration),
|
||||||
|
metrics: NopMetrics(),
|
||||||
}
|
}
|
||||||
|
|
||||||
p.mconn = createMConnection(
|
p.mconn = createMConnection(
|
||||||
@ -125,6 +135,9 @@ func newPeer(
|
|||||||
mConfig,
|
mConfig,
|
||||||
)
|
)
|
||||||
p.BaseService = *cmn.NewBaseService(nil, "Peer", p)
|
p.BaseService = *cmn.NewBaseService(nil, "Peer", p)
|
||||||
|
for _, option := range options {
|
||||||
|
option(p)
|
||||||
|
}
|
||||||
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
@ -143,12 +156,18 @@ func (p *peer) OnStart() error {
|
|||||||
if err := p.BaseService.OnStart(); err != nil {
|
if err := p.BaseService.OnStart(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err := p.mconn.Start()
|
|
||||||
|
if err := p.mconn.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go p.metricsReporter()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// OnStop implements BaseService.
|
// OnStop implements BaseService.
|
||||||
func (p *peer) OnStop() {
|
func (p *peer) OnStop() {
|
||||||
|
p.metricsTicker.Stop()
|
||||||
p.BaseService.OnStop()
|
p.BaseService.OnStop()
|
||||||
p.mconn.Stop() // stop everything and close the conn
|
p.mconn.Stop() // stop everything and close the conn
|
||||||
}
|
}
|
||||||
@ -200,7 +219,11 @@ func (p *peer) Send(chID byte, msgBytes []byte) bool {
|
|||||||
} else if !p.hasChannel(chID) {
|
} else if !p.hasChannel(chID) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return p.mconn.Send(chID, msgBytes)
|
res := p.mconn.Send(chID, msgBytes)
|
||||||
|
if res {
|
||||||
|
p.metrics.PeerSendBytesTotal.With("peer-id", string(p.ID())).Add(float64(len(msgBytes)))
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrySend msg bytes to the channel identified by chID byte. Immediately returns
|
// TrySend msg bytes to the channel identified by chID byte. Immediately returns
|
||||||
@ -211,7 +234,11 @@ func (p *peer) TrySend(chID byte, msgBytes []byte) bool {
|
|||||||
} else if !p.hasChannel(chID) {
|
} else if !p.hasChannel(chID) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return p.mconn.TrySend(chID, msgBytes)
|
res := p.mconn.TrySend(chID, msgBytes)
|
||||||
|
if res {
|
||||||
|
p.metrics.PeerSendBytesTotal.With("peer-id", string(p.ID())).Add(float64(len(msgBytes)))
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the data for a given key.
|
// Get the data for a given key.
|
||||||
@ -314,6 +341,29 @@ func (p *peer) String() string {
|
|||||||
return fmt.Sprintf("Peer{%v %v in}", p.mconn, p.ID())
|
return fmt.Sprintf("Peer{%v %v in}", p.mconn, p.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PeerMetrics(metrics *Metrics) PeerOption {
|
||||||
|
return func(p *peer) {
|
||||||
|
p.metrics = metrics
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *peer) metricsReporter() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-p.metricsTicker.C:
|
||||||
|
status := p.mconn.Status()
|
||||||
|
var sendQueueSize float64
|
||||||
|
for _, chStatus := range status.Channels {
|
||||||
|
sendQueueSize += float64(chStatus.SendQueueSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.metrics.PeerPendingSendBytes.With("peer-id", string(p.ID())).Set(sendQueueSize)
|
||||||
|
case <-p.Quit():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
// helper funcs
|
// helper funcs
|
||||||
|
|
||||||
@ -333,6 +383,7 @@ func createMConnection(
|
|||||||
// which does onPeerError.
|
// which does onPeerError.
|
||||||
panic(fmt.Sprintf("Unknown channel %X", chID))
|
panic(fmt.Sprintf("Unknown channel %X", chID))
|
||||||
}
|
}
|
||||||
|
p.metrics.PeerReceiveBytesTotal.With("peer_id", string(p.ID())).Add(float64(len(msgBytes)))
|
||||||
reactor.Receive(chID, p, msgBytes)
|
reactor.Receive(chID, p, msgBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ func randPeer(ip net.IP) *peer {
|
|||||||
ID: nodeKey.ID(),
|
ID: nodeKey.ID(),
|
||||||
ListenAddr: fmt.Sprintf("%v.%v.%v.%v:26656", cmn.RandInt()%256, cmn.RandInt()%256, cmn.RandInt()%256, cmn.RandInt()%256),
|
ListenAddr: fmt.Sprintf("%v.%v.%v.%v:26656", cmn.RandInt()%256, cmn.RandInt()%256, cmn.RandInt()%256, cmn.RandInt()%256),
|
||||||
},
|
},
|
||||||
|
metrics: NopMetrics(),
|
||||||
}
|
}
|
||||||
|
|
||||||
p.ip = ip
|
p.ip = ip
|
||||||
|
@ -463,6 +463,7 @@ func (sw *Switch) acceptRoutine() {
|
|||||||
chDescs: sw.chDescs,
|
chDescs: sw.chDescs,
|
||||||
onPeerError: sw.StopPeerForError,
|
onPeerError: sw.StopPeerForError,
|
||||||
reactorsByCh: sw.reactorsByCh,
|
reactorsByCh: sw.reactorsByCh,
|
||||||
|
metrics: sw.metrics,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
@ -549,6 +550,7 @@ func (sw *Switch) addOutboundPeerWithConfig(
|
|||||||
onPeerError: sw.StopPeerForError,
|
onPeerError: sw.StopPeerForError,
|
||||||
persistent: persistent,
|
persistent: persistent,
|
||||||
reactorsByCh: sw.reactorsByCh,
|
reactorsByCh: sw.reactorsByCh,
|
||||||
|
metrics: sw.metrics,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch e := err.(type) {
|
switch e := err.(type) {
|
||||||
|
@ -29,6 +29,7 @@ func CreateRandomPeer(outbound bool) *peer {
|
|||||||
ListenAddr: netAddr.DialString(),
|
ListenAddr: netAddr.DialString(),
|
||||||
},
|
},
|
||||||
mconn: &conn.MConnection{},
|
mconn: &conn.MConnection{},
|
||||||
|
metrics: NopMetrics(),
|
||||||
}
|
}
|
||||||
p.SetLogger(log.TestingLogger().With("peer", addr))
|
p.SetLogger(log.TestingLogger().With("peer", addr))
|
||||||
return p
|
return p
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/config"
|
"github.com/tendermint/tendermint/config"
|
||||||
crypto "github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
"github.com/tendermint/tendermint/p2p/conn"
|
"github.com/tendermint/tendermint/p2p/conn"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -41,6 +41,7 @@ type peerConfig struct {
|
|||||||
onPeerError func(Peer, interface{})
|
onPeerError func(Peer, interface{})
|
||||||
outbound, persistent bool
|
outbound, persistent bool
|
||||||
reactorsByCh map[byte]Reactor
|
reactorsByCh map[byte]Reactor
|
||||||
|
metrics *Metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transport emits and connects to Peers. The implementation of Peer is left to
|
// Transport emits and connects to Peers. The implementation of Peer is left to
|
||||||
@ -411,6 +412,7 @@ func (mt *MultiplexTransport) wrapPeer(
|
|||||||
cfg.reactorsByCh,
|
cfg.reactorsByCh,
|
||||||
cfg.chDescs,
|
cfg.chDescs,
|
||||||
cfg.onPeerError,
|
cfg.onPeerError,
|
||||||
|
PeerMetrics(cfg.metrics),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Wait for Peer to Stop so we can cleanup.
|
// Wait for Peer to Stop so we can cleanup.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user