Skip to content

Commit f075590

Browse files
author
Andrea Spacca
authored
Benchmark stream command (#1584)
Similarly to benchmark rally command, generate schema-b documents for a given integration. Instead of creating a rally track out of them we will stream them, according to a configurable rate, directly to an ES cluster, using bulk requets
1 parent a5c8a8e commit f075590

File tree

6 files changed

+1024
-0
lines changed

6 files changed

+1024
-0
lines changed

README.md

+16
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,16 @@ These benchmarks allow you to benchmark an integration corpus with rally.
159159

160160
For details on how to configure rally benchmarks for a package, review the [HOWTO guide](./docs/howto/rally_benchmarking.md).
161161

162+
#### Stream Benchmarks
163+
164+
These benchmarks allow you to benchmark ingesting real time data.
165+
You can stream data to a remote ES cluster setting the following environment variables:
166+
167+
ELASTIC_PACKAGE_ELASTICSEARCH_HOST=https://my-deployment.es.eu-central-1.aws.foundit.no
168+
ELASTIC_PACKAGE_ELASTICSEARCH_USERNAME=elastic
169+
ELASTIC_PACKAGE_ELASTICSEARCH_PASSWORD=changeme
170+
ELASTIC_PACKAGE_KIBANA_HOST=https://my-deployment.kb.eu-central-1.aws.foundit.no:9243
171+
162172
#### System Benchmarks
163173

164174
These benchmarks allow you to benchmark an integration end to end.
@@ -177,6 +187,12 @@ _Context: package_
177187

178188
Run rally benchmarks for the package (esrally needs to be installed in the path of the system).
179189

190+
### `elastic-package benchmark stream`
191+
192+
_Context: package_
193+
194+
Run stream benchmarks for the package.
195+
180196
### `elastic-package benchmark system`
181197

182198
_Context: package_

cmd/benchmark.go

+137
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
benchcommon "github.com/elastic/elastic-package/internal/benchrunner/runners/common"
2626
"github.com/elastic/elastic-package/internal/benchrunner/runners/pipeline"
2727
"github.com/elastic/elastic-package/internal/benchrunner/runners/rally"
28+
"github.com/elastic/elastic-package/internal/benchrunner/runners/stream"
2829
"github.com/elastic/elastic-package/internal/benchrunner/runners/system"
2930
"github.com/elastic/elastic-package/internal/cobraext"
3031
"github.com/elastic/elastic-package/internal/common"
@@ -47,6 +48,16 @@ These benchmarks allow you to benchmark an integration corpus with rally.
4748
4849
For details on how to configure rally benchmarks for a package, review the [HOWTO guide](./docs/howto/rally_benchmarking.md).
4950
51+
#### Stream Benchmarks
52+
53+
These benchmarks allow you to benchmark ingesting real time data.
54+
You can stream data to a remote ES cluster setting the following environment variables:
55+
56+
ELASTIC_PACKAGE_ELASTICSEARCH_HOST=https://my-deployment.es.eu-central-1.aws.foundit.no
57+
ELASTIC_PACKAGE_ELASTICSEARCH_USERNAME=elastic
58+
ELASTIC_PACKAGE_ELASTICSEARCH_PASSWORD=changeme
59+
ELASTIC_PACKAGE_KIBANA_HOST=https://my-deployment.kb.eu-central-1.aws.foundit.no:9243
60+
5061
#### System Benchmarks
5162
5263
These benchmarks allow you to benchmark an integration end to end.
@@ -68,6 +79,9 @@ func setupBenchmarkCommand() *cobraext.Command {
6879
rallyCmd := getRallyCommand()
6980
cmd.AddCommand(rallyCmd)
7081

82+
streamCmd := getStreamCommand()
83+
cmd.AddCommand(streamCmd)
84+
7185
systemCmd := getSystemCommand()
7286
cmd.AddCommand(systemCmd)
7387

@@ -381,6 +395,129 @@ func getPackageNameAndVersion(packageFromRegistry string) (string, string, error
381395
return name, version, nil
382396
}
383397

398+
func getStreamCommand() *cobra.Command {
399+
cmd := &cobra.Command{
400+
Use: "stream",
401+
Short: "Run stream benchmarks",
402+
Long: "Run stream benchmarks for the package",
403+
Args: cobra.NoArgs,
404+
RunE: streamCommandAction,
405+
}
406+
407+
cmd.Flags().StringP(cobraext.BenchNameFlagName, "", "", cobraext.BenchNameFlagDescription)
408+
cmd.Flags().String(cobraext.VariantFlagName, "", cobraext.VariantFlagDescription)
409+
cmd.Flags().DurationP(cobraext.BenchStreamBackFillFlagName, "", 15*time.Minute, cobraext.BenchStreamBackFillFlagDescription)
410+
cmd.Flags().Uint64P(cobraext.BenchStreamEventsPerPeriodFlagName, "", 10, cobraext.BenchStreamEventsPerPeriodFlagDescription)
411+
cmd.Flags().DurationP(cobraext.BenchStreamPeriodDurationFlagName, "", 10*time.Second, cobraext.BenchStreamPeriodDurationFlagDescription)
412+
cmd.Flags().BoolP(cobraext.BenchStreamPerformCleanupFlagName, "", false, cobraext.BenchStreamPerformCleanupFlagDescription)
413+
cmd.Flags().StringP(cobraext.BenchStreamTimestampFieldFlagName, "", "timestamp", cobraext.BenchStreamTimestampFieldFlagDescription)
414+
415+
return cmd
416+
}
417+
418+
func streamCommandAction(cmd *cobra.Command, args []string) error {
419+
cmd.Println("Run stream benchmarks for the package")
420+
421+
variant, err := cmd.Flags().GetString(cobraext.VariantFlagName)
422+
if err != nil {
423+
return cobraext.FlagParsingError(err, cobraext.VariantFlagName)
424+
}
425+
426+
benchName, err := cmd.Flags().GetString(cobraext.BenchNameFlagName)
427+
if err != nil {
428+
return cobraext.FlagParsingError(err, cobraext.BenchNameFlagName)
429+
}
430+
431+
backFill, err := cmd.Flags().GetDuration(cobraext.BenchStreamBackFillFlagName)
432+
if err != nil {
433+
return cobraext.FlagParsingError(err, cobraext.BenchStreamBackFillFlagName)
434+
}
435+
436+
if backFill < 0 {
437+
return cobraext.FlagParsingError(errors.New("cannot be a negative duration"), cobraext.BenchStreamBackFillFlagName)
438+
}
439+
440+
eventsPerPeriod, err := cmd.Flags().GetUint64(cobraext.BenchStreamEventsPerPeriodFlagName)
441+
if err != nil {
442+
return cobraext.FlagParsingError(err, cobraext.BenchStreamEventsPerPeriodFlagName)
443+
}
444+
445+
if eventsPerPeriod <= 0 {
446+
return cobraext.FlagParsingError(errors.New("cannot be zero or negative"), cobraext.BenchStreamEventsPerPeriodFlagName)
447+
}
448+
449+
periodDuration, err := cmd.Flags().GetDuration(cobraext.BenchStreamPeriodDurationFlagName)
450+
if err != nil {
451+
return cobraext.FlagParsingError(err, cobraext.BenchStreamPeriodDurationFlagName)
452+
}
453+
454+
if periodDuration < time.Nanosecond {
455+
return cobraext.FlagParsingError(errors.New("cannot be a negative duration"), cobraext.BenchStreamPeriodDurationFlagName)
456+
}
457+
458+
performCleanup, err := cmd.Flags().GetBool(cobraext.BenchStreamPerformCleanupFlagName)
459+
if err != nil {
460+
return cobraext.FlagParsingError(err, cobraext.BenchStreamPerformCleanupFlagName)
461+
}
462+
463+
timestampField, err := cmd.Flags().GetString(cobraext.BenchStreamTimestampFieldFlagName)
464+
if err != nil {
465+
return cobraext.FlagParsingError(err, cobraext.BenchStreamTimestampFieldFlagName)
466+
}
467+
468+
packageRootPath, found, err := packages.FindPackageRoot()
469+
if !found {
470+
return errors.New("package root not found")
471+
}
472+
if err != nil {
473+
return fmt.Errorf("locating package root failed: %w", err)
474+
}
475+
476+
profile, err := cobraext.GetProfileFlag(cmd)
477+
if err != nil {
478+
return err
479+
}
480+
481+
signal.Enable()
482+
483+
esClient, err := stack.NewElasticsearchClientFromProfile(profile)
484+
if err != nil {
485+
return fmt.Errorf("can't create Elasticsearch client: %w", err)
486+
}
487+
err = esClient.CheckHealth(cmd.Context())
488+
if err != nil {
489+
return err
490+
}
491+
492+
kc, err := stack.NewKibanaClientFromProfile(profile)
493+
if err != nil {
494+
return fmt.Errorf("can't create Kibana client: %w", err)
495+
}
496+
497+
withOpts := []stream.OptionFunc{
498+
stream.WithVariant(variant),
499+
stream.WithBenchmarkName(benchName),
500+
stream.WithBackFill(backFill),
501+
stream.WithEventsPerPeriod(eventsPerPeriod),
502+
stream.WithPeriodDuration(periodDuration),
503+
stream.WithPerformCleanup(performCleanup),
504+
stream.WithTimestampField(timestampField),
505+
stream.WithPackageRootPath(packageRootPath),
506+
stream.WithESAPI(esClient.API),
507+
stream.WithKibanaClient(kc),
508+
stream.WithProfile(profile),
509+
}
510+
511+
runner := stream.NewStreamBenchmark(stream.NewOptions(withOpts...))
512+
513+
_, err = benchrunner.Run(runner)
514+
if err != nil {
515+
return fmt.Errorf("error running package stream benchmarks: %w", err)
516+
}
517+
518+
return nil
519+
}
520+
384521
func getSystemCommand() *cobra.Command {
385522
cmd := &cobra.Command{
386523
Use: "system",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License;
3+
// you may not use this file except in compliance with the Elastic License.
4+
5+
package stream
6+
7+
import (
8+
"time"
9+
10+
"github.com/elastic/elastic-package/internal/elasticsearch"
11+
"github.com/elastic/elastic-package/internal/kibana"
12+
"github.com/elastic/elastic-package/internal/profile"
13+
)
14+
15+
// Options contains benchmark runner options.
16+
type Options struct {
17+
ESAPI *elasticsearch.API
18+
KibanaClient *kibana.Client
19+
BenchName string
20+
BackFill time.Duration
21+
EventsPerPeriod uint64
22+
PeriodDuration time.Duration
23+
PerformCleanup bool
24+
TimestampField string
25+
PackageRootPath string
26+
Variant string
27+
Profile *profile.Profile
28+
}
29+
30+
type ClientOptions struct {
31+
Host string
32+
Username string
33+
Password string
34+
}
35+
type OptionFunc func(*Options)
36+
37+
func NewOptions(fns ...OptionFunc) Options {
38+
var opts Options
39+
for _, fn := range fns {
40+
fn(&opts)
41+
}
42+
return opts
43+
}
44+
45+
func WithESAPI(api *elasticsearch.API) OptionFunc {
46+
return func(opts *Options) {
47+
opts.ESAPI = api
48+
}
49+
}
50+
51+
func WithKibanaClient(c *kibana.Client) OptionFunc {
52+
return func(opts *Options) {
53+
opts.KibanaClient = c
54+
}
55+
}
56+
57+
func WithPackageRootPath(path string) OptionFunc {
58+
return func(opts *Options) {
59+
opts.PackageRootPath = path
60+
}
61+
}
62+
63+
func WithBenchmarkName(name string) OptionFunc {
64+
return func(opts *Options) {
65+
opts.BenchName = name
66+
}
67+
}
68+
69+
func WithVariant(name string) OptionFunc {
70+
return func(opts *Options) {
71+
opts.Variant = name
72+
}
73+
}
74+
75+
func WithProfile(p *profile.Profile) OptionFunc {
76+
return func(opts *Options) {
77+
opts.Profile = p
78+
}
79+
}
80+
81+
func WithBackFill(d time.Duration) OptionFunc {
82+
return func(opts *Options) {
83+
opts.BackFill = -1 * d
84+
}
85+
}
86+
87+
func WithEventsPerPeriod(e uint64) OptionFunc {
88+
return func(opts *Options) {
89+
opts.EventsPerPeriod = e
90+
}
91+
}
92+
93+
func WithPeriodDuration(d time.Duration) OptionFunc {
94+
return func(opts *Options) {
95+
opts.PeriodDuration = d
96+
}
97+
}
98+
99+
func WithPerformCleanup(p bool) OptionFunc {
100+
return func(opts *Options) {
101+
opts.PerformCleanup = p
102+
}
103+
}
104+
105+
func WithTimestampField(t string) OptionFunc {
106+
return func(opts *Options) {
107+
opts.TimestampField = t
108+
}
109+
}

0 commit comments

Comments
 (0)