Skip to content

Commit 19e97b7

Browse files
authored
rule: Added ability to specify multiple remote write targets. (#4927)
This is mainly for non surprising remote write YAML format, but also for ability to add more targets, similar to agent supported model. Signed-off-by: Bartlomiej Plotka <[email protected]>
1 parent c9d7465 commit 19e97b7

File tree

4 files changed

+56
-18
lines changed

4 files changed

+56
-18
lines changed

cmd/thanos/rule.go

+8-5
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ func registerRule(app *extkingpin.App) {
126126
cmd.Flag("eval-interval", "The default evaluation interval to use.").
127127
Default("30s").DurationVar(&conf.evalInterval)
128128

129-
conf.rwConfig = extflag.RegisterPathOrContent(cmd, "remote-write.config", "YAML config for the remote-write server where samples should be sent to (see https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write). This automatically enables stateless mode for ruler and no series will be stored in the ruler's TSDB. If an empty config (or file) is provided, the flag is ignored and ruler is run with its own TSDB.", extflag.WithEnvSubstitution())
129+
conf.rwConfig = extflag.RegisterPathOrContent(cmd, "remote-write.config", "YAML config for the remote-write configurations, that specify servers where samples should be sent to (see https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write). This automatically enables stateless mode for ruler and no series will be stored in the ruler's TSDB. If an empty config (or file) is provided, the flag is ignored and ruler is run with its own TSDB.", extflag.WithEnvSubstitution())
130130

131131
reqLogDecision := cmd.Flag("log.request.decision", "Deprecation Warning - This flag would be soon deprecated, and replaced with `request.logging-config`. Request Logging for logging the start and end of requests. By default this flag is disabled. LogFinishCall: Logs the finish call of the requests. LogStartAndFinishCall: Logs the start and finish call of the requests. NoLogCall: Disable request logging.").Default("").Enum("NoLogCall", "LogFinishCall", "LogStartAndFinishCall", "")
132132

@@ -350,18 +350,21 @@ func runRule(
350350
}
351351

352352
if len(rwCfgYAML) > 0 {
353-
var rwCfg config.RemoteWriteConfig
353+
var rwCfg struct {
354+
RemoteWriteConfigs []*config.RemoteWriteConfig `yaml:"remote_write,omitempty"`
355+
}
354356
if err := yaml.Unmarshal(rwCfgYAML, &rwCfg); err != nil {
355-
return err
357+
return errors.Wrapf(err, "failed to parse remote write config %v", string(rwCfgYAML))
356358
}
357-
walDir := filepath.Join(conf.dataDir, rwCfg.Name)
359+
360+
walDir := filepath.Join(conf.dataDir, "wal")
358361
// flushDeadline is set to 1m, but it is for metadata watcher only so not used here.
359362
remoteStore := remote.NewStorage(logger, reg, func() (int64, error) {
360363
return 0, nil
361364
}, walDir, 1*time.Minute, nil)
362365
if err := remoteStore.ApplyConfig(&config.Config{
363366
GlobalConfig: config.DefaultGlobalConfig,
364-
RemoteWriteConfigs: []*config.RemoteWriteConfig{&rwCfg},
367+
RemoteWriteConfigs: rwCfg.RemoteWriteConfigs,
365368
}); err != nil {
366369
return errors.Wrap(err, "applying config to remote storage")
367370
}

docs/components/rule.md

+28-6
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ Stateless ruler enables nearly indefinite horizontal scalability. Ruler doesn't
210210

211211
The WAL only storage reuses the upstream [Prometheus agent](https://prometheus.io/blog/2021/11/16/agent/) and it is compatible with the old TSDB data. For more design purpose of this mode, please refer to the [proposal](https://thanos.io/tip/proposals-done/202005-scalable-rule-storage.md/).
212212

213-
Stateless mode can be enabled by providing `--remote-write.config` or `--remote-write.config-file` flag. For example:
213+
Stateless mode can be enabled by providing [Prometheus remote write config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write) in file via `--remote-write.config` or inlined `--remote-write.config-file` flag. For example:
214214

215215
```bash
216216
thanos rule \
@@ -227,7 +227,27 @@ thanos rule \
227227
--remote-write.config-file 'rw-config.yaml'
228228
```
229229

230-
The remote write config file is exactly the same as the [Prometheus remote write config format](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write).
230+
Where `rw-config.yaml` could look as follows:
231+
232+
```yaml
233+
remote_write:
234+
- url: http://e2e_test_rule_remote_write-receive-1:8081/api/v1/receive
235+
name: thanos-receiver
236+
follow_redirects: false
237+
- url: https://e2e_test_rule_remote_write-receive-2:443/api/v1/receive
238+
remote_timeout: 30s
239+
follow_redirects: true
240+
queue_config:
241+
capacity: 120000
242+
max_shards: 50
243+
min_shards: 1
244+
max_samples_per_send: 40000
245+
batch_send_deadline: 5s
246+
min_backoff: 5s
247+
max_backoff: 5m
248+
```
249+
250+
You can pass this in file using `--remote-write.config-file=` or inline it using `--remote-write.config=`.
231251

232252
**NOTE:**
233253
1. `metadata_config` is not supported in this mode and will be ignored if provided in the remote write configuration.
@@ -378,17 +398,19 @@ Flags:
378398
--remote-write.config=<content>
379399
Alternative to 'remote-write.config-file' flag
380400
(mutually exclusive). Content of YAML config
381-
for the remote-write server where samples
382-
should be sent to (see
401+
for the remote-write configurations, that
402+
specify servers where samples should be sent to
403+
(see
383404
https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write).
384405
This automatically enables stateless mode for
385406
ruler and no series will be stored in the
386407
ruler's TSDB. If an empty config (or file) is
387408
provided, the flag is ignored and ruler is run
388409
with its own TSDB.
389410
--remote-write.config-file=<file-path>
390-
Path to YAML config for the remote-write server
391-
where samples should be sent to (see
411+
Path to YAML config for the remote-write
412+
configurations, that specify servers where
413+
samples should be sent to (see
392414
https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write).
393415
This automatically enables stateless mode for
394416
ruler and no series will be stored in the

test/e2e/e2ethanos/services.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -551,11 +551,11 @@ func NewTSDBRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.Aler
551551
return newRuler(e, name, ruleSubDir, amCfg, queryCfg, nil)
552552
}
553553

554-
func NewStatelessRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg *config.RemoteWriteConfig) (*e2e.InstrumentedRunnable, error) {
554+
func NewStatelessRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig) (*e2e.InstrumentedRunnable, error) {
555555
return newRuler(e, name, ruleSubDir, amCfg, queryCfg, remoteWriteCfg)
556556
}
557557

558-
func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg *config.RemoteWriteConfig) (*e2e.InstrumentedRunnable, error) {
558+
func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig) (*e2e.InstrumentedRunnable, error) {
559559
dir := filepath.Join(e.SharedDir(), "data", "rule", name)
560560
container := filepath.Join(ContainerSharedDir, "data", "rule", name)
561561

@@ -592,7 +592,9 @@ func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.Alertman
592592
"--resend-delay": "5s",
593593
}
594594
if remoteWriteCfg != nil {
595-
rwCfgBytes, err := yaml.Marshal(remoteWriteCfg)
595+
rwCfgBytes, err := yaml.Marshal(struct {
596+
RemoteWriteConfigs []*config.RemoteWriteConfig `yaml:"remote_write,omitempty"`
597+
}{remoteWriteCfg})
596598
if err != nil {
597599
return nil, errors.Wrapf(err, "generate remote write config: %v", remoteWriteCfg)
598600
}

test/e2e/rule_test.go

+15-4
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,12 @@ func TestRule_CanRemoteWriteData(t *testing.T) {
492492
testutil.Ok(t, e2e.StartAndWaitReady(receiver))
493493
rwURL := mustURLParse(t, e2ethanos.RemoteWriteEndpoint(receiver.InternalEndpoint("remote-write")))
494494

495-
q, err := e2ethanos.NewQuerierBuilder(e, "1", receiver.InternalEndpoint("grpc")).Build()
495+
receiver2, err := e2ethanos.NewIngestingReceiver(e, "2")
496+
testutil.Ok(t, err)
497+
testutil.Ok(t, e2e.StartAndWaitReady(receiver2))
498+
rwURL2 := mustURLParse(t, e2ethanos.RemoteWriteEndpoint(receiver2.InternalEndpoint("remote-write")))
499+
500+
q, err := e2ethanos.NewQuerierBuilder(e, "1", receiver.InternalEndpoint("grpc"), receiver2.InternalEndpoint("grpc")).Build()
496501
testutil.Ok(t, err)
497502
testutil.Ok(t, e2e.StartAndWaitReady(q))
498503
r, err := e2ethanos.NewStatelessRuler(e, "1", rulesSubDir, []alert.AlertmanagerConfig{
@@ -515,9 +520,9 @@ func TestRule_CanRemoteWriteData(t *testing.T) {
515520
Scheme: "http",
516521
},
517522
},
518-
}, &config.RemoteWriteConfig{
519-
URL: &common_cfg.URL{URL: rwURL},
520-
Name: "thanos-receiver",
523+
}, []*config.RemoteWriteConfig{
524+
{URL: &common_cfg.URL{URL: rwURL}, Name: "thanos-receiver"},
525+
{URL: &common_cfg.URL{URL: rwURL2}, Name: "thanos-receiver2"},
521526
})
522527
testutil.Ok(t, err)
523528
testutil.Ok(t, e2e.StartAndWaitReady(r))
@@ -536,6 +541,12 @@ func TestRule_CanRemoteWriteData(t *testing.T) {
536541
"receive": "1",
537542
"tenant_id": "default-tenant",
538543
},
544+
{
545+
"__name__": "test_absent_metric",
546+
"job": "thanos-receive",
547+
"receive": "2",
548+
"tenant_id": "default-tenant",
549+
},
539550
})
540551
})
541552
}

0 commit comments

Comments
 (0)