go.etcd.io/etcd@v3.3.27+incompatible/etcdserver/stats/leader.go (about) 1 // Copyright 2015 The etcd Authors 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 stats 16 17 import ( 18 "encoding/json" 19 "math" 20 "sync" 21 "time" 22 ) 23 24 // LeaderStats is used by the leader in an etcd cluster, and encapsulates 25 // statistics about communication with its followers 26 type LeaderStats struct { 27 leaderStats 28 sync.Mutex 29 } 30 31 type leaderStats struct { 32 // Leader is the ID of the leader in the etcd cluster. 33 // TODO(jonboulle): clarify that these are IDs, not names 34 Leader string `json:"leader"` 35 Followers map[string]*FollowerStats `json:"followers"` 36 } 37 38 // NewLeaderStats generates a new LeaderStats with the given id as leader 39 func NewLeaderStats(id string) *LeaderStats { 40 return &LeaderStats{ 41 leaderStats: leaderStats{ 42 Leader: id, 43 Followers: make(map[string]*FollowerStats), 44 }, 45 } 46 } 47 48 func (ls *LeaderStats) JSON() []byte { 49 ls.Lock() 50 stats := ls.leaderStats 51 ls.Unlock() 52 b, err := json.Marshal(stats) 53 // TODO(jonboulle): appropriate error handling? 54 if err != nil { 55 plog.Errorf("error marshalling leader stats (%v)", err) 56 } 57 return b 58 } 59 60 func (ls *LeaderStats) Follower(name string) *FollowerStats { 61 ls.Lock() 62 defer ls.Unlock() 63 fs, ok := ls.Followers[name] 64 if !ok { 65 fs = &FollowerStats{} 66 fs.Latency.Minimum = 1 << 63 67 ls.Followers[name] = fs 68 } 69 return fs 70 } 71 72 // FollowerStats encapsulates various statistics about a follower in an etcd cluster 73 type FollowerStats struct { 74 Latency LatencyStats `json:"latency"` 75 Counts CountsStats `json:"counts"` 76 77 sync.Mutex 78 } 79 80 // LatencyStats encapsulates latency statistics. 81 type LatencyStats struct { 82 Current float64 `json:"current"` 83 Average float64 `json:"average"` 84 averageSquare float64 85 StandardDeviation float64 `json:"standardDeviation"` 86 Minimum float64 `json:"minimum"` 87 Maximum float64 `json:"maximum"` 88 } 89 90 // CountsStats encapsulates raft statistics. 91 type CountsStats struct { 92 Fail uint64 `json:"fail"` 93 Success uint64 `json:"success"` 94 } 95 96 // Succ updates the FollowerStats with a successful send 97 func (fs *FollowerStats) Succ(d time.Duration) { 98 fs.Lock() 99 defer fs.Unlock() 100 101 total := float64(fs.Counts.Success) * fs.Latency.Average 102 totalSquare := float64(fs.Counts.Success) * fs.Latency.averageSquare 103 104 fs.Counts.Success++ 105 106 fs.Latency.Current = float64(d) / (1000000.0) 107 108 if fs.Latency.Current > fs.Latency.Maximum { 109 fs.Latency.Maximum = fs.Latency.Current 110 } 111 112 if fs.Latency.Current < fs.Latency.Minimum { 113 fs.Latency.Minimum = fs.Latency.Current 114 } 115 116 fs.Latency.Average = (total + fs.Latency.Current) / float64(fs.Counts.Success) 117 fs.Latency.averageSquare = (totalSquare + fs.Latency.Current*fs.Latency.Current) / float64(fs.Counts.Success) 118 119 // sdv = sqrt(avg(x^2) - avg(x)^2) 120 fs.Latency.StandardDeviation = math.Sqrt(fs.Latency.averageSquare - fs.Latency.Average*fs.Latency.Average) 121 } 122 123 // Fail updates the FollowerStats with an unsuccessful send 124 func (fs *FollowerStats) Fail() { 125 fs.Lock() 126 defer fs.Unlock() 127 fs.Counts.Fail++ 128 }