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 }