Skip to content

Commit

Permalink
Support multiple Execution Clients
Browse files Browse the repository at this point in the history
  • Loading branch information
oleg-ssvlabs committed Feb 6, 2025
1 parent 0ea10d3 commit 88deea2
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 35 deletions.
34 changes: 22 additions & 12 deletions configs/benchmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,21 @@ func (c Consensus) AddrURLs() ([]*url.URL, error) {
}

type Execution struct {
Address string `mapstructure:"address"`
Metrics ExecutionMetrics `mapstructure:"metrics"`
Addresses []string `mapstructure:"address"`
Metrics ExecutionMetrics `mapstructure:"metrics"`
}

func (e Execution) AddrURL() (*url.URL, error) {
parsedURL, err := url.Parse(e.Address)
if err != nil {
return nil, errors.Join(err, errors.New("error parsing Execution address to URL type"))
func (e Execution) AddrURLs() ([]*url.URL, error) {
var urls []*url.URL
for _, addr := range e.Addresses {
parsedURL, err := url.Parse(addr)
if err != nil {
return nil, errors.Join(err, errors.New("error parsing Execution address to URL type"))
}
urls = append(urls, parsedURL)
}
return parsedURL, nil

return urls, nil
}

type SSV struct {
Expand Down Expand Up @@ -113,12 +118,17 @@ func (b *Benchmark) Validate() (bool, error) {
b.Consensus.Addresses = urls
}

if b.Execution.Metrics.Peers.Enabled {
url, err := sanitizeURL(b.Execution.Address)
if err != nil {
return false, errors.Join(err, errors.New("execution client address was not a valid URL"))
if b.Execution.Metrics.Peers.Enabled || b.Execution.Metrics.Latency.Enabled {
var urls []string
for _, addr := range b.Execution.Addresses {
url, err := sanitizeURL(addr)
if err != nil {
return false, errors.Join(err, errors.New("execution client address was not a valid URL"))
}
urls = append(urls, url)
}
b.Execution.Address = url

b.Execution.Addresses = urls
}

if b.SSV.Metrics.Peers.Enabled || b.SSV.Metrics.Connections.Enabled {
Expand Down
4 changes: 3 additions & 1 deletion configs/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ benchmark:
enabled: true

execution:
address:
# Can be a single address or a collection of addresses. Both formats are supported:
# `address: http://127.0.0.1:8080` and `address: [http://127.0.0.1:8080, http://127.0.0.2:8080]`.
address: []
metrics:
peers:
enabled: true
Expand Down
2 changes: 1 addition & 1 deletion docs/benchmark.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Description

The `benchmark` feature allows for evaluating the health and severity of various SSV client-related metrics over time by running the application as a daemon. The addresses of the SSV client, Consensus Client(s), and Execution Client need to be supplied. During runtime, the benchmark will communicate with these clients through API endpoints to gather various metrics that help troubleshoot underperforming SSV clients. Additionally, it will provide infrastructure-related metrics, such as CPU and memory usage, from the environment it is running on. The metrics will be provided in an aggregated manner when the application shuts down (the `--duration` flag sets the execution time. The process can also be interrupted manually).
The `benchmark` feature allows for evaluating the health and severity of various SSV client-related metrics over time by running the application as a daemon. The addresses of the SSV client, Consensus Client(s), and Execution Client(s) need to be supplied. During runtime, the benchmark will communicate with these clients through API endpoints to gather various metrics that help troubleshoot underperforming SSV clients. Additionally, it will provide infrastructure-related metrics, such as CPU and memory usage, from the environment it is running on. The metrics will be provided in an aggregated manner when the application shuts down (the `--duration` flag sets the execution time. The process can also be interrupted manually).

The system is designed to be flexible, allowing different metrics to have their own set of conditions that determine their health status and severity levels.

Expand Down
4 changes: 2 additions & 2 deletions internal/benchmark/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,13 @@ var CMD = &cobra.Command{
func addFlags(cobraCMD *cobra.Command) {
cobraCMD.Flags().Duration(durationFlag, defaultExecutionDuration, "Duration for which the application will run to gather metrics, e.g. '5m'")
cobraCMD.Flags().Uint16(serverPortFlag, defaultServerPort, "Web server port with metrics endpoint exposed, e.g. '8080'")
cobraCMD.Flags().String(consensusAddrFlag, "", "A comma-separated list of consensus client addresses, including the scheme (HTTP/HTTPS) and port. For example: `https://lighthouse:5052,https://prysm:5052`.")
cobraCMD.Flags().String(consensusAddrFlag, "", "A comma-separated list of consensus client addresses, including the scheme (HTTP/HTTPS) and port, e.g. `https://lighthouse:5052,https://prysm:5052`.")
cobraCMD.Flags().Bool(consensusMetricClientFlag, true, "Enable consensus client metric")
cobraCMD.Flags().Bool(consensusMetricLatencyFlag, true, "Enable consensus client latency metric")
cobraCMD.Flags().Bool(consensusMetricPeersFlag, true, "Enable consensus client peers metric")
cobraCMD.Flags().Bool(consensusMetricAttestationFlag, true, "Enable consensus client attestation metric")

cobraCMD.Flags().String(executionAddrFlag, "", "Execution client address with scheme (HTTP/HTTPS) and port, e.g. https://geth:8545")
cobraCMD.Flags().String(executionAddrFlag, "", "A comma-separated list of execution client addresses, including the scheme (HTTP/HTTPS) and port, e.g. `https://geth:8545,https://reth:8545`.")
cobraCMD.Flags().Bool(executionMetricPeersFlag, true, "Enable execution client peers metric")
cobraCMD.Flags().Bool(executionMetricLatencyFlag, true, "Enable execution client latency metric")

Expand Down
44 changes: 25 additions & 19 deletions internal/benchmark/metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func LoadEnabledMetrics(config configs.Config) (map[metric.Group][]metricService

if config.Benchmark.Consensus.Metrics.Attestation.Enabled {
for i, addr := range configs.Values.Benchmark.Consensus.Addresses {
enabledMetrics[metric.Group(metric.Group(fmt.Sprintf("%s-%d", metric.ConsensusGroup, i+1)))] = append(enabledMetrics[metric.Group(fmt.Sprintf("%s-%d", metric.ConsensusGroup, i+1))],
enabledMetrics[metric.Group(fmt.Sprintf("%s-%d", metric.ConsensusGroup, i+1))] = append(enabledMetrics[metric.Group(fmt.Sprintf("%s-%d", metric.ConsensusGroup, i+1))],
consensus.NewAttestationMetric(
addr,
"Attestation",
Expand All @@ -77,29 +77,35 @@ func LoadEnabledMetrics(config configs.Config) (map[metric.Group][]metricService
}

if config.Benchmark.Execution.Metrics.Peers.Enabled {
enabledMetrics[metric.ExecutionGroup] = append(enabledMetrics[metric.ExecutionGroup], execution.NewPeerMetric(
configs.Values.Benchmark.Execution.Address,
"Peers",
time.Second*10,
[]metric.HealthCondition[uint32]{
{Name: execution.PeerCountMeasurement, Threshold: 5, Operator: metric.OperatorLessThanOrEqual, Severity: metric.SeverityHigh},
{Name: execution.PeerCountMeasurement, Threshold: 20, Operator: metric.OperatorLessThanOrEqual, Severity: metric.SeverityMedium},
{Name: execution.PeerCountMeasurement, Threshold: 40, Operator: metric.OperatorLessThanOrEqual, Severity: metric.SeverityLow},
}))
for i, addr := range configs.Values.Benchmark.Execution.Addresses {
enabledMetrics[metric.Group(fmt.Sprintf("%s-%d", metric.ExecutionGroup, i+1))] = append(enabledMetrics[metric.Group(fmt.Sprintf("%s-%d", metric.ExecutionGroup, i+1))],
execution.NewPeerMetric(
addr,
"Peers",
time.Second*10,
[]metric.HealthCondition[uint32]{
{Name: execution.PeerCountMeasurement, Threshold: 5, Operator: metric.OperatorLessThanOrEqual, Severity: metric.SeverityHigh},
{Name: execution.PeerCountMeasurement, Threshold: 20, Operator: metric.OperatorLessThanOrEqual, Severity: metric.SeverityMedium},
{Name: execution.PeerCountMeasurement, Threshold: 40, Operator: metric.OperatorLessThanOrEqual, Severity: metric.SeverityLow},
}))
}
}

if config.Benchmark.Execution.Metrics.Latency.Enabled {
executionClientURL, err := config.Benchmark.Execution.AddrURL()
executionClientURLs, err := config.Benchmark.Execution.AddrURLs()
if err != nil {
return nil, errors.Join(err, errors.New("failed fetching Execution client address as URL"))
return nil, errors.Join(err, errors.New("failed fetching Execution client addresses as URLs"))
}
for i, url := range executionClientURLs {
enabledMetrics[metric.Group(fmt.Sprintf("%s-%d", metric.ExecutionGroup, i+1))] = append(enabledMetrics[metric.Group(fmt.Sprintf("%s-%d", metric.ExecutionGroup, i+1))],
execution.NewLatencyMetric(
url.Host,
"Latency",
time.Second*3,
[]metric.HealthCondition[time.Duration]{
{Name: execution.DurationP90Measurement, Threshold: time.Second, Operator: metric.OperatorGreaterThanOrEqual, Severity: metric.SeverityHigh},
}))
}
enabledMetrics[metric.ExecutionGroup] = append(enabledMetrics[metric.ExecutionGroup], execution.NewLatencyMetric(
executionClientURL.Host,
"Latency",
time.Second*3,
[]metric.HealthCondition[time.Duration]{
{Name: execution.DurationP90Measurement, Threshold: time.Second, Operator: metric.OperatorGreaterThanOrEqual, Severity: metric.SeverityHigh},
}))
}

if config.Benchmark.SSV.Metrics.Peers.Enabled {
Expand Down

0 comments on commit 88deea2

Please sign in to comment.