-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ingest stage to provide synthetic workload for benchmarks #395
Changes from all commits
0ad41eb
0cd4f57
a775571
f16ee7f
a82b12d
032255f
b00857b
1db643a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* | ||
* Copyright (C) 2023 IBM, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
|
||
package api | ||
|
||
type IngestSynthetic struct { | ||
Connections int `yaml:"connections,omitempty" json:"connections,omitempty" doc:"number of connections to maintain"` | ||
BatchMaxLen int `yaml:"batchMaxLen,omitempty" json:"batchMaxLen,omitempty" doc:"the number of accumulated flows before being forwarded for processing"` | ||
FlowLogsPerMin int `yaml:"flowLogsPerMin,omitempty" json:"flowLogsPerMin,omitempty" doc:"the number of flow logs to send per minute"` | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/* | ||
* Copyright (C) 2023 IBM, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
|
||
package ingest | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/netobserv/flowlogs-pipeline/pkg/api" | ||
"github.com/netobserv/flowlogs-pipeline/pkg/config" | ||
"github.com/netobserv/flowlogs-pipeline/pkg/operational" | ||
"github.com/netobserv/flowlogs-pipeline/pkg/pipeline/utils" | ||
"github.com/prometheus/client_golang/prometheus" | ||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
type IngestSynthetic struct { | ||
params api.IngestSynthetic | ||
exitChan <-chan struct{} | ||
flowLogsProcessed prometheus.Counter | ||
} | ||
|
||
const ( | ||
defaultConnections = 100 | ||
defaultBatchLen = 10 | ||
defaultFlowLogsPerMin = 2000 | ||
) | ||
|
||
var ( | ||
flowLogsProcessed = operational.DefineMetric( | ||
"ingest_synthetic_flows_processed", | ||
"Number of flow logs processed", | ||
operational.TypeCounter, | ||
"stage", | ||
) | ||
) | ||
|
||
// Ingest generates flow logs according to provided parameters | ||
func (ingestS *IngestSynthetic) Ingest(out chan<- config.GenericMap) { | ||
log.Debugf("entering IngestSynthetic Ingest, params = %v", ingestS.params) | ||
// get a list of flow log entries, one per desired connection | ||
// these flow logs will be sent again and again to simulate ongoing traffic on those connections | ||
flowLogs := utils.GenerateConnectionFlowEntries(ingestS.params.Connections) | ||
nLogs := len(flowLogs) | ||
next := 0 | ||
|
||
// compute time interval between batches; divide BatchMaxLen by FlowLogsPerMin and adjust the types | ||
ticker := time.NewTicker(time.Duration(int(time.Minute*time.Duration(ingestS.params.BatchMaxLen)) / ingestS.params.FlowLogsPerMin)) | ||
|
||
// loop forever | ||
for { | ||
select { | ||
case <-ingestS.exitChan: | ||
log.Debugf("exiting IngestSynthetic because of signal") | ||
return | ||
case <-ticker.C: | ||
log.Debugf("sending a batch of %d flow logs from index %d", ingestS.params.BatchMaxLen, next) | ||
for i := 0; i < ingestS.params.BatchMaxLen; i++ { | ||
out <- flowLogs[next] | ||
ingestS.flowLogsProcessed.Inc() | ||
next++ | ||
if next >= nLogs { | ||
next = 0 | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
// NewIngestSynthetic create a new ingester | ||
func NewIngestSynthetic(opMetrics *operational.Metrics, params config.StageParam) (Ingester, error) { | ||
log.Debugf("entering NewIngestSynthetic") | ||
confIngestSynthetic := api.IngestSynthetic{} | ||
if params.Ingest != nil || params.Ingest.Synthetic != nil { | ||
confIngestSynthetic = *params.Ingest.Synthetic | ||
} | ||
if confIngestSynthetic.Connections == 0 { | ||
confIngestSynthetic.Connections = defaultConnections | ||
} | ||
if confIngestSynthetic.FlowLogsPerMin == 0 { | ||
confIngestSynthetic.FlowLogsPerMin = defaultFlowLogsPerMin | ||
} | ||
if confIngestSynthetic.BatchMaxLen == 0 { | ||
confIngestSynthetic.BatchMaxLen = defaultBatchLen | ||
} | ||
log.Debugf("params = %v", confIngestSynthetic) | ||
|
||
return &IngestSynthetic{ | ||
params: confIngestSynthetic, | ||
exitChan: utils.ExitChannel(), | ||
flowLogsProcessed: opMetrics.NewCounter(&flowLogsProcessed, params.Name), | ||
}, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* | ||
* Copyright (C) 2023 IBM, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
|
||
package ingest | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/netobserv/flowlogs-pipeline/pkg/api" | ||
"github.com/netobserv/flowlogs-pipeline/pkg/config" | ||
"github.com/netobserv/flowlogs-pipeline/pkg/operational" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestIngestSynthetic(t *testing.T) { | ||
// check default values | ||
params := config.StageParam{ | ||
Ingest: &config.Ingest{ | ||
Type: "synthetic", | ||
Synthetic: &api.IngestSynthetic{}, | ||
}, | ||
} | ||
ingest, err := NewIngestSynthetic(operational.NewMetrics(&config.MetricsSettings{}), params) | ||
syn := ingest.(*IngestSynthetic) | ||
require.NoError(t, err) | ||
require.Equal(t, defaultBatchLen, syn.params.BatchMaxLen) | ||
require.Equal(t, defaultConnections, syn.params.Connections) | ||
require.Equal(t, defaultFlowLogsPerMin, syn.params.FlowLogsPerMin) | ||
|
||
batchMaxLen := 3 | ||
connections := 20 | ||
flowLogsPerMin := 1000 | ||
synthetic := api.IngestSynthetic{ | ||
BatchMaxLen: batchMaxLen, | ||
Connections: connections, | ||
FlowLogsPerMin: flowLogsPerMin, | ||
} | ||
params = config.StageParam{ | ||
Ingest: &config.Ingest{ | ||
Type: "synthetic", | ||
Synthetic: &synthetic, | ||
}, | ||
} | ||
ingest, err = NewIngestSynthetic(operational.NewMetrics(&config.MetricsSettings{}), params) | ||
syn = ingest.(*IngestSynthetic) | ||
require.NoError(t, err) | ||
require.Equal(t, batchMaxLen, syn.params.BatchMaxLen) | ||
require.Equal(t, connections, syn.params.Connections) | ||
require.Equal(t, flowLogsPerMin, syn.params.FlowLogsPerMin) | ||
|
||
// run the Ingest method in a separate thread | ||
ingestOutput := make(chan config.GenericMap) | ||
go syn.Ingest(ingestOutput) | ||
|
||
type connection struct { | ||
srcAddr string | ||
dstAddr string | ||
srcPort int | ||
dstPort int | ||
protocol int | ||
} | ||
|
||
// Start collecting flows from the ingester and ensure we have the specified number of distinct connections | ||
connectionMap := make(map[connection]int) | ||
for i := 0; i < (3 * connections); i++ { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the hardcoded 3 the batchMaxLen? or just an arbitrary number to make sure we have multiple flow logs per connection? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's just to have (many) more flow logs than connections, and to verify that we accumulate the proper number of connections with multiple flow logs per connection. |
||
flowEntry := <-ingestOutput | ||
conn := connection{ | ||
srcAddr: flowEntry["SrcAddr"].(string), | ||
dstAddr: flowEntry["DstAddr"].(string), | ||
srcPort: flowEntry["SrcPort"].(int), | ||
dstPort: flowEntry["DstPort"].(int), | ||
protocol: flowEntry["Proto"].(int), | ||
} | ||
connectionMap[conn]++ | ||
} | ||
require.Equal(t, connections, len(connectionMap)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The computation of the interval between batches looks complex to me.
I don't think I understand it.
What does it mean to create a
Duration
fromBatchMaxLen
and multiply it bytime.Minute
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added a comment