Skip to content

Commit b7df2d4

Browse files
authored
Add blockgen command to generate blocks of mock data (#191)
Generate blocks of mock data
1 parent fe421bc commit b7df2d4

File tree

8 files changed

+304
-58
lines changed

8 files changed

+304
-58
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Order should be `CHANGE`, `FEATURE`, `ENHANCEMENT`, and `BUGFIX`
44

55
## unreleased/master
66

7+
* [FEATURE] Blockgen: adding a new tool to generate blocks of mock data.
78
* [BUGFIX] Benchtool: avoid duplicate DNS metrics registration when enabling both query and write benchmarking. #188
89
* [ENHANCEMENT] Added the ability to set an explicit user when Cortex is behind basic auth. #187
910

cmd/blockgen/main.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package main
2+
3+
import (
4+
"os"
5+
6+
"gopkg.in/alecthomas/kingpin.v2"
7+
8+
"github.com/grafana/cortex-tools/pkg/commands"
9+
)
10+
11+
var blockGenCommand commands.BlockGenCommand
12+
13+
func main() {
14+
kingpin.Version("0.0.1")
15+
app := kingpin.New("blockgen", "A command-line tool to generate cortex blocks.")
16+
blockGenCommand.Register(app)
17+
kingpin.MustParse(app.Parse(os.Args[1:]))
18+
}

docs/blockgen.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Blockgen
2+
3+
The `blockgen` is a tool which generates Prometheus blocks of mock data. These
4+
blocks can be uploaded to an object store used by Cortex, which may be useful
5+
to profile and benchmark Cortex components when querying or compacting the
6+
generated blocks.
7+
8+
## Config file
9+
10+
The blockgen command requires a config file to be specified.
11+
It uses the same syntax to define what metrics should be generated like the
12+
`benchtool` which is documented [here](benchtool.md).
13+
14+
This is an example config file:
15+
16+
```yaml
17+
replicas: 3
18+
block_gen:
19+
interval: 15s
20+
block_size: 2h
21+
block_dir: /tmp/mock_blocks
22+
max_t: 1623422958000
23+
min_t: 1623336558000
24+
series:
25+
- labels:
26+
- name: label_01
27+
unique_values: 100
28+
value_prefix: label_value_01
29+
- name: label_02
30+
unique_values: 10
31+
value_prefix: label_value_02
32+
name: metric_gauge_random_01
33+
static_labels:
34+
static: "true"
35+
type: gauge-random
36+
- labels:
37+
- name: label_01
38+
unique_values: 100
39+
value_prefix: label_value_01
40+
- name: label_02
41+
unique_values: 10
42+
value_prefix: label_value_02
43+
name: metric_gauge_zero_01
44+
static_labels:
45+
static: "true"
46+
type: gauge-zero
47+
```
48+
49+
50+
## Running it
51+
52+
Assuming the config is in a file named `blockgen.conf` the command could
53+
be run like this:
54+
55+
```
56+
$ ./blockgen --config.file=./blockgen.conf
57+
level=info msg="Generating data" minT=1623336558000 maxT=1623422958000 interval=15000
58+
level=info msg="starting new block" block_id=225463 blocks_left=13
59+
level=info msg="starting new block" block_id=225464 blocks_left=12
60+
level=info msg="starting new block" block_id=225465 blocks_left=11
61+
level=info msg="starting new block" block_id=225466 blocks_left=10
62+
level=info msg="starting new block" block_id=225467 blocks_left=9
63+
level=info msg="starting new block" block_id=225468 blocks_left=8
64+
level=info msg="starting new block" block_id=225469 blocks_left=7
65+
level=info msg="starting new block" block_id=225470 blocks_left=6
66+
level=info msg="starting new block" block_id=225471 blocks_left=5
67+
level=info msg="starting new block" block_id=225472 blocks_left=4
68+
level=info msg="starting new block" block_id=225473 blocks_left=3
69+
level=info msg="starting new block" block_id=225474 blocks_left=2
70+
level=info msg="starting new block" block_id=225475 blocks_left=1
71+
level=info msg=finished block_dir=/tmp/mock_blocks
72+
$
73+
```

pkg/bench/ring_check.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ type RingChecker struct {
4040

4141
Ring *ring.Ring
4242
MemberlistKV *memberlist.KVInitService
43-
workload *writeWorkload
43+
workload *WriteWorkload
4444
logger log.Logger
4545
}
4646

47-
func NewRingChecker(id string, instanceName string, cfg RingCheckConfig, workload *writeWorkload, logger log.Logger) (*RingChecker, error) {
47+
func NewRingChecker(id string, instanceName string, cfg RingCheckConfig, workload *WriteWorkload, logger log.Logger) (*RingChecker, error) {
4848
r := RingChecker{
4949
id: id,
5050
instanceName: instanceName,
@@ -86,7 +86,7 @@ func (r *RingChecker) Run(ctx context.Context) error {
8686
}
8787

8888
func (r *RingChecker) check() {
89-
timeseries := r.workload.generateTimeSeries(r.id, time.Now())
89+
timeseries := r.workload.GenerateTimeSeries(r.id, time.Now())
9090

9191
addrMap := map[string]int{}
9292
for _, s := range timeseries {
@@ -97,7 +97,6 @@ func (r *RingChecker) check() {
9797
token := shardByAllLabels(r.instanceName, s.Labels)
9898

9999
rs, err := r.Ring.Get(token, ring.Write, []ring.InstanceDesc{}, nil, nil)
100-
101100
if err != nil {
102101
level.Warn(r.logger).Log("msg", "unable to get token for metric", "err", err)
103102
continue

pkg/bench/workload.go

Lines changed: 58 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,17 @@ type WorkloadDesc struct {
6161
Write WriteDesc `yaml:"write_options"`
6262
}
6363

64-
type timeseries struct {
64+
type Timeseries struct {
6565
labelSets [][]prompb.Label
6666
lastValue float64
6767
seriesType SeriesType
6868
}
6969

70-
type writeWorkload struct {
71-
replicas int
72-
series []*timeseries
73-
totalSeries int
74-
totalSeriesTypeMap map[SeriesType]int
70+
type WriteWorkload struct {
71+
Replicas int
72+
Series []*Timeseries
73+
TotalSeries int
74+
TotalSeriesTypeMap map[SeriesType]int
7575

7676
missedIterations prometheus.Counter
7777

@@ -80,18 +80,56 @@ type writeWorkload struct {
8080
seriesBufferChan chan []prompb.TimeSeries
8181
}
8282

83-
func newWriteWorkload(workloadDesc WorkloadDesc, reg prometheus.Registerer) *writeWorkload {
83+
func newWriteWorkload(workloadDesc WorkloadDesc, reg prometheus.Registerer) *WriteWorkload {
84+
series, totalSeriesTypeMap := SeriesDescToSeries(workloadDesc.Series)
85+
8486
totalSeries := 0
87+
for _, typeTotal := range totalSeriesTypeMap {
88+
totalSeries += typeTotal
89+
}
90+
91+
// Set batch size to 500 samples if not set
92+
if workloadDesc.Write.BatchSize == 0 {
93+
workloadDesc.Write.BatchSize = 500
94+
}
95+
96+
// Set the write interval to 15 seconds if not set
97+
if workloadDesc.Write.Interval == 0 {
98+
workloadDesc.Write.Interval = time.Second * 15
99+
}
100+
101+
// Set the write timeout to 15 seconds if not set
102+
if workloadDesc.Write.Timeout == 0 {
103+
workloadDesc.Write.Timeout = time.Second * 15
104+
}
105+
106+
return &WriteWorkload{
107+
Replicas: workloadDesc.Replicas,
108+
Series: series,
109+
TotalSeries: totalSeries,
110+
TotalSeriesTypeMap: totalSeriesTypeMap,
111+
options: workloadDesc.Write,
112+
113+
missedIterations: promauto.With(reg).NewCounter(
114+
prometheus.CounterOpts{
115+
Namespace: "benchtool",
116+
Name: "write_iterations_late_total",
117+
Help: "Number of write intervals started late because the previous interval did not complete in time.",
118+
},
119+
),
120+
}
121+
}
122+
123+
func SeriesDescToSeries(seriesDescs []SeriesDesc) ([]*Timeseries, map[SeriesType]int) {
124+
series := []*Timeseries{}
85125
totalSeriesTypeMap := map[SeriesType]int{
86126
GaugeZero: 0,
87127
GaugeRandom: 0,
88128
CounterOne: 0,
89129
CounterRandom: 0,
90130
}
91131

92-
series := []*timeseries{}
93-
94-
for _, seriesDesc := range workloadDesc.Series {
132+
for _, seriesDesc := range seriesDescs {
95133
// Create the metric with a name value
96134
labelSets := [][]prompb.Label{
97135
{
@@ -109,45 +147,15 @@ func newWriteWorkload(workloadDesc WorkloadDesc, reg prometheus.Registerer) *wri
109147
labelSets = addLabelToLabelSet(labelSets, lbl)
110148
}
111149

112-
series = append(series, &timeseries{
150+
series = append(series, &Timeseries{
113151
labelSets: labelSets,
114152
seriesType: seriesDesc.Type,
115153
})
116154
numSeries := len(labelSets)
117-
totalSeries += numSeries
118155
totalSeriesTypeMap[seriesDesc.Type] += numSeries
119156
}
120157

121-
// Set batch size to 500 samples if not set
122-
if workloadDesc.Write.BatchSize == 0 {
123-
workloadDesc.Write.BatchSize = 500
124-
}
125-
126-
// Set the write interval to 15 seconds if not set
127-
if workloadDesc.Write.Interval == 0 {
128-
workloadDesc.Write.Interval = time.Second * 15
129-
}
130-
131-
// Set the write timeout to 15 seconds if not set
132-
if workloadDesc.Write.Timeout == 0 {
133-
workloadDesc.Write.Timeout = time.Second * 15
134-
}
135-
136-
return &writeWorkload{
137-
replicas: workloadDesc.Replicas,
138-
series: series,
139-
totalSeries: totalSeries,
140-
totalSeriesTypeMap: totalSeriesTypeMap,
141-
options: workloadDesc.Write,
142-
143-
missedIterations: promauto.With(reg).NewCounter(
144-
prometheus.CounterOpts{
145-
Namespace: "benchtool",
146-
Name: "write_iterations_late_total",
147-
Help: "Number of write intervals started late because the previous interval did not complete in time.",
148-
},
149-
),
150-
}
158+
return series, totalSeriesTypeMap
151159
}
152160

153161
func addLabelToLabelSet(labelSets [][]prompb.Label, lbl LabelDesc) [][]prompb.Label {
@@ -167,14 +175,14 @@ func addLabelToLabelSet(labelSets [][]prompb.Label, lbl LabelDesc) [][]prompb.La
167175
return newLabelSets
168176
}
169177

170-
func (w *writeWorkload) generateTimeSeries(id string, t time.Time) []prompb.TimeSeries {
178+
func (w *WriteWorkload) GenerateTimeSeries(id string, t time.Time) []prompb.TimeSeries {
171179
now := t.UnixNano() / int64(time.Millisecond)
172180

173-
timeseries := make([]prompb.TimeSeries, 0, w.replicas*w.totalSeries)
174-
for replicaNum := 0; replicaNum < w.replicas; replicaNum++ {
181+
timeseries := make([]prompb.TimeSeries, 0, w.Replicas*w.TotalSeries)
182+
for replicaNum := 0; replicaNum < w.Replicas; replicaNum++ {
175183
replicaLabel := prompb.Label{Name: "bench_replica", Value: fmt.Sprintf("replica-%05d", replicaNum)}
176184
idLabel := prompb.Label{Name: "bench_id", Value: id}
177-
for _, series := range w.series {
185+
for _, series := range w.Series {
178186
var value float64
179187
switch series.seriesType {
180188
case GaugeZero:
@@ -215,7 +223,7 @@ type batchReq struct {
215223
putBack chan []prompb.TimeSeries
216224
}
217225

218-
func (w *writeWorkload) getSeriesBuffer(ctx context.Context) []prompb.TimeSeries {
226+
func (w *WriteWorkload) getSeriesBuffer(ctx context.Context) []prompb.TimeSeries {
219227
select {
220228
case <-ctx.Done():
221229
return nil
@@ -224,7 +232,7 @@ func (w *writeWorkload) getSeriesBuffer(ctx context.Context) []prompb.TimeSeries
224232
}
225233
}
226234

227-
func (w *writeWorkload) generateWriteBatch(ctx context.Context, id string, numBuffers int, seriesChan chan batchReq) error {
235+
func (w *WriteWorkload) generateWriteBatch(ctx context.Context, id string, numBuffers int, seriesChan chan batchReq) error {
228236
w.seriesBufferChan = make(chan []prompb.TimeSeries, numBuffers)
229237
for i := 0; i < numBuffers; i++ {
230238
w.seriesBufferChan <- make([]prompb.TimeSeries, 0, w.options.BatchSize)
@@ -250,10 +258,10 @@ func (w *writeWorkload) generateWriteBatch(ctx context.Context, id string, numBu
250258
timeNow := time.Now()
251259
timeNowMillis := timeNow.UnixNano() / int64(time.Millisecond)
252260
wg := &sync.WaitGroup{}
253-
for replicaNum := 0; replicaNum < w.replicas; replicaNum++ {
261+
for replicaNum := 0; replicaNum < w.Replicas; replicaNum++ {
254262
replicaLabel := prompb.Label{Name: "bench_replica", Value: fmt.Sprintf("replica-%05d", replicaNum)}
255263
idLabel := prompb.Label{Name: "bench_id", Value: id}
256-
for _, series := range w.series {
264+
for _, series := range w.Series {
257265
var value float64
258266
switch series.seriesType {
259267
case GaugeZero:

pkg/bench/workload_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ func TestWorkload_generateTimeSeries(t *testing.T) {
131131
for _, testCase := range testCases {
132132
t.Run(testCase.name, func(t *testing.T) {
133133
w := newWriteWorkload(testCase.workloadDesc, prometheus.NewRegistry())
134-
generatedSeries := w.generateTimeSeries("test-id", time.Now())
134+
generatedSeries := w.GenerateTimeSeries("test-id", time.Now())
135135
require.Equal(t, testCase.numSeries, countUniqueTimeSeries(generatedSeries))
136136
})
137137
}

pkg/bench/write_runner.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,15 @@ type WriteBenchmarkRunner struct {
5050

5151
dnsProvider *dns.Provider
5252

53-
workload *writeWorkload
53+
workload *WriteWorkload
5454

5555
reg prometheus.Registerer
5656
logger log.Logger
5757

5858
requestDuration *prometheus.HistogramVec
5959
}
6060

61-
func NewWriteBenchmarkRunner(id string, tenantName string, cfg WriteBenchConfig, workload *writeWorkload, logger log.Logger, reg prometheus.Registerer) (*WriteBenchmarkRunner, error) {
61+
func NewWriteBenchmarkRunner(id string, tenantName string, cfg WriteBenchConfig, workload *WriteWorkload, logger log.Logger, reg prometheus.Registerer) (*WriteBenchmarkRunner, error) {
6262
writeBench := &WriteBenchmarkRunner{
6363
id: id,
6464
tenantName: tenantName,
@@ -137,7 +137,7 @@ func (w *WriteBenchmarkRunner) Run(ctx context.Context) error {
137137

138138
// Run replicas * 10 write client workers.
139139
// This number will also be used for the number of series buffers to store at once.
140-
numWorkers := w.workload.replicas * 10
140+
numWorkers := w.workload.Replicas * 10
141141

142142
batchChan := make(chan batchReq, 10)
143143
for i := 0; i < numWorkers; i++ {

0 commit comments

Comments
 (0)