Skip to content

Commit 127a36e

Browse files
otel(tests): align BenchmarkFilebeatOTelThroughputMockES with presets (#51714) (#51898)
* otel(tests): align BenchmarkFilebeatOTelThroughputMockES with presets The current benchmark options don't reflect what Elastic Agent actually renders into otel-merged.yaml for a real deployment. Turned the benchmark into a table test covering all presets, settings pulled from a 9.5.0 bb benchmark diagnostics bundles: preset mem queue (events/min_events/timeout) exporter batch (max/min/flush) conns/consumers/queue_size throughput 12800/1600/5s 1600/1600/5s 4/4/12800 balanced 3200/1600/10s 1600/1600/10s 1/1/3200 scale 3200/1600/20s 1600/1600/20s 1/1/3200 latency 4100/2050/1s 50/50/1s 1/1/4100 The total events processed by the benchmark are a multiple of the queue size, to avoid waiting on the flush timeout for the last batches which skews the benchmark numbers. Also expanded the benchmark to have 3 filebeatreceiver instances, each in its own pipeline, with a beatprocessor. Measured events/sec at different -cpu values (go test -bench=... -cpu=N). At the host's full core count, results are dominated by the ES exporter, batching, and I/O rather than processor CPU cost: preset -cpu=32 (full) -cpu=2 throughput ~97.6k ~34.8k balanced ~55.8k ~33.9k scale ~56.2k ~33.5k latency ~35.4k ~26.6k -cpu=2 approximates a throttled 4-core/cpu50 host, closer to the real benchmark suite's methodology, and is where processor-side CPU improvements are expected to actually show up in this benchmark's numbers. * reuse presets from es output (cherry picked from commit d6a567b) Co-authored-by: Mauri de Souza Meneguzzo <mauri870@gmail.com>
1 parent a9611a1 commit 127a36e

1 file changed

Lines changed: 165 additions & 20 deletions

File tree

x-pack/filebeat/tests/integration/otel_test.go

Lines changed: 165 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ import (
3636
"github.com/gofrs/uuid/v5"
3737

3838
"github.com/elastic/beats/v7/libbeat/features"
39+
esoutput "github.com/elastic/beats/v7/libbeat/outputs/elasticsearch"
3940
libbeattesting "github.com/elastic/beats/v7/libbeat/testing"
4041
"github.com/elastic/beats/v7/libbeat/tests/integration"
4142
"github.com/elastic/beats/v7/x-pack/otel/oteltest"
4243
"github.com/elastic/beats/v7/x-pack/otel/oteltestcol"
44+
"github.com/elastic/elastic-agent-libs/config"
4345
"github.com/elastic/elastic-agent-libs/mapstr"
4446
"github.com/elastic/elastic-agent-libs/testing/estools"
4547
"github.com/elastic/go-elasticsearch/v8"
@@ -2094,9 +2096,90 @@ service:
20942096
}
20952097
}
20962098

2097-
// BenchmarkFilebeatOTelThroughputMockES measures end-to-end EPS through a full otel pipeline.
2099+
type benchPreset struct {
2100+
name string
2101+
2102+
// beats queue
2103+
memQueueEvents int
2104+
memQueueMinEvents int
2105+
memQueueFlushTimeout string
2106+
2107+
// sending_queue
2108+
maxConnsPerHost int
2109+
expBatchMaxSize int
2110+
expBatchMinSize int
2111+
expFlushTimeout string
2112+
expNumConsumers int
2113+
expQueueSize int
2114+
eventCountPerRecv int
2115+
}
2116+
2117+
// presetFields mirrors the subset of elasticsearch.ElasticsearchConfig that
2118+
// elasticsearch.ApplyPreset's preset configs set, so the real preset values
2119+
// can be unpacked directly instead of hand-copied into benchPresets.
2120+
type presetFields struct {
2121+
BulkMaxSize int `config:"bulk_max_size"`
2122+
Worker int `config:"worker"`
2123+
QueueMemEvents int `config:"queue.mem.events"`
2124+
QueueMemFlushMinEvents int `config:"queue.mem.flush.min_events"`
2125+
QueueMemFlushTimeout time.Duration `config:"queue.mem.flush.timeout"`
2126+
}
2127+
2128+
// benchPresetFromName builds a benchPreset from the real preset config
2129+
// applied by elasticsearch.ApplyPreset, keeping the benchmark's queue/batch
2130+
// settings in sync with the actual preset definitions instead of a
2131+
// hand-maintained copy. eventCountPerRecv is picked as the nearest multiple
2132+
// of the preset's min_events/bulk_max_size threshold to targetEventCount, so
2133+
// the benchmark's fixed, bounded event count doesn't leave a leftover
2134+
// partial batch that has to wait out the full flush timeout before the
2135+
// mem-queue (or the exporter's own sending_queue) releases it.
2136+
func benchPresetFromName(name string, targetEventCount int) benchPreset {
2137+
_, presetCfg, err := esoutput.ApplyPreset(name, config.NewConfig())
2138+
if err != nil {
2139+
panic(fmt.Sprintf("unknown benchmark preset %q: %v", name, err))
2140+
}
2141+
2142+
var pf presetFields
2143+
if err := presetCfg.Unpack(&pf); err != nil {
2144+
panic(fmt.Sprintf("failed to unpack benchmark preset %q: %v", name, err))
2145+
}
2146+
2147+
eventCountPerRecv := (targetEventCount / pf.QueueMemFlushMinEvents) * pf.QueueMemFlushMinEvents
2148+
2149+
return benchPreset{
2150+
name: name,
2151+
memQueueEvents: pf.QueueMemEvents,
2152+
memQueueMinEvents: pf.QueueMemFlushMinEvents,
2153+
memQueueFlushTimeout: pf.QueueMemFlushTimeout.String(),
2154+
maxConnsPerHost: pf.Worker,
2155+
expBatchMaxSize: pf.BulkMaxSize,
2156+
expBatchMinSize: pf.BulkMaxSize,
2157+
expFlushTimeout: pf.QueueMemFlushTimeout.String(),
2158+
expNumConsumers: pf.Worker,
2159+
expQueueSize: pf.QueueMemEvents,
2160+
eventCountPerRecv: eventCountPerRecv,
2161+
}
2162+
}
2163+
2164+
var benchPresets = []benchPreset{
2165+
benchPresetFromName("throughput", 32_000),
2166+
benchPresetFromName("balanced", 32_000),
2167+
benchPresetFromName("scale", 32_000),
2168+
benchPresetFromName("latency", 32_000),
2169+
}
2170+
2171+
// BenchmarkFilebeatOTelThroughputMockES measures end-to-end EPS through a full
2172+
// otel pipeline, once per benchmark preset (see benchPresets).
20982173
func BenchmarkFilebeatOTelThroughputMockES(b *testing.B) {
2099-
const eventCount = 100_000
2174+
for _, preset := range benchPresets {
2175+
b.Run(preset.name, func(b *testing.B) {
2176+
benchmarkFilebeatOTelThroughputMockES(b, preset)
2177+
})
2178+
}
2179+
}
2180+
2181+
func benchmarkFilebeatOTelThroughputMockES(b *testing.B, preset benchPreset) {
2182+
eventCount := preset.eventCountPerRecv * 3
21002183

21012184
for b.Loop() {
21022185
b.StopTimer()
@@ -2134,15 +2217,41 @@ func BenchmarkFilebeatOTelThroughputMockES(b *testing.B) {
21342217
)
21352218

21362219
cfg := renderOtelConfig(b, `receivers:
2137-
filebeatreceiver:
2220+
filebeatreceiver/1:
21382221
filebeat:
21392222
inputs:
21402223
- type: benchmark
21412224
enabled: true
2142-
count: {{.EventCount}}
2143-
path.home: {{.PathHome}}
2225+
count: {{.EventCountPerReceiver}}
2226+
path.home: {{.PathHome}}/1
21442227
setup.template.enabled: false
2145-
queue.mem.flush.timeout: 0s
2228+
queue.mem.events: {{.MemQueueEvents}}
2229+
queue.mem.flush.min_events: {{.MemQueueMinEvents}}
2230+
queue.mem.flush.timeout: {{.MemQueueFlushTimeout}}
2231+
processors: []
2232+
filebeatreceiver/2:
2233+
filebeat:
2234+
inputs:
2235+
- type: benchmark
2236+
enabled: true
2237+
count: {{.EventCountPerReceiver}}
2238+
path.home: {{.PathHome}}/2
2239+
setup.template.enabled: false
2240+
queue.mem.events: {{.MemQueueEvents}}
2241+
queue.mem.flush.min_events: {{.MemQueueMinEvents}}
2242+
queue.mem.flush.timeout: {{.MemQueueFlushTimeout}}
2243+
processors: []
2244+
filebeatreceiver/3:
2245+
filebeat:
2246+
inputs:
2247+
- type: benchmark
2248+
enabled: true
2249+
count: {{.EventCountPerReceiver}}
2250+
path.home: {{.PathHome}}/3
2251+
setup.template.enabled: false
2252+
queue.mem.events: {{.MemQueueEvents}}
2253+
queue.mem.flush.min_events: {{.MemQueueMinEvents}}
2254+
queue.mem.flush.timeout: {{.MemQueueFlushTimeout}}
21462255
processors: []
21472256
exporters:
21482257
elasticsearch:
@@ -2152,28 +2261,46 @@ exporters:
21522261
endpoints:
21532262
- {{.ESEndpoint}}
21542263
logs_index: benchtest
2155-
max_conns_per_host: 4
2264+
max_conns_per_host: {{.MaxConnsPerHost}}
21562265
sending_queue:
21572266
batch:
2158-
flush_timeout: 5s
2159-
max_size: 1600
2160-
min_size: 0
2267+
flush_timeout: {{.ExpFlushTimeout}}
2268+
max_size: {{.ExpBatchMaxSize}}
2269+
min_size: {{.ExpBatchMinSize}}
21612270
sizer: items
21622271
block_on_overflow: true
21632272
enabled: true
2164-
num_consumers: 4
2165-
queue_size: 12800
2273+
num_consumers: {{.ExpNumConsumers}}
2274+
queue_size: {{.ExpQueueSize}}
21662275
wait_for_result: true
21672276
suppress_conflict_errors: true
21682277
processors:
21692278
beat:
21702279
processors:
21712280
- add_host_metadata: ~
2281+
- add_fields:
2282+
target: ""
2283+
fields:
2284+
env: staging
21722285
service:
21732286
pipelines:
2174-
logs:
2287+
logs/1:
21752288
receivers:
2176-
- filebeatreceiver
2289+
- filebeatreceiver/1
2290+
processors:
2291+
- beat
2292+
exporters:
2293+
- elasticsearch
2294+
logs/2:
2295+
receivers:
2296+
- filebeatreceiver/2
2297+
processors:
2298+
- beat
2299+
exporters:
2300+
- elasticsearch
2301+
logs/3:
2302+
receivers:
2303+
- filebeatreceiver/3
21772304
processors:
21782305
- beat
21792306
exporters:
@@ -2184,13 +2311,31 @@ service:
21842311
metrics:
21852312
level: none
21862313
`, struct {
2187-
EventCount int
2188-
PathHome string
2189-
ESEndpoint string
2314+
EventCountPerReceiver int
2315+
PathHome string
2316+
ESEndpoint string
2317+
MemQueueEvents int
2318+
MemQueueMinEvents int
2319+
MemQueueFlushTimeout string
2320+
MaxConnsPerHost int
2321+
ExpBatchMaxSize int
2322+
ExpBatchMinSize int
2323+
ExpFlushTimeout string
2324+
ExpNumConsumers int
2325+
ExpQueueSize int
21902326
}{
2191-
EventCount: eventCount,
2192-
PathHome: tmpDir,
2193-
ESEndpoint: mockServer.URL,
2327+
EventCountPerReceiver: preset.eventCountPerRecv,
2328+
PathHome: tmpDir,
2329+
ESEndpoint: mockServer.URL,
2330+
MemQueueEvents: preset.memQueueEvents,
2331+
MemQueueMinEvents: preset.memQueueMinEvents,
2332+
MemQueueFlushTimeout: preset.memQueueFlushTimeout,
2333+
MaxConnsPerHost: preset.maxConnsPerHost,
2334+
ExpBatchMaxSize: preset.expBatchMaxSize,
2335+
ExpBatchMinSize: preset.expBatchMinSize,
2336+
ExpFlushTimeout: preset.expFlushTimeout,
2337+
ExpNumConsumers: preset.expNumConsumers,
2338+
ExpQueueSize: preset.expQueueSize,
21942339
})
21952340

21962341
b.StartTimer()

0 commit comments

Comments
 (0)