...

Source file src/go.etcd.io/etcd/server/v3/etcdserver/api/v2stats/leader.go

Documentation: go.etcd.io/etcd/server/v3/etcdserver/api/v2stats

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

View as plain text