Skip to content
This repository was archived by the owner on Aug 23, 2023. It is now read-only.

Commit 66ef27a

Browse files
committed
add a "Containers" mode to fakemetrics with configurable churn
1 parent b69bf5b commit 66ef27a

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

cmd/mt-fakemetrics/cmd/containers.go

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// Copyright © 2018 Grafana Labs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cmd
16+
17+
import (
18+
"fmt"
19+
"math/rand"
20+
"strconv"
21+
"strings"
22+
23+
"github.com/spf13/cobra"
24+
25+
"time"
26+
27+
"github.com/grafana/metrictank/clock"
28+
"github.com/grafana/metrictank/cmd/mt-fakemetrics/out"
29+
"github.com/grafana/metrictank/cmd/mt-fakemetrics/policy"
30+
"github.com/grafana/metrictank/schema"
31+
log "github.com/sirupsen/logrus"
32+
)
33+
34+
var containersCmd = &cobra.Command{
35+
Use: "containers",
36+
Short: "Mimic a set of containers - with churn - whose stats get reported at the same time",
37+
Run: func(cmd *cobra.Command, args []string) {
38+
checkOutputs()
39+
period = int(periodDur.Seconds())
40+
41+
// since we have so many small little outputs they would each be sending the same data which would be a bit crazy.
42+
initStats(false, "containers")
43+
churnSplit := strings.Split(churn, ":")
44+
if len(churnSplit) != 3 {
45+
log.Fatalf("churnspec: <cycle time>:<cycle time noise>:<pct of containers to cycle>")
46+
}
47+
cycleDur, err := time.ParseDuration(churnSplit[0])
48+
if err != nil {
49+
log.Fatalf("churnspec: <cycle time>:<cycle time noise>:<pct of containers to cycle>")
50+
}
51+
cycleJitter, err := time.ParseDuration(churnSplit[1])
52+
if err != nil {
53+
log.Fatalf("churnspec: <cycle time>:<cycle time noise>:<pct of containers to cycle>")
54+
}
55+
cyclePct, err := strconv.Atoi(churnSplit[2])
56+
if err != nil {
57+
log.Fatalf("churnspec: <cycle time>:<cycle time noise>:<pct of containers to cycle>")
58+
}
59+
if cyclePct < 0 || cyclePct > 100 {
60+
log.Fatalf("churnspec: <cycle time>:<cycle time noise>:<pct of containers to cycle>")
61+
}
62+
63+
rand.Seed(time.Now().UnixNano())
64+
65+
for i := 0; i < numContainers; i++ {
66+
var key [8]byte
67+
rand.Read(key[:])
68+
containers = append(containers, key)
69+
}
70+
71+
vp, err := policy.ParseValuePolicy(valuePolicy)
72+
if err != nil {
73+
panic(err)
74+
}
75+
monitorContainers(cycleDur, cycleJitter, cyclePct, vp)
76+
},
77+
}
78+
79+
var (
80+
containers [][8]byte
81+
numContainers int
82+
numContainersPerBatch int
83+
metricsPerContainer int
84+
churn string
85+
)
86+
87+
func init() {
88+
rootCmd.AddCommand(containersCmd)
89+
containersCmd.Flags().IntVar(&numContainers, "containers", 1000, "how many containers to simulate")
90+
containersCmd.Flags().IntVar(&numContainersPerBatch, "batch", 10, "how many containers's metrics should go into each batch")
91+
containersCmd.Flags().IntVar(&metricsPerContainer, "metrics", 10, "how many metrics per container to simulate")
92+
containersCmd.Flags().DurationVar(&periodDur, "period", 10*time.Second, "period between metric points (must be a multiple of 1s)")
93+
containersCmd.Flags().StringVar(&churn, "churn", "4h:0h:50", "churn spec: <cycle time>:<cycle time noise>:<pct of containers to cycle>")
94+
containersCmd.Flags().StringVar(&valuePolicy, "value-policy", "", "a value policy (i.e. \"single:1\" \"multiple:1,2,3,4,5\" \"timestamp\" \"daily-sine:<peak>,<offset>,<stdev>\")")
95+
96+
}
97+
98+
// containerChurn keeps pct of the existing containers (random selection) and replaces the other ones with new ones
99+
// during this process, containers also gets shuffled
100+
func containerChurn(pct int) {
101+
rand.Shuffle(len(containers), func(i, j int) {
102+
containers[i], containers[j] = containers[j], containers[i]
103+
})
104+
for i := pct * len(containers) / 100; i < len(containers); i++ {
105+
var key [8]byte
106+
rand.Read(key[:])
107+
containers[i] = key
108+
}
109+
}
110+
111+
func containerFlush(now time.Time, vp policy.ValuePolicy, out out.Out) {
112+
var batch []*schema.MetricData
113+
ts := now.Unix()
114+
var numContainers int
115+
for _, id := range containers {
116+
for i := 0; i < metricsPerContainer; i++ {
117+
met := &schema.MetricData{
118+
Name: fmt.Sprintf("mt-fakemetrics.container.%x.metric.%d", id, i),
119+
OrgId: 1,
120+
Interval: period,
121+
Value: vp.Value(ts),
122+
Unit: "ms",
123+
Mtype: "gauge",
124+
Time: ts,
125+
}
126+
met.SetId()
127+
batch = append(batch, met)
128+
}
129+
numContainers++
130+
if numContainers == numContainersPerBatch {
131+
err := out.Flush(batch)
132+
if err != nil {
133+
log.Error(0, err.Error())
134+
}
135+
numContainers = 0
136+
batch = batch[:0]
137+
}
138+
}
139+
if numContainers > 0 {
140+
err := out.Flush(batch)
141+
if err != nil {
142+
log.Error(0, err.Error())
143+
}
144+
}
145+
}
146+
147+
func monitorContainers(cycleDur, cycleJitter time.Duration, cyclePct int, vp policy.ValuePolicy) {
148+
out := getOutput()
149+
tickFlush := clock.AlignedTickLossless(periodDur)
150+
tickChurn := clock.NewRandomTicker(cycleDur, cycleJitter, true)
151+
for {
152+
select {
153+
case t := <-tickFlush:
154+
containerFlush(t, vp, out)
155+
case <-tickChurn.C:
156+
containerChurn(cyclePct)
157+
}
158+
}
159+
}

docs/tools.md

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Available Commands:
7171
agginput A particular workload good to test performance of carbon-relay-ng aggregators
7272
backfill backfills old data and stops when 'now' is reached
7373
bad Sends out invalid/out-of-order/duplicate metric data
74+
containers Mimic a set of containers - with churn - whose stats get reported at the same time
7475
feed Publishes a realtime feed of data
7576
help Help about any command
7677
resolutionchange Sends out metric with changing intervals, time range 24hours

0 commit comments

Comments
 (0)