Skip to content

Commit

Permalink
[metrics] remove go-kit dependencies (#282)
Browse files Browse the repository at this point in the history
# Description

Now implementation use [go-kit](https://github.com/go-kit/kit) package
help build the metrics interface, but there is a performance cost in the
implementation of go-kit, this PR replaces go-kit, and directly uses the
prometheus metrics interface

exist cost code:
[prometheus.go#L159](https://github.com/go-kit/kit/blob/e923d5df8514423885b3a6d25cd44ae1d1db6d9d/metrics/prometheus/prometheus.go#L159)

`makeLabels` will be called every time the metrics is updated

```
func makeLabels(labelValues ...string) prometheus.Labels {
	labels := prometheus.Labels{}
	for i := 0; i < len(labelValues); i += 2 {
		labels[labelValues[i]] = labelValues[i+1]
	}
	return labels
}
```

heap pprof results:

![pprof](https://user-images.githubusercontent.com/111933059/212003591-3ec9dbef-5122-424f-816c-57b56568293f.png)

# Changes include

- [x] Bugfix (non-breaking change that solves an issue)

## Testing

- [x] I have tested this code with the official test suite
  • Loading branch information
0xcb9ff9 authored Jan 12, 2023
1 parent 2c217cb commit 8b4141f
Show file tree
Hide file tree
Showing 19 changed files with 586 additions and 544 deletions.
12 changes: 6 additions & 6 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,7 @@ func (b *Blockchain) executeBlockTransactions(block *types.Block) (*BlockResult,

begin := time.Now()
defer func() {
b.metrics.BlockExecutionSeconds.Observe(time.Since(begin).Seconds())
b.metrics.BlockExecutionSecondsObserve(time.Since(begin).Seconds())
}()

header := block.Header
Expand Down Expand Up @@ -1056,11 +1056,11 @@ func (b *Blockchain) WriteBlock(block *types.Block, source string) error {
bigPrice := new(big.Float).SetInt(b.gpAverage.price)
price, _ := bigPrice.Float64()

b.metrics.GasPriceAverage.Observe(price)
b.metrics.GasPriceAverageObserve(price)

b.metrics.GasUsed.Observe(float64(header.GasUsed))
b.metrics.BlockHeight.Set(float64(header.Number))
b.metrics.TransactionNum.Observe(float64(len(block.Transactions)))
b.metrics.GasUsedObserve(float64(header.GasUsed))
b.metrics.SetBlockHeight(float64(header.Number))
b.metrics.TransactionNumObserve(float64(len(block.Transactions)))
}

return nil
Expand Down Expand Up @@ -1111,7 +1111,7 @@ func (b *Blockchain) updateGasPriceAvgWithBlock(block *types.Block) {
func (b *Blockchain) writeBody(block *types.Block) error {
begin := time.Now()
defer func() {
b.metrics.BlockWrittenSeconds.Observe(time.Since(begin).Seconds())
b.metrics.BlockWrittenSecondsObserve(time.Since(begin).Seconds())
}()

body := block.Body()
Expand Down
146 changes: 87 additions & 59 deletions blockchain/metrics.go
Original file line number Diff line number Diff line change
@@ -1,86 +1,114 @@
package blockchain

import (
"github.com/go-kit/kit/metrics"
"github.com/go-kit/kit/metrics/discard"
prometheus "github.com/go-kit/kit/metrics/prometheus"
stdprometheus "github.com/prometheus/client_golang/prometheus"
"github.com/dogechain-lab/dogechain/helper/metrics"
"github.com/prometheus/client_golang/prometheus"
)

// Metrics represents the blockchain metrics
type Metrics struct {
// Gas Price Average
GasPriceAverage metrics.Histogram
gasPriceAverage prometheus.Histogram
// Gas used
GasUsed metrics.Histogram
gasUsed prometheus.Histogram
// Block height
BlockHeight metrics.Gauge
blockHeight prometheus.Gauge
// Block written duration
BlockWrittenSeconds metrics.Histogram
blockWrittenSeconds prometheus.Histogram
// Block execution duration
BlockExecutionSeconds metrics.Histogram
blockExecutionSeconds prometheus.Histogram
// Transaction number
TransactionNum metrics.Histogram
transactionNum prometheus.Histogram
}

func (m *Metrics) GasPriceAverageObserve(v float64) {
metrics.HistogramObserve(m.gasPriceAverage, v)
}

func (m *Metrics) GasUsedObserve(v float64) {
metrics.HistogramObserve(m.gasUsed, v)
}

func (m *Metrics) SetBlockHeight(v float64) {
metrics.SetGauge(m.blockHeight, v)
}

func (m *Metrics) BlockWrittenSecondsObserve(v float64) {
metrics.HistogramObserve(m.blockWrittenSeconds, v)
}

func (m *Metrics) BlockExecutionSecondsObserve(v float64) {
metrics.HistogramObserve(m.blockExecutionSeconds, v)
}

func (m *Metrics) TransactionNumObserve(v float64) {
metrics.HistogramObserve(m.transactionNum, v)
}

// GetPrometheusMetrics return the blockchain metrics instance
func GetPrometheusMetrics(namespace string, labelsWithValues ...string) *Metrics {
labels := []string{}
constLabels := metrics.ParseLables(labelsWithValues...)

for i := 0; i < len(labelsWithValues); i += 2 {
labels = append(labels, labelsWithValues[i])
m := &Metrics{
gasPriceAverage: prometheus.NewHistogram(prometheus.HistogramOpts{
Namespace: namespace,
Subsystem: "blockchain",
Name: "gas_avg_price",
Help: "Gas Price Average",
ConstLabels: constLabels,
}),
gasUsed: prometheus.NewHistogram(prometheus.HistogramOpts{
Namespace: namespace,
Subsystem: "blockchain",
Name: "gas_used",
Help: "Gas Used",
ConstLabels: constLabels,
}),
blockHeight: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "blockchain",
Name: "block_height",
Help: "Block height",
ConstLabels: constLabels,
}),
blockWrittenSeconds: prometheus.NewHistogram(prometheus.HistogramOpts{
Namespace: namespace,
Subsystem: "blockchain",
Name: "block_write_seconds",
Help: "block write time (seconds)",
ConstLabels: constLabels,
}),
blockExecutionSeconds: prometheus.NewHistogram(prometheus.HistogramOpts{
Namespace: namespace,
Subsystem: "blockchain",
Name: "block_execution_seconds",
Help: "block execution time (seconds)",
ConstLabels: constLabels,
}),
transactionNum: prometheus.NewHistogram(prometheus.HistogramOpts{
Namespace: namespace,
Subsystem: "blockchain",
Name: "transaction_number",
Help: "Transaction number",
ConstLabels: constLabels,
}),
}

return &Metrics{
GasPriceAverage: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
Namespace: namespace,
Subsystem: "blockchain",
Name: "gas_avg_price",
Help: "Gas Price Average",
}, labels).With(labelsWithValues...),
GasUsed: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
Namespace: namespace,
Subsystem: "blockchain",
Name: "gas_used",
Help: "Gas Used",
}, labels).With(labelsWithValues...),
BlockHeight: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "blockchain",
Name: "block_height",
Help: "Block height",
}, labels).With(labelsWithValues...),
BlockWrittenSeconds: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
Namespace: namespace,
Subsystem: "blockchain",
Name: "block_write_seconds",
Help: "block write time (seconds)",
}, labels).With(labelsWithValues...),
BlockExecutionSeconds: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
Namespace: namespace,
Subsystem: "blockchain",
Name: "block_execution_seconds",
Help: "block execution time (seconds)",
}, labels).With(labelsWithValues...),
TransactionNum: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
Namespace: namespace,
Subsystem: "blockchain",
Name: "transaction_number",
Help: "Transaction number",
}, labels).With(labelsWithValues...),
}
prometheus.MustRegister(
m.gasPriceAverage,
m.gasUsed,
m.blockHeight,
m.blockWrittenSeconds,
m.blockExecutionSeconds,
m.transactionNum,
)

return m
}

// NilMetrics will return the non operational blockchain metrics
func NilMetrics() *Metrics {
return &Metrics{
GasPriceAverage: discard.NewHistogram(),
GasUsed: discard.NewHistogram(),
BlockHeight: discard.NewGauge(),
BlockWrittenSeconds: discard.NewHistogram(),
BlockExecutionSeconds: discard.NewHistogram(),
TransactionNum: discard.NewHistogram(),
}
return &Metrics{}
}

// NewDummyMetrics will return the no nil blockchain metrics
Expand Down
6 changes: 3 additions & 3 deletions consensus/ibft/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func (i *Ibft) runAcceptState(ctx context.Context) (shouldStop bool) { // start
logger := i.logger.Named("acceptState")
logger.Info("Accept state", "sequence", i.state.Sequence(), "round", i.state.Round()+1)
// set consensus_rounds metric output
i.metrics.Rounds.Set(float64(i.state.Round() + 1))
i.metrics.SetRounds(float64(i.state.Round() + 1))

// This is the state in which we either propose a block or wait for the pre-prepare message
parent := i.blockchain.Header()
Expand Down Expand Up @@ -182,7 +182,7 @@ func (i *Ibft) runAcceptState(ctx context.Context) (shouldStop bool) { // start
i.state.SetValidators(snap.Set)

//Update the No.of validator metric
i.metrics.Validators.Set(float64(len(snap.Set)))
i.metrics.SetValidators(float64(len(snap.Set)))
// reset round messages
i.state.ResetRoundMsgs()

Expand Down Expand Up @@ -509,7 +509,7 @@ func (i *Ibft) runRoundChangeState(ctx context.Context) (shouldStop bool) {
logger.Debug("local round change", "round", round+1)
// set the new round and update the round metric
i.startNewRound(round)
i.metrics.Rounds.Set(float64(round))
i.metrics.SetRounds(float64(round))
// clean the round
i.state.CleanRound(round)
// send the round change message
Expand Down
4 changes: 2 additions & 2 deletions consensus/ibft/ibft.go
Original file line number Diff line number Diff line change
Expand Up @@ -1139,13 +1139,13 @@ func (i *Ibft) updateMetrics(block *types.Block) {

//Update the block interval metric
if block.Number() > 1 {
i.metrics.BlockInterval.Set(
i.metrics.SetBlockInterval(
headerTime.Sub(parentTime).Seconds(),
)
}

//Update the Number of transactions in the block metric
i.metrics.NumTxs.Set(float64(len(block.Body().Transactions)))
i.metrics.SetNumTxs(float64(len(block.Body().Transactions)))
}

func gatherCanonicalCommittedSeals(
Expand Down
97 changes: 52 additions & 45 deletions consensus/metrics.go
Original file line number Diff line number Diff line change
@@ -1,68 +1,75 @@
package consensus

import (
"github.com/go-kit/kit/metrics"
"github.com/go-kit/kit/metrics/discard"
prometheus "github.com/go-kit/kit/metrics/prometheus"
stdprometheus "github.com/prometheus/client_golang/prometheus"
"github.com/dogechain-lab/dogechain/helper/metrics"
"github.com/prometheus/client_golang/prometheus"
)

// Metrics represents the consensus metrics
type Metrics struct {
// No.of validators
Validators metrics.Gauge
validators prometheus.Gauge
// No.of rounds
Rounds metrics.Gauge
rounds prometheus.Gauge
// No.of transactions in the block
NumTxs metrics.Gauge

numTxs prometheus.Gauge
//Time between current block and the previous block in seconds
BlockInterval metrics.Gauge
blockInterval prometheus.Gauge
}

func (m *Metrics) SetValidators(val float64) {
metrics.SetGauge(m.validators, val)
}

func (m *Metrics) SetRounds(val float64) {
metrics.SetGauge(m.rounds, val)
}

func (m *Metrics) SetNumTxs(val float64) {
metrics.SetGauge(m.numTxs, val)
}

func (m *Metrics) SetBlockInterval(val float64) {
metrics.SetGauge(m.blockInterval, val)
}

// GetPrometheusMetrics return the consensus metrics instance
func GetPrometheusMetrics(namespace string, labelsWithValues ...string) *Metrics {
labels := []string{}

for i := 0; i < len(labelsWithValues); i += 2 {
labels = append(labels, labelsWithValues[i])
}
constLabels := metrics.ParseLables(labelsWithValues...)

return &Metrics{
Validators: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "consensus",
Name: "validators",
Help: "Number of validators.",
}, labels).With(labelsWithValues...),
Rounds: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "consensus",
Name: "rounds",
Help: "Number of rounds.",
}, labels).With(labelsWithValues...),
NumTxs: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "consensus",
Name: "num_txs",
Help: "Number of transactions.",
}, labels).With(labelsWithValues...),

BlockInterval: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "consensus",
Name: "block_interval",
Help: "Time between current block and the previous block in seconds.",
}, labels).With(labelsWithValues...),
validators: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "consensus",
Name: "validators",
Help: "Number of validators.",
ConstLabels: constLabels,
}),
rounds: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "consensus",
Name: "rounds",
Help: "Number of rounds.",
ConstLabels: constLabels,
}),
numTxs: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "consensus",
Name: "num_txs",
Help: "Number of transactions.",
ConstLabels: constLabels,
}),
blockInterval: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: namespace,
Subsystem: "consensus",
Name: "block_interval",
Help: "Time between current block and the previous block in seconds.",
ConstLabels: constLabels,
}),
}
}

// NilMetrics will return the non operational metrics
func NilMetrics() *Metrics {
return &Metrics{
Validators: discard.NewGauge(),
Rounds: discard.NewGauge(),
NumTxs: discard.NewGauge(),
BlockInterval: discard.NewGauge(),
}
return &Metrics{}
}
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ require (
//github.com/umbracle/fastrlp v0.0.0-20220529195328-c1416904ae17
github.com/dogechain-lab/fastrlp v0.0.0-20220523073019-b0c60fc6bb7a
github.com/elastic/gosigar v0.14.2 // indirect
github.com/go-kit/kit v0.12.0
github.com/golang/protobuf v1.5.2
github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.5.0
Expand Down Expand Up @@ -107,7 +106,7 @@ require (
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/koron/go-ssdp v0.0.2 // indirect
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
github.com/libp2p/go-cidranger v1.1.0 // indirect
github.com/libp2p/go-cidranger v1.1.0
github.com/libp2p/go-conn-security-multistream v0.3.0 // indirect
github.com/libp2p/go-eventbus v0.2.1 // indirect
github.com/libp2p/go-flow-metrics v0.0.3 // indirect
Expand Down
Loading

0 comments on commit 8b4141f

Please sign in to comment.