@@ -69,6 +69,9 @@ const (
69
69
// mergeSlicesParallelism is a constant of how much go routines we should use to merge slices, and
70
70
// it was based on empirical observation: See BenchmarkMergeSlicesParallel
71
71
mergeSlicesParallelism = 8
72
+
73
+ sampleMetricTypeFloat = "float"
74
+ sampleMetricTypeHistogram = "histogram"
72
75
)
73
76
74
77
// Distributor is a storage.SampleAppender and a client.Querier which
@@ -274,7 +277,7 @@ func New(cfg Config, clientConfig ingester_client.Config, limits *validation.Ove
274
277
Namespace : "cortex" ,
275
278
Name : "distributor_received_samples_total" ,
276
279
Help : "The total number of received samples, excluding rejected and deduped samples." ,
277
- }, []string {"user" }),
280
+ }, []string {"user" , "type" }),
278
281
receivedExemplars : promauto .With (reg ).NewCounterVec (prometheus.CounterOpts {
279
282
Namespace : "cortex" ,
280
283
Name : "distributor_received_exemplars_total" ,
@@ -289,7 +292,7 @@ func New(cfg Config, clientConfig ingester_client.Config, limits *validation.Ove
289
292
Namespace : "cortex" ,
290
293
Name : "distributor_samples_in_total" ,
291
294
Help : "The total number of samples that have come in to the distributor, including rejected or deduped samples." ,
292
- }, []string {"user" }),
295
+ }, []string {"user" , "type" }),
293
296
incomingExemplars : promauto .With (reg ).NewCounterVec (prometheus.CounterOpts {
294
297
Namespace : "cortex" ,
295
298
Name : "distributor_exemplars_in_total" ,
@@ -424,10 +427,12 @@ func (d *Distributor) cleanupInactiveUser(userID string) {
424
427
425
428
d .HATracker .CleanupHATrackerMetricsForUser (userID )
426
429
427
- d .receivedSamples .DeleteLabelValues (userID )
430
+ d .receivedSamples .DeleteLabelValues (userID , sampleMetricTypeFloat )
431
+ d .receivedSamples .DeleteLabelValues (userID , sampleMetricTypeHistogram )
428
432
d .receivedExemplars .DeleteLabelValues (userID )
429
433
d .receivedMetadata .DeleteLabelValues (userID )
430
- d .incomingSamples .DeleteLabelValues (userID )
434
+ d .incomingSamples .DeleteLabelValues (userID , sampleMetricTypeFloat )
435
+ d .incomingSamples .DeleteLabelValues (userID , sampleMetricTypeHistogram )
431
436
d .incomingExemplars .DeleteLabelValues (userID )
432
437
d .incomingMetadata .DeleteLabelValues (userID )
433
438
d .nonHASamples .DeleteLabelValues (userID )
@@ -543,7 +548,7 @@ func (d *Distributor) validateSeries(ts cortexpb.PreallocTimeseries, userID stri
543
548
// Only alloc when data present
544
549
samples = make ([]cortexpb.Sample , 0 , len (ts .Samples ))
545
550
for _ , s := range ts .Samples {
546
- if err := validation .ValidateSample (limits , userID , ts .Labels , s ); err != nil {
551
+ if err := validation .ValidateSampleTimestamp (limits , userID , ts .Labels , s . TimestampMs ); err != nil {
547
552
return emptyPreallocSeries , err
548
553
}
549
554
samples = append (samples , s )
@@ -570,8 +575,13 @@ func (d *Distributor) validateSeries(ts cortexpb.PreallocTimeseries, userID stri
570
575
if len (ts .Histograms ) > 0 {
571
576
// Only alloc when data present
572
577
histograms = make ([]cortexpb.Histogram , 0 , len (ts .Histograms ))
573
- // TODO(yeya24): we need to have validations for native histograms
574
- // at some point. Skip validations for now.
578
+ for _ , h := range ts .Histograms {
579
+ // TODO(yeya24): add other validations for native histogram.
580
+ // For example, Prometheus scrape has bucket limit and schema check.
581
+ if err := validation .ValidateSampleTimestamp (limits , userID , ts .Labels , h .TimestampMs ); err != nil {
582
+ return emptyPreallocSeries , err
583
+ }
584
+ }
575
585
histograms = append (histograms , ts .Histograms ... )
576
586
}
577
587
@@ -603,14 +613,17 @@ func (d *Distributor) Push(ctx context.Context, req *cortexpb.WriteRequest) (*co
603
613
now := time .Now ()
604
614
d .activeUsers .UpdateUserTimestamp (userID , now )
605
615
606
- numSamples := 0
616
+ numFloatSamples := 0
617
+ numHistogramSamples := 0
607
618
numExemplars := 0
608
619
for _ , ts := range req .Timeseries {
609
- numSamples += len (ts .Samples ) + len (ts .Histograms )
620
+ numFloatSamples += len (ts .Samples )
621
+ numHistogramSamples += len (ts .Histograms )
610
622
numExemplars += len (ts .Exemplars )
611
623
}
612
624
// Count the total samples, exemplars in, prior to validation or deduplication, for comparison with other metrics.
613
- d .incomingSamples .WithLabelValues (userID ).Add (float64 (numSamples ))
625
+ d .incomingSamples .WithLabelValues (userID , sampleMetricTypeFloat ).Add (float64 (numFloatSamples ))
626
+ d .incomingSamples .WithLabelValues (userID , sampleMetricTypeHistogram ).Add (float64 (numFloatSamples ))
614
627
d .incomingExemplars .WithLabelValues (userID ).Add (float64 (numExemplars ))
615
628
// Count the total number of metadata in.
616
629
d .incomingMetadata .WithLabelValues (userID ).Add (float64 (len (req .Metadata )))
@@ -638,31 +651,32 @@ func (d *Distributor) Push(ctx context.Context, req *cortexpb.WriteRequest) (*co
638
651
639
652
if errors .Is (err , ha.ReplicasNotMatchError {}) {
640
653
// These samples have been deduped.
641
- d .dedupedSamples .WithLabelValues (userID , cluster ).Add (float64 (numSamples ))
654
+ d .dedupedSamples .WithLabelValues (userID , cluster ).Add (float64 (numFloatSamples + numHistogramSamples ))
642
655
return nil , httpgrpc .Errorf (http .StatusAccepted , err .Error ())
643
656
}
644
657
645
658
if errors .Is (err , ha.TooManyReplicaGroupsError {}) {
646
- validation .DiscardedSamples .WithLabelValues (validation .TooManyHAClusters , userID ).Add (float64 (numSamples ))
659
+ validation .DiscardedSamples .WithLabelValues (validation .TooManyHAClusters , userID ).Add (float64 (numFloatSamples + numHistogramSamples ))
647
660
return nil , httpgrpc .Errorf (http .StatusBadRequest , err .Error ())
648
661
}
649
662
650
663
return nil , err
651
664
}
652
665
// If there wasn't an error but removeReplica is false that means we didn't find both HA labels.
653
666
if ! removeReplica {
654
- d .nonHASamples .WithLabelValues (userID ).Add (float64 (numSamples ))
667
+ d .nonHASamples .WithLabelValues (userID ).Add (float64 (numFloatSamples + numHistogramSamples ))
655
668
}
656
669
}
657
670
658
671
// A WriteRequest can only contain series or metadata but not both. This might change in the future.
659
- seriesKeys , validatedTimeseries , validatedSamples , validatedExemplars , firstPartialErr , err := d .prepareSeriesKeys (ctx , req , userID , limits , removeReplica )
672
+ seriesKeys , validatedTimeseries , validatedFloatSamples , validatedHistogramSamples , validatedExemplars , firstPartialErr , err := d .prepareSeriesKeys (ctx , req , userID , limits , removeReplica )
660
673
if err != nil {
661
674
return nil , err
662
675
}
663
676
metadataKeys , validatedMetadata , firstPartialErr := d .prepareMetadataKeys (req , limits , userID , firstPartialErr )
664
677
665
- d .receivedSamples .WithLabelValues (userID ).Add (float64 (validatedSamples ))
678
+ d .receivedSamples .WithLabelValues (userID , sampleMetricTypeFloat ).Add (float64 (validatedFloatSamples ))
679
+ d .receivedSamples .WithLabelValues (userID , sampleMetricTypeHistogram ).Add (float64 (validatedHistogramSamples ))
666
680
d .receivedExemplars .WithLabelValues (userID ).Add (float64 (validatedExemplars ))
667
681
d .receivedMetadata .WithLabelValues (userID ).Add (float64 (len (validatedMetadata )))
668
682
@@ -673,18 +687,19 @@ func (d *Distributor) Push(ctx context.Context, req *cortexpb.WriteRequest) (*co
673
687
return & cortexpb.WriteResponse {}, firstPartialErr
674
688
}
675
689
676
- totalN := validatedSamples + validatedExemplars + len (validatedMetadata )
690
+ totalSamples := validatedFloatSamples + validatedHistogramSamples
691
+ totalN := totalSamples + validatedExemplars + len (validatedMetadata )
677
692
if ! d .ingestionRateLimiter .AllowN (now , userID , totalN ) {
678
693
// Ensure the request slice is reused if the request is rate limited.
679
694
cortexpb .ReuseSlice (req .Timeseries )
680
695
681
- validation .DiscardedSamples .WithLabelValues (validation .RateLimited , userID ).Add (float64 (validatedSamples ))
696
+ validation .DiscardedSamples .WithLabelValues (validation .RateLimited , userID ).Add (float64 (totalSamples ))
682
697
validation .DiscardedExemplars .WithLabelValues (validation .RateLimited , userID ).Add (float64 (validatedExemplars ))
683
698
validation .DiscardedMetadata .WithLabelValues (validation .RateLimited , userID ).Add (float64 (len (validatedMetadata )))
684
699
// Return a 429 here to tell the client it is going too fast.
685
700
// Client may discard the data or slow down and re-send.
686
701
// Prometheus v2.26 added a remote-write option 'retry_on_http_429'.
687
- return nil , httpgrpc .Errorf (http .StatusTooManyRequests , "ingestion rate limit (%v) exceeded while adding %d samples and %d metadata" , d .ingestionRateLimiter .Limit (now , userID ), validatedSamples , len (validatedMetadata ))
702
+ return nil , httpgrpc .Errorf (http .StatusTooManyRequests , "ingestion rate limit (%v) exceeded while adding %d samples and %d metadata" , d .ingestionRateLimiter .Limit (now , userID ), totalSamples , len (validatedMetadata ))
688
703
}
689
704
690
705
// totalN included samples and metadata. Ingester follows this pattern when computing its ingestion rate.
@@ -806,15 +821,16 @@ func (d *Distributor) prepareMetadataKeys(req *cortexpb.WriteRequest, limits *va
806
821
return metadataKeys , validatedMetadata , firstPartialErr
807
822
}
808
823
809
- func (d * Distributor ) prepareSeriesKeys (ctx context.Context , req * cortexpb.WriteRequest , userID string , limits * validation.Limits , removeReplica bool ) ([]uint32 , []cortexpb.PreallocTimeseries , int , int , error , error ) {
824
+ func (d * Distributor ) prepareSeriesKeys (ctx context.Context , req * cortexpb.WriteRequest , userID string , limits * validation.Limits , removeReplica bool ) ([]uint32 , []cortexpb.PreallocTimeseries , int , int , int , error , error ) {
810
825
pSpan , _ := opentracing .StartSpanFromContext (ctx , "prepareSeriesKeys" )
811
826
defer pSpan .Finish ()
812
827
813
828
// For each timeseries or samples, we compute a hash to distribute across ingesters;
814
829
// check each sample/metadata and discard if outside limits.
815
830
validatedTimeseries := make ([]cortexpb.PreallocTimeseries , 0 , len (req .Timeseries ))
816
831
seriesKeys := make ([]uint32 , 0 , len (req .Timeseries ))
817
- validatedSamples := 0
832
+ validatedFloatSamples := 0
833
+ validatedHistogramSamples := 0
818
834
validatedExemplars := 0
819
835
820
836
var firstPartialErr error
@@ -835,7 +851,9 @@ func (d *Distributor) prepareSeriesKeys(ctx context.Context, req *cortexpb.Write
835
851
if len (ts .Samples ) > 0 {
836
852
latestSampleTimestampMs = max (latestSampleTimestampMs , ts .Samples [len (ts .Samples )- 1 ].TimestampMs )
837
853
}
838
- // TODO(yeya24): use timestamp of the latest native histogram in the series as well.
854
+ if len (ts .Histograms ) > 0 {
855
+ latestSampleTimestampMs = max (latestSampleTimestampMs , ts .Histograms [len (ts .Histograms )- 1 ].TimestampMs )
856
+ }
839
857
840
858
if mrc := limits .MetricRelabelConfigs ; len (mrc ) > 0 {
841
859
l , _ := relabel .Process (cortexpb .FromLabelAdaptersToLabels (ts .Labels ), mrc ... )
@@ -881,7 +899,7 @@ func (d *Distributor) prepareSeriesKeys(ctx context.Context, req *cortexpb.Write
881
899
// label and dropped labels (if any)
882
900
key , err := d .tokenForLabels (userID , ts .Labels )
883
901
if err != nil {
884
- return nil , nil , 0 , 0 , nil , err
902
+ return nil , nil , 0 , 0 , 0 , nil , err
885
903
}
886
904
validatedSeries , validationErr := d .validateSeries (ts , userID , skipLabelNameValidation , limits )
887
905
@@ -900,11 +918,11 @@ func (d *Distributor) prepareSeriesKeys(ctx context.Context, req *cortexpb.Write
900
918
901
919
seriesKeys = append (seriesKeys , key )
902
920
validatedTimeseries = append (validatedTimeseries , validatedSeries )
903
- // TODO(yeya24): add histogram samples as well when supported.
904
- validatedSamples += len (ts .Samples )
921
+ validatedFloatSamples += len ( ts . Samples )
922
+ validatedHistogramSamples += len (ts .Histograms )
905
923
validatedExemplars += len (ts .Exemplars )
906
924
}
907
- return seriesKeys , validatedTimeseries , validatedSamples , validatedExemplars , firstPartialErr , nil
925
+ return seriesKeys , validatedTimeseries , validatedFloatSamples , validatedHistogramSamples , validatedExemplars , firstPartialErr , nil
908
926
}
909
927
910
928
func sortLabelsIfNeeded (labels []cortexpb.LabelAdapter ) {
0 commit comments