vitess.io/vitess@v0.16.2/go/vt/vtorc/discovery/aggregated.go (about)

     1  /*
     2     Copyright 2017 Simon J Mudd
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package discovery
    18  
    19  import (
    20  	"time"
    21  
    22  	"github.com/montanaflynn/stats"
    23  
    24  	"vitess.io/vitess/go/vt/vtorc/collection"
    25  )
    26  
    27  // AggregatedDiscoveryMetrics contains aggregated metrics for instance discovery.
    28  // Called from api/discovery-metrics-aggregated/:seconds
    29  type AggregatedDiscoveryMetrics struct {
    30  	FirstSeen                       time.Time // timestamp of the first data seen
    31  	LastSeen                        time.Time // timestamp of the last data seen
    32  	CountDistinctInstanceKeys       int       // number of distinct Instances seen (note: this may not be true: distinct = succeeded + failed)
    33  	CountDistinctOkInstanceKeys     int       // number of distinct Instances which succeeded
    34  	CountDistinctFailedInstanceKeys int       // number of distinct Instances which failed
    35  	FailedDiscoveries               uint64    // number of failed discoveries
    36  	SuccessfulDiscoveries           uint64    // number of successful discoveries
    37  	MeanTotalSeconds                float64
    38  	MeanBackendSeconds              float64
    39  	MeanInstanceSeconds             float64
    40  	FailedMeanTotalSeconds          float64
    41  	FailedMeanBackendSeconds        float64
    42  	FailedMeanInstanceSeconds       float64
    43  	MaxTotalSeconds                 float64
    44  	MaxBackendSeconds               float64
    45  	MaxInstanceSeconds              float64
    46  	FailedMaxTotalSeconds           float64
    47  	FailedMaxBackendSeconds         float64
    48  	FailedMaxInstanceSeconds        float64
    49  	MedianTotalSeconds              float64
    50  	MedianBackendSeconds            float64
    51  	MedianInstanceSeconds           float64
    52  	FailedMedianTotalSeconds        float64
    53  	FailedMedianBackendSeconds      float64
    54  	FailedMedianInstanceSeconds     float64
    55  	P95TotalSeconds                 float64
    56  	P95BackendSeconds               float64
    57  	P95InstanceSeconds              float64
    58  	FailedP95TotalSeconds           float64
    59  	FailedP95BackendSeconds         float64
    60  	FailedP95InstanceSeconds        float64
    61  }
    62  
    63  // aggregate returns the aggregate values of the given metrics (assumed to be Metric)
    64  func aggregate(results []collection.Metric) AggregatedDiscoveryMetrics {
    65  	if len(results) == 0 {
    66  		return AggregatedDiscoveryMetrics{}
    67  	}
    68  
    69  	var (
    70  		first time.Time
    71  		last  time.Time
    72  	)
    73  
    74  	type counterKey string
    75  	type hostKey string
    76  	type timerKey string
    77  	const (
    78  		FailedDiscoveries     counterKey = "FailedDiscoveries"
    79  		Discoveries                      = "Discoveries"
    80  		InstanceKeys          hostKey    = "InstanceKeys"
    81  		OkInstanceKeys                   = "OkInstanceKeys"
    82  		FailedInstanceKeys               = "FailedInstanceKeys"
    83  		TotalSeconds          timerKey   = "TotalSeconds"
    84  		BackendSeconds                   = "BackendSeconds"
    85  		InstanceSeconds                  = "InstanceSeconds"
    86  		FailedTotalSeconds               = "FailedTotalSeconds"
    87  		FailedBackendSeconds             = "FailedBackendSeconds"
    88  		FailedInstanceSeconds            = "FailedInstanceSeconds"
    89  	)
    90  
    91  	counters := make(map[counterKey]uint64)         // map of string based counters
    92  	names := make(map[hostKey]map[string]int)       // map of string based names (using a map)
    93  	timings := make(map[timerKey]stats.Float64Data) // map of string based float64 values
    94  
    95  	// initialise counters
    96  	for _, v := range []counterKey{FailedDiscoveries, Discoveries} {
    97  		counters[v] = 0
    98  	}
    99  	// initialise names
   100  	for _, v := range []hostKey{InstanceKeys, FailedInstanceKeys, OkInstanceKeys} {
   101  		names[v] = make(map[string]int)
   102  	}
   103  	// initialise timers
   104  	for _, v := range []timerKey{TotalSeconds, BackendSeconds, InstanceSeconds, FailedTotalSeconds, FailedBackendSeconds, FailedInstanceSeconds} {
   105  		timings[v] = nil
   106  	}
   107  
   108  	// iterate over results storing required values
   109  	for _, v2 := range results {
   110  		v := v2.(*Metric) // convert to the right type
   111  
   112  		// first and last
   113  		if first.IsZero() || first.After(v.Timestamp) {
   114  			first = v.Timestamp
   115  		}
   116  		if last.Before(v.Timestamp) {
   117  			last = v.Timestamp
   118  		}
   119  
   120  		// different names
   121  		x := names[InstanceKeys]
   122  		x[v.InstanceKey.String()] = 1 // Value doesn't matter
   123  		names[InstanceKeys] = x
   124  
   125  		if v.Err == nil {
   126  			// ok names
   127  			x := names[OkInstanceKeys]
   128  			x[v.InstanceKey.String()] = 1 // Value doesn't matter
   129  			names[OkInstanceKeys] = x
   130  		} else {
   131  			// failed names
   132  			x := names[FailedInstanceKeys]
   133  			x[v.InstanceKey.String()] = 1 // Value doesn't matter
   134  			names[FailedInstanceKeys] = x
   135  		}
   136  
   137  		// discoveries
   138  		counters[Discoveries]++
   139  		if v.Err != nil {
   140  			counters[FailedDiscoveries]++
   141  		}
   142  
   143  		// All timings
   144  		timings[TotalSeconds] = append(timings[TotalSeconds], v.TotalLatency.Seconds())
   145  		timings[BackendSeconds] = append(timings[BackendSeconds], v.BackendLatency.Seconds())
   146  		timings[InstanceSeconds] = append(timings[InstanceSeconds], v.InstanceLatency.Seconds())
   147  
   148  		// Failed timings
   149  		if v.Err != nil {
   150  			timings[FailedTotalSeconds] = append(timings[FailedTotalSeconds], v.TotalLatency.Seconds())
   151  			timings[FailedBackendSeconds] = append(timings[FailedBackendSeconds], v.BackendLatency.Seconds())
   152  			timings[FailedInstanceSeconds] = append(timings[FailedInstanceSeconds], v.InstanceLatency.Seconds())
   153  		}
   154  	}
   155  
   156  	return AggregatedDiscoveryMetrics{
   157  		FirstSeen:                       first,
   158  		LastSeen:                        last,
   159  		CountDistinctInstanceKeys:       len(names[InstanceKeys]),
   160  		CountDistinctOkInstanceKeys:     len(names[OkInstanceKeys]),
   161  		CountDistinctFailedInstanceKeys: len(names[FailedInstanceKeys]),
   162  		FailedDiscoveries:               counters[FailedDiscoveries],
   163  		SuccessfulDiscoveries:           counters[Discoveries],
   164  		MeanTotalSeconds:                mean(timings[TotalSeconds]),
   165  		MeanBackendSeconds:              mean(timings[BackendSeconds]),
   166  		MeanInstanceSeconds:             mean(timings[InstanceSeconds]),
   167  		FailedMeanTotalSeconds:          mean(timings[FailedTotalSeconds]),
   168  		FailedMeanBackendSeconds:        mean(timings[FailedBackendSeconds]),
   169  		FailedMeanInstanceSeconds:       mean(timings[FailedInstanceSeconds]),
   170  		MaxTotalSeconds:                 max(timings[TotalSeconds]),
   171  		MaxBackendSeconds:               max(timings[BackendSeconds]),
   172  		MaxInstanceSeconds:              max(timings[InstanceSeconds]),
   173  		FailedMaxTotalSeconds:           max(timings[FailedTotalSeconds]),
   174  		FailedMaxBackendSeconds:         max(timings[FailedBackendSeconds]),
   175  		FailedMaxInstanceSeconds:        max(timings[FailedInstanceSeconds]),
   176  		MedianTotalSeconds:              median(timings[TotalSeconds]),
   177  		MedianBackendSeconds:            median(timings[BackendSeconds]),
   178  		MedianInstanceSeconds:           median(timings[InstanceSeconds]),
   179  		FailedMedianTotalSeconds:        median(timings[FailedTotalSeconds]),
   180  		FailedMedianBackendSeconds:      median(timings[FailedBackendSeconds]),
   181  		FailedMedianInstanceSeconds:     median(timings[FailedInstanceSeconds]),
   182  		P95TotalSeconds:                 percentile(timings[TotalSeconds], 95),
   183  		P95BackendSeconds:               percentile(timings[BackendSeconds], 95),
   184  		P95InstanceSeconds:              percentile(timings[InstanceSeconds], 95),
   185  		FailedP95TotalSeconds:           percentile(timings[FailedTotalSeconds], 95),
   186  		FailedP95BackendSeconds:         percentile(timings[FailedBackendSeconds], 95),
   187  		FailedP95InstanceSeconds:        percentile(timings[FailedInstanceSeconds], 95),
   188  	}
   189  }
   190  
   191  // AggregatedSince returns a large number of aggregated metrics
   192  // based on the raw metrics collected since the given time.
   193  func AggregatedSince(c *collection.Collection, t time.Time) (AggregatedDiscoveryMetrics, error) {
   194  	results, err := c.Since(t)
   195  	if err != nil {
   196  		return AggregatedDiscoveryMetrics{}, err
   197  	}
   198  
   199  	return aggregate(results), nil
   200  }