github.com/sym3tri/etcd@v0.2.1-0.20140422215517-a563d82f95d6/server/peer_server.go (about)

     1  package server
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"math/rand"
     9  	"net/http"
    10  	"net/url"
    11  	"sort"
    12  	"strconv"
    13  	"strings"
    14  	"sync"
    15  	"time"
    16  
    17  	"github.com/coreos/etcd/third_party/github.com/goraft/raft"
    18  	"github.com/coreos/etcd/third_party/github.com/gorilla/mux"
    19  
    20  	"github.com/coreos/etcd/discovery"
    21  	etcdErr "github.com/coreos/etcd/error"
    22  	"github.com/coreos/etcd/log"
    23  	"github.com/coreos/etcd/metrics"
    24  	"github.com/coreos/etcd/pkg/btrfs"
    25  	"github.com/coreos/etcd/store"
    26  )
    27  
    28  const (
    29  	// ThresholdMonitorTimeout is the time between log notifications that the
    30  	// Raft heartbeat is too close to the election timeout.
    31  	ThresholdMonitorTimeout = 5 * time.Second
    32  
    33  	// ActiveMonitorTimeout is the time between checks on the active size of
    34  	// the cluster. If the active size is different than the actual size then
    35  	// etcd attempts to promote/demote to bring it to the correct number.
    36  	ActiveMonitorTimeout = 1 * time.Second
    37  
    38  	// PeerActivityMonitorTimeout is the time between checks for dead nodes in
    39  	// the cluster.
    40  	PeerActivityMonitorTimeout = 1 * time.Second
    41  )
    42  
    43  const (
    44  	peerModeFlag    = 0
    45  	standbyModeFlag = 1
    46  )
    47  
    48  type PeerServerConfig struct {
    49  	Name          string
    50  	Scheme        string
    51  	URL           string
    52  	SnapshotCount int
    53  	RetryTimes    int
    54  	RetryInterval float64
    55  }
    56  
    57  type PeerServer struct {
    58  	Config         PeerServerConfig
    59  	clusterConfig  *ClusterConfig
    60  	raftServer     raft.Server
    61  	server         *Server
    62  	joinIndex      uint64
    63  	followersStats *raftFollowersStats
    64  	serverStats    *raftServerStats
    65  	registry       *Registry
    66  	store          store.Store
    67  	snapConf       *snapshotConf
    68  	mode           Mode
    69  
    70  	closeChan            chan bool
    71  	timeoutThresholdChan chan interface{}
    72  
    73  	standbyPeerURL   string
    74  	standbyClientURL string
    75  
    76  	metrics *metrics.Bucket
    77  	sync.Mutex
    78  }
    79  
    80  // TODO: find a good policy to do snapshot
    81  type snapshotConf struct {
    82  	// Etcd will check if snapshot is need every checkingInterval
    83  	checkingInterval time.Duration
    84  
    85  	// The index when the last snapshot happened
    86  	lastIndex uint64
    87  
    88  	// If the incremental number of index since the last snapshot
    89  	// exceeds the snapshot Threshold, etcd will do a snapshot
    90  	snapshotThr uint64
    91  }
    92  
    93  func NewPeerServer(psConfig PeerServerConfig, registry *Registry, store store.Store, mb *metrics.Bucket, followersStats *raftFollowersStats, serverStats *raftServerStats) *PeerServer {
    94  	s := &PeerServer{
    95  		Config:         psConfig,
    96  		clusterConfig:  NewClusterConfig(),
    97  		registry:       registry,
    98  		store:          store,
    99  		followersStats: followersStats,
   100  		serverStats:    serverStats,
   101  
   102  		timeoutThresholdChan: make(chan interface{}, 1),
   103  
   104  		metrics: mb,
   105  	}
   106  
   107  	return s
   108  }
   109  
   110  func (s *PeerServer) SetRaftServer(raftServer raft.Server) {
   111  	s.snapConf = &snapshotConf{
   112  		checkingInterval: time.Second * 3,
   113  		// this is not accurate, we will update raft to provide an api
   114  		lastIndex:   raftServer.CommitIndex(),
   115  		snapshotThr: uint64(s.Config.SnapshotCount),
   116  	}
   117  
   118  	raftServer.AddEventListener(raft.StateChangeEventType, s.raftEventLogger)
   119  	raftServer.AddEventListener(raft.LeaderChangeEventType, s.raftEventLogger)
   120  	raftServer.AddEventListener(raft.TermChangeEventType, s.raftEventLogger)
   121  	raftServer.AddEventListener(raft.AddPeerEventType, s.raftEventLogger)
   122  	raftServer.AddEventListener(raft.RemovePeerEventType, s.raftEventLogger)
   123  	raftServer.AddEventListener(raft.HeartbeatIntervalEventType, s.raftEventLogger)
   124  	raftServer.AddEventListener(raft.ElectionTimeoutThresholdEventType, s.raftEventLogger)
   125  
   126  	raftServer.AddEventListener(raft.HeartbeatEventType, s.recordMetricEvent)
   127  
   128  	s.raftServer = raftServer
   129  }
   130  
   131  // Mode retrieves the current mode of the server.
   132  func (s *PeerServer) Mode() Mode {
   133  	return s.mode
   134  }
   135  
   136  // SetMode updates the current mode of the server.
   137  // Switching to a peer mode will start the Raft server.
   138  // Switching to a standby mode will stop the Raft server.
   139  func (s *PeerServer) setMode(mode Mode) {
   140  	s.mode = mode
   141  
   142  	switch mode {
   143  	case PeerMode:
   144  		if !s.raftServer.Running() {
   145  			s.raftServer.Start()
   146  		}
   147  	case StandbyMode:
   148  		if s.raftServer.Running() {
   149  			s.raftServer.Stop()
   150  		}
   151  	}
   152  }
   153  
   154  // ClusterConfig retrieves the current cluster configuration.
   155  func (s *PeerServer) ClusterConfig() *ClusterConfig {
   156  	return s.clusterConfig
   157  }
   158  
   159  // SetClusterConfig updates the current cluster configuration.
   160  // Adjusting the active size will cause the PeerServer to demote peers or
   161  // promote standbys to match the new size.
   162  func (s *PeerServer) SetClusterConfig(c *ClusterConfig) {
   163  	// Set minimums.
   164  	if c.ActiveSize < MinActiveSize {
   165  		c.ActiveSize = MinActiveSize
   166  	}
   167  	if c.PromoteDelay < MinPromoteDelay {
   168  		c.PromoteDelay = MinPromoteDelay
   169  	}
   170  
   171  	s.clusterConfig = c
   172  }
   173  
   174  // Try all possible ways to find clusters to join
   175  // Include log data in -data-dir, -discovery and -peers
   176  //
   177  // Peer discovery follows this order:
   178  // 1. previous peers in -data-dir
   179  // 2. -discovery
   180  // 3. -peers
   181  //
   182  // TODO(yichengq): RaftServer should be started as late as possible.
   183  // Current implementation to start it is not that good,
   184  // and should be refactored later.
   185  func (s *PeerServer) findCluster(discoverURL string, peers []string) {
   186  	name := s.Config.Name
   187  	isNewNode := s.raftServer.IsLogEmpty()
   188  
   189  	// Try its best to find possible peers, and connect with them.
   190  	if !isNewNode {
   191  		// It is not allowed to join the cluster with existing peer address
   192  		// This prevents old node joining with different name by mistake.
   193  		if !s.checkPeerAddressNonconflict() {
   194  			log.Fatalf("%v is not allowed to join the cluster with existing URL %v", s.Config.Name, s.Config.URL)
   195  		}
   196  
   197  		// Take old nodes into account.
   198  		allPeers := s.getKnownPeers()
   199  		// Discover registered peers.
   200  		// TODO(yichengq): It may mess up discoverURL if this is
   201  		// set wrong by mistake. This may need to refactor discovery
   202  		// module. Fix it later.
   203  		if discoverURL != "" {
   204  			discoverPeers, _ := s.handleDiscovery(discoverURL)
   205  			allPeers = append(allPeers, discoverPeers...)
   206  		}
   207  		allPeers = append(allPeers, peers...)
   208  		allPeers = s.removeSelfFromList(allPeers)
   209  
   210  		// If there is possible peer list, use it to find cluster.
   211  		if len(allPeers) > 0 {
   212  			// TODO(yichengq): joinCluster may fail if there's no leader for
   213  			// current cluster. It should wait if the cluster is under
   214  			// leader election, or the node with changed IP cannot join
   215  			// the cluster then.
   216  			if err := s.startAsFollower(allPeers, 1); err == nil {
   217  				log.Debugf("%s joins to the previous cluster %v", name, allPeers)
   218  				return
   219  			}
   220  
   221  			log.Warnf("%s cannot connect to previous cluster %v", name, allPeers)
   222  		}
   223  
   224  		// TODO(yichengq): Think about the action that should be done
   225  		// if it cannot connect any of the previous known node.
   226  		s.raftServer.Start()
   227  		log.Debugf("%s is restarting the cluster %v", name, allPeers)
   228  		return
   229  	}
   230  
   231  	// Attempt cluster discovery
   232  	if discoverURL != "" {
   233  		discoverPeers, discoverErr := s.handleDiscovery(discoverURL)
   234  		// It is registered in discover url
   235  		if discoverErr == nil {
   236  			// start as a leader in a new cluster
   237  			if len(discoverPeers) == 0 {
   238  				log.Debugf("%s is starting a new cluster via discover service", name)
   239  				s.startAsLeader()
   240  			} else {
   241  				log.Debugf("%s is joining a cluster %v via discover service", name, discoverPeers)
   242  				if err := s.startAsFollower(discoverPeers, s.Config.RetryTimes); err != nil {
   243  					log.Fatal(err)
   244  				}
   245  			}
   246  			return
   247  		}
   248  		log.Warnf("%s failed to connect discovery service[%v]: %v", name, discoverURL, discoverErr)
   249  
   250  		if len(peers) == 0 {
   251  			log.Fatalf("%s, the new leader, must register itself to discovery service as required", name)
   252  		}
   253  	}
   254  
   255  	if len(peers) > 0 {
   256  		if err := s.startAsFollower(peers, s.Config.RetryTimes); err != nil {
   257  			log.Fatalf("%s cannot connect to existing cluster %v", name, peers)
   258  		}
   259  		return
   260  	}
   261  
   262  	log.Infof("%s is starting a new cluster.", s.Config.Name)
   263  	s.startAsLeader()
   264  	return
   265  }
   266  
   267  // Start the raft server
   268  func (s *PeerServer) Start(snapshot bool, discoverURL string, peers []string) error {
   269  	s.Lock()
   270  	defer s.Unlock()
   271  
   272  	// LoadSnapshot
   273  	if snapshot {
   274  		err := s.raftServer.LoadSnapshot()
   275  
   276  		if err == nil {
   277  			log.Debugf("%s finished load snapshot", s.Config.Name)
   278  		} else {
   279  			log.Debug(err)
   280  		}
   281  	}
   282  
   283  	s.raftServer.Init()
   284  
   285  	// Set NOCOW for data directory in btrfs
   286  	if btrfs.IsBtrfs(s.raftServer.LogPath()) {
   287  		if err := btrfs.SetNOCOWFile(s.raftServer.LogPath()); err != nil {
   288  			log.Warnf("Failed setting NOCOW: %v", err)
   289  		}
   290  	}
   291  
   292  	s.findCluster(discoverURL, peers)
   293  
   294  	s.closeChan = make(chan bool)
   295  
   296  	go s.monitorSync()
   297  	go s.monitorTimeoutThreshold(s.closeChan)
   298  	go s.monitorActiveSize(s.closeChan)
   299  	go s.monitorPeerActivity(s.closeChan)
   300  
   301  	// open the snapshot
   302  	if snapshot {
   303  		go s.monitorSnapshot()
   304  	}
   305  
   306  	return nil
   307  }
   308  
   309  func (s *PeerServer) Stop() {
   310  	s.Lock()
   311  	defer s.Unlock()
   312  
   313  	if s.closeChan != nil {
   314  		close(s.closeChan)
   315  		s.closeChan = nil
   316  	}
   317  	s.raftServer.Stop()
   318  }
   319  
   320  func (s *PeerServer) HTTPHandler() http.Handler {
   321  	router := mux.NewRouter()
   322  
   323  	// internal commands
   324  	router.HandleFunc("/name", s.NameHttpHandler)
   325  	router.HandleFunc("/version", s.VersionHttpHandler)
   326  	router.HandleFunc("/version/{version:[0-9]+}/check", s.VersionCheckHttpHandler)
   327  	router.HandleFunc("/upgrade", s.UpgradeHttpHandler)
   328  	router.HandleFunc("/join", s.JoinHttpHandler)
   329  	router.HandleFunc("/promote", s.PromoteHttpHandler).Methods("POST")
   330  	router.HandleFunc("/remove/{name:.+}", s.RemoveHttpHandler)
   331  	router.HandleFunc("/vote", s.VoteHttpHandler)
   332  	router.HandleFunc("/log", s.GetLogHttpHandler)
   333  	router.HandleFunc("/log/append", s.AppendEntriesHttpHandler)
   334  	router.HandleFunc("/snapshot", s.SnapshotHttpHandler)
   335  	router.HandleFunc("/snapshotRecovery", s.SnapshotRecoveryHttpHandler)
   336  	router.HandleFunc("/etcdURL", s.EtcdURLHttpHandler)
   337  
   338  	router.HandleFunc("/v2/admin/config", s.getClusterConfigHttpHandler).Methods("GET")
   339  	router.HandleFunc("/v2/admin/config", s.setClusterConfigHttpHandler).Methods("PUT")
   340  	router.HandleFunc("/v2/admin/machines", s.getMachinesHttpHandler).Methods("GET")
   341  	router.HandleFunc("/v2/admin/machines/{name}", s.getMachineHttpHandler).Methods("GET")
   342  	router.HandleFunc("/v2/admin/machines/{name}", s.addMachineHttpHandler).Methods("PUT")
   343  	router.HandleFunc("/v2/admin/machines/{name}", s.removeMachineHttpHandler).Methods("DELETE")
   344  
   345  	return router
   346  }
   347  
   348  // Retrieves the underlying Raft server.
   349  func (s *PeerServer) RaftServer() raft.Server {
   350  	return s.raftServer
   351  }
   352  
   353  // Associates the client server with the peer server.
   354  func (s *PeerServer) SetServer(server *Server) {
   355  	s.server = server
   356  }
   357  
   358  func (s *PeerServer) startAsLeader() {
   359  	s.raftServer.Start()
   360  	// leader need to join self as a peer
   361  	for {
   362  		c := &JoinCommandV1{
   363  			MinVersion: store.MinVersion(),
   364  			MaxVersion: store.MaxVersion(),
   365  			Name:       s.raftServer.Name(),
   366  			RaftURL:    s.Config.URL,
   367  			EtcdURL:    s.server.URL(),
   368  		}
   369  		_, err := s.raftServer.Do(c)
   370  		if err == nil {
   371  			break
   372  		}
   373  	}
   374  	log.Debugf("%s start as a leader", s.Config.Name)
   375  }
   376  
   377  func (s *PeerServer) startAsFollower(cluster []string, retryTimes int) error {
   378  	// start as a follower in a existing cluster
   379  	for i := 0; ; i++ {
   380  		ok := s.joinCluster(cluster)
   381  		if ok {
   382  			break
   383  		}
   384  		if i == retryTimes-1 {
   385  			return fmt.Errorf("Cannot join the cluster via given peers after %x retries", s.Config.RetryTimes)
   386  		}
   387  		log.Warnf("%v is unable to join the cluster using any of the peers %v at %dth time. Retrying in %.1f seconds", s.Config.Name, cluster, i, s.Config.RetryInterval)
   388  		time.Sleep(time.Second * time.Duration(s.Config.RetryInterval))
   389  	}
   390  
   391  	s.raftServer.Start()
   392  	return nil
   393  }
   394  
   395  // getVersion fetches the peer version of a cluster.
   396  func getVersion(t *transporter, versionURL url.URL) (int, error) {
   397  	resp, _, err := t.Get(versionURL.String())
   398  	if err != nil {
   399  		return 0, err
   400  	}
   401  	defer resp.Body.Close()
   402  
   403  	body, err := ioutil.ReadAll(resp.Body)
   404  	if err != nil {
   405  		return 0, err
   406  	}
   407  
   408  	// Parse version number.
   409  	version, _ := strconv.Atoi(string(body))
   410  	return version, nil
   411  }
   412  
   413  // Upgradable checks whether all peers in a cluster support an upgrade to the next store version.
   414  func (s *PeerServer) Upgradable() error {
   415  	nextVersion := s.store.Version() + 1
   416  	for _, peerURL := range s.registry.PeerURLs(s.raftServer.Leader(), s.Config.Name) {
   417  		u, err := url.Parse(peerURL)
   418  		if err != nil {
   419  			return fmt.Errorf("PeerServer: Cannot parse URL: '%s' (%s)", peerURL, err)
   420  		}
   421  
   422  		t, _ := s.raftServer.Transporter().(*transporter)
   423  		checkURL := (&url.URL{Host: u.Host, Scheme: s.Config.Scheme, Path: fmt.Sprintf("/version/%d/check", nextVersion)}).String()
   424  		resp, _, err := t.Get(checkURL)
   425  		if err != nil {
   426  			return fmt.Errorf("PeerServer: Cannot check version compatibility: %s", u.Host)
   427  		}
   428  		if resp.StatusCode != 200 {
   429  			return fmt.Errorf("PeerServer: Version %d is not compatible with peer: %s", nextVersion, u.Host)
   430  		}
   431  	}
   432  
   433  	return nil
   434  }
   435  
   436  // checkPeerAddressNonconflict checks whether the peer address has existed with different name.
   437  func (s *PeerServer) checkPeerAddressNonconflict() bool {
   438  	// there exists the (name, peer address) pair
   439  	if peerURL, ok := s.registry.PeerURL(s.Config.Name); ok {
   440  		if peerURL == s.Config.URL {
   441  			return true
   442  		}
   443  	}
   444  
   445  	// check all existing peer addresses
   446  	peerURLs := s.registry.PeerURLs(s.raftServer.Leader(), s.Config.Name)
   447  	for _, peerURL := range peerURLs {
   448  		if peerURL == s.Config.URL {
   449  			return false
   450  		}
   451  	}
   452  	return true
   453  }
   454  
   455  // Helper function to do discovery and return results in expected format
   456  func (s *PeerServer) handleDiscovery(discoverURL string) (peers []string, err error) {
   457  	peers, err = discovery.Do(discoverURL, s.Config.Name, s.Config.URL)
   458  
   459  	// Warn about errors coming from discovery, this isn't fatal
   460  	// since the user might have provided a peer list elsewhere,
   461  	// or there is some log in data dir.
   462  	if err != nil {
   463  		log.Warnf("Discovery encountered an error: %v", err)
   464  		return
   465  	}
   466  
   467  	for i := range peers {
   468  		// Strip the scheme off of the peer if it has one
   469  		// TODO(bp): clean this up!
   470  		purl, err := url.Parse(peers[i])
   471  		if err == nil {
   472  			peers[i] = purl.Host
   473  		}
   474  	}
   475  
   476  	log.Infof("Discovery fetched back peer list: %v", peers)
   477  
   478  	return
   479  }
   480  
   481  // getKnownPeers gets the previous peers from log
   482  func (s *PeerServer) getKnownPeers() []string {
   483  	peers := s.registry.PeerURLs(s.raftServer.Leader(), s.Config.Name)
   484  	log.Infof("Peer URLs in log: %s / %s (%s)", s.raftServer.Leader(), s.Config.Name, strings.Join(peers, ","))
   485  
   486  	for i := range peers {
   487  		u, err := url.Parse(peers[i])
   488  		if err != nil {
   489  			log.Debug("getPrevPeers cannot parse url %v", peers[i])
   490  		}
   491  		peers[i] = u.Host
   492  	}
   493  	return peers
   494  }
   495  
   496  // removeSelfFromList removes url of the peerServer from the peer list
   497  func (s *PeerServer) removeSelfFromList(peers []string) []string {
   498  	// Remove its own peer address from the peer list to join
   499  	u, err := url.Parse(s.Config.URL)
   500  	if err != nil {
   501  		log.Fatalf("removeSelfFromList cannot parse peer address %v", s.Config.URL)
   502  	}
   503  	newPeers := make([]string, 0)
   504  	for _, v := range peers {
   505  		if v != u.Host {
   506  			newPeers = append(newPeers, v)
   507  		}
   508  	}
   509  	return newPeers
   510  }
   511  
   512  func (s *PeerServer) joinCluster(cluster []string) bool {
   513  	for _, peer := range cluster {
   514  		if len(peer) == 0 {
   515  			continue
   516  		}
   517  
   518  		err := s.joinByPeer(s.raftServer, peer, s.Config.Scheme)
   519  		if err == nil {
   520  			log.Debugf("%s joined the cluster via peer %s", s.Config.Name, peer)
   521  			return true
   522  
   523  		}
   524  
   525  		if _, ok := err.(etcdErr.Error); ok {
   526  			log.Fatal(err)
   527  		}
   528  
   529  		log.Warnf("Attempt to join via %s failed: %s", peer, err)
   530  	}
   531  
   532  	return false
   533  }
   534  
   535  // Send join requests to peer.
   536  func (s *PeerServer) joinByPeer(server raft.Server, peer string, scheme string) error {
   537  	// t must be ok
   538  	t, _ := server.Transporter().(*transporter)
   539  
   540  	// Our version must match the leaders version
   541  	versionURL := url.URL{Host: peer, Scheme: scheme, Path: "/version"}
   542  	version, err := getVersion(t, versionURL)
   543  	if err != nil {
   544  		return fmt.Errorf("Error during join version check: %v", err)
   545  	}
   546  	if version < store.MinVersion() || version > store.MaxVersion() {
   547  		return fmt.Errorf("Unable to join: cluster version is %d; version compatibility is %d - %d", version, store.MinVersion(), store.MaxVersion())
   548  	}
   549  
   550  	var b bytes.Buffer
   551  	c := &JoinCommandV2{
   552  		MinVersion: store.MinVersion(),
   553  		MaxVersion: store.MaxVersion(),
   554  		Name:       server.Name(),
   555  		PeerURL:    s.Config.URL,
   556  		ClientURL:  s.server.URL(),
   557  	}
   558  	json.NewEncoder(&b).Encode(c)
   559  
   560  	joinURL := url.URL{Host: peer, Scheme: scheme, Path: "/v2/admin/machines/" + server.Name()}
   561  	log.Infof("Send Join Request to %s", joinURL.String())
   562  
   563  	req, _ := http.NewRequest("PUT", joinURL.String(), &b)
   564  	resp, err := t.client.Do(req)
   565  
   566  	for {
   567  		if err != nil {
   568  			return fmt.Errorf("Unable to join: %v", err)
   569  		}
   570  		if resp != nil {
   571  			defer resp.Body.Close()
   572  
   573  			log.Infof("»»»» %d", resp.StatusCode)
   574  			if resp.StatusCode == http.StatusOK {
   575  				var msg joinMessageV2
   576  				if err := json.NewDecoder(resp.Body).Decode(&msg); err != nil {
   577  					log.Debugf("Error reading join response: %v", err)
   578  					return err
   579  				}
   580  				s.joinIndex = msg.CommitIndex
   581  				s.setMode(msg.Mode)
   582  
   583  				if msg.Mode == StandbyMode {
   584  					s.standbyClientURL = resp.Header.Get("X-Leader-Client-URL")
   585  					s.standbyPeerURL = resp.Header.Get("X-Leader-Peer-URL")
   586  				}
   587  
   588  				return nil
   589  			}
   590  			if resp.StatusCode == http.StatusTemporaryRedirect {
   591  				address := resp.Header.Get("Location")
   592  				log.Debugf("Send Join Request to %s", address)
   593  				c := &JoinCommandV2{
   594  					MinVersion: store.MinVersion(),
   595  					MaxVersion: store.MaxVersion(),
   596  					Name:       server.Name(),
   597  					PeerURL:    s.Config.URL,
   598  					ClientURL:  s.server.URL(),
   599  				}
   600  				json.NewEncoder(&b).Encode(c)
   601  				resp, _, err = t.Put(address, &b)
   602  
   603  			} else if resp.StatusCode == http.StatusBadRequest {
   604  				log.Debug("Reach max number peers in the cluster")
   605  				decoder := json.NewDecoder(resp.Body)
   606  				err := &etcdErr.Error{}
   607  				decoder.Decode(err)
   608  				return *err
   609  			} else {
   610  				return fmt.Errorf("Unable to join")
   611  			}
   612  		}
   613  
   614  	}
   615  }
   616  
   617  func (s *PeerServer) Stats() []byte {
   618  	s.serverStats.LeaderInfo.Uptime = time.Now().Sub(s.serverStats.LeaderInfo.startTime).String()
   619  
   620  	// TODO: register state listener to raft to change this field
   621  	// rather than compare the state each time Stats() is called.
   622  	if s.RaftServer().State() == raft.Leader {
   623  		s.serverStats.LeaderInfo.Name = s.RaftServer().Name()
   624  	}
   625  
   626  	queue := s.serverStats.sendRateQueue
   627  
   628  	s.serverStats.SendingPkgRate, s.serverStats.SendingBandwidthRate = queue.Rate()
   629  
   630  	queue = s.serverStats.recvRateQueue
   631  
   632  	s.serverStats.RecvingPkgRate, s.serverStats.RecvingBandwidthRate = queue.Rate()
   633  
   634  	b, _ := json.Marshal(s.serverStats)
   635  
   636  	return b
   637  }
   638  
   639  func (s *PeerServer) PeerStats() []byte {
   640  	if s.raftServer.State() == raft.Leader {
   641  		b, _ := json.Marshal(s.followersStats)
   642  		return b
   643  	}
   644  	return nil
   645  }
   646  
   647  // raftEventLogger converts events from the Raft server into log messages.
   648  func (s *PeerServer) raftEventLogger(event raft.Event) {
   649  	value := event.Value()
   650  	prevValue := event.PrevValue()
   651  	if value == nil {
   652  		value = "<nil>"
   653  	}
   654  	if prevValue == nil {
   655  		prevValue = "<nil>"
   656  	}
   657  
   658  	switch event.Type() {
   659  	case raft.StateChangeEventType:
   660  		log.Infof("%s: state changed from '%v' to '%v'.", s.Config.Name, prevValue, value)
   661  	case raft.TermChangeEventType:
   662  		log.Infof("%s: term #%v started.", s.Config.Name, value)
   663  	case raft.LeaderChangeEventType:
   664  		log.Infof("%s: leader changed from '%v' to '%v'.", s.Config.Name, prevValue, value)
   665  	case raft.AddPeerEventType:
   666  		log.Infof("%s: peer added: '%v'", s.Config.Name, value)
   667  	case raft.RemovePeerEventType:
   668  		log.Infof("%s: peer removed: '%v'", s.Config.Name, value)
   669  	case raft.HeartbeatIntervalEventType:
   670  		var name = "<unknown>"
   671  		if peer, ok := value.(*raft.Peer); ok {
   672  			name = peer.Name
   673  		}
   674  		log.Infof("%s: warning: heartbeat timed out: '%v'", s.Config.Name, name)
   675  	case raft.ElectionTimeoutThresholdEventType:
   676  		select {
   677  		case s.timeoutThresholdChan <- value:
   678  		default:
   679  		}
   680  
   681  	}
   682  }
   683  
   684  func (s *PeerServer) recordMetricEvent(event raft.Event) {
   685  	name := fmt.Sprintf("raft.event.%s", event.Type())
   686  	value := event.Value().(time.Duration)
   687  	(*s.metrics).Timer(name).Update(value)
   688  }
   689  
   690  // logSnapshot logs about the snapshot that was taken.
   691  func (s *PeerServer) logSnapshot(err error, currentIndex, count uint64) {
   692  	info := fmt.Sprintf("%s: snapshot of %d events at index %d", s.Config.Name, count, currentIndex)
   693  
   694  	if err != nil {
   695  		log.Infof("%s attempted and failed: %v", info, err)
   696  	} else {
   697  		log.Infof("%s completed", info)
   698  	}
   699  }
   700  
   701  func (s *PeerServer) monitorSnapshot() {
   702  	for {
   703  		time.Sleep(s.snapConf.checkingInterval)
   704  		currentIndex := s.RaftServer().CommitIndex()
   705  		count := currentIndex - s.snapConf.lastIndex
   706  		if uint64(count) > s.snapConf.snapshotThr {
   707  			err := s.raftServer.TakeSnapshot()
   708  			s.logSnapshot(err, currentIndex, count)
   709  			s.snapConf.lastIndex = currentIndex
   710  		}
   711  	}
   712  }
   713  
   714  func (s *PeerServer) monitorSync() {
   715  	ticker := time.Tick(time.Millisecond * 500)
   716  	for {
   717  		select {
   718  		case now := <-ticker:
   719  			if s.raftServer.State() == raft.Leader {
   720  				s.raftServer.Do(s.store.CommandFactory().CreateSyncCommand(now))
   721  			}
   722  		}
   723  	}
   724  }
   725  
   726  // monitorTimeoutThreshold groups timeout threshold events together and prints
   727  // them as a single log line.
   728  func (s *PeerServer) monitorTimeoutThreshold(closeChan chan bool) {
   729  	for {
   730  		select {
   731  		case value := <-s.timeoutThresholdChan:
   732  			log.Infof("%s: warning: heartbeat near election timeout: %v", s.Config.Name, value)
   733  		case <-closeChan:
   734  			return
   735  		}
   736  
   737  		time.Sleep(ThresholdMonitorTimeout)
   738  	}
   739  }
   740  
   741  // monitorActiveSize has the leader periodically check the status of cluster
   742  // nodes and swaps them out for standbys as needed.
   743  func (s *PeerServer) monitorActiveSize(closeChan chan bool) {
   744  	for {
   745  		select {
   746  		case <-time.After(ActiveMonitorTimeout):
   747  		case <-closeChan:
   748  			return
   749  		}
   750  
   751  		// Ignore while this peer is not a leader.
   752  		if s.raftServer.State() != raft.Leader {
   753  			continue
   754  		}
   755  
   756  		// Retrieve target active size and actual active size.
   757  		activeSize := s.ClusterConfig().ActiveSize
   758  		peerCount := s.registry.PeerCount()
   759  		standbys := s.registry.Standbys()
   760  		peers := s.registry.Peers()
   761  		if index := sort.SearchStrings(peers, s.Config.Name); index < len(peers) && peers[index] == s.Config.Name {
   762  			peers = append(peers[:index], peers[index+1:]...)
   763  		}
   764  
   765  		// If we have more active nodes than we should then demote.
   766  		if peerCount > activeSize {
   767  			peer := peers[rand.Intn(len(peers))]
   768  			log.Infof("%s: demoting: %v", s.Config.Name, peer)
   769  			if _, err := s.raftServer.Do(&DemoteCommand{Name: peer}); err != nil {
   770  				log.Infof("%s: warning: demotion error: %v", s.Config.Name, err)
   771  			}
   772  			continue
   773  		}
   774  
   775  		// If we don't have enough active nodes then try to promote a standby.
   776  		if peerCount < activeSize && len(standbys) > 0 {
   777  		loop:
   778  			for _, i := range rand.Perm(len(standbys)) {
   779  				standby := standbys[i]
   780  				standbyPeerURL, _ := s.registry.StandbyPeerURL(standby)
   781  				log.Infof("%s: attempting to promote: %v (%s)", s.Config.Name, standby, standbyPeerURL)
   782  
   783  				// Notify standby to promote itself.
   784  				client := &http.Client{
   785  					Transport: &http.Transport{
   786  						DisableKeepAlives:     false,
   787  						ResponseHeaderTimeout: ActiveMonitorTimeout,
   788  					},
   789  				}
   790  				resp, err := client.Post(fmt.Sprintf("%s/promote", standbyPeerURL), "application/json", nil)
   791  				if err != nil {
   792  					log.Infof("%s: warning: promotion error: %v", s.Config.Name, err)
   793  					continue
   794  				} else if resp.StatusCode != http.StatusOK {
   795  					log.Infof("%s: warning: promotion failure: %v", s.Config.Name, resp.StatusCode)
   796  					continue
   797  				}
   798  				break loop
   799  			}
   800  		}
   801  	}
   802  }
   803  
   804  // monitorPeerActivity has the leader periodically for dead nodes and demotes them.
   805  func (s *PeerServer) monitorPeerActivity(closeChan chan bool) {
   806  	for {
   807  		select {
   808  		case <-time.After(PeerActivityMonitorTimeout):
   809  		case <-closeChan:
   810  			return
   811  		}
   812  
   813  		// Ignore while this peer is not a leader.
   814  		if s.raftServer.State() != raft.Leader {
   815  			continue
   816  		}
   817  
   818  		// Check last activity for all peers.
   819  		now := time.Now()
   820  		promoteDelay := time.Duration(s.ClusterConfig().PromoteDelay) * time.Second
   821  		peers := s.raftServer.Peers()
   822  		for _, peer := range peers {
   823  			// If the last response from the peer is longer than the promote delay
   824  			// then automatically demote the peer.
   825  			if !peer.LastActivity().IsZero() && now.Sub(peer.LastActivity()) > promoteDelay {
   826  				log.Infof("%s: demoting node: %v; last activity %v ago", s.Config.Name, peer.Name, now.Sub(peer.LastActivity()))
   827  				if _, err := s.raftServer.Do(&DemoteCommand{Name: peer.Name}); err != nil {
   828  					log.Infof("%s: warning: autodemotion error: %v", s.Config.Name, err)
   829  				}
   830  				continue
   831  			}
   832  		}
   833  	}
   834  }
   835  
   836  // Mode represents whether the server is an active peer or if the server is
   837  // simply acting as a standby.
   838  type Mode string
   839  
   840  const (
   841  	// PeerMode is when the server is an active node in Raft.
   842  	PeerMode = Mode("peer")
   843  
   844  	// StandbyMode is when the server is an inactive, request-forwarding node.
   845  	StandbyMode = Mode("standby")
   846  )