ETCD核心数据结构&包&关系

ETCD核心数据结构

本文分析了从main包到etcdmain包到embed包到etcdserver包, 完整跟踪了etcd启动,包括rpc, http端口监听, rpc接口服务注册(也就是客户端调用的put, range, 等功能)

main包

main函数-->embed.Main() embed包

package main

import "go.etcd.io/etcd/etcdmain" //导入etcdmain包

func main() {
	etcdmain.Main()               //就一行代码,启动server
}

etcdmain 包

如果是启动etcd,实际上启动的embed.StartEtcd

思考:

ETCD PROXY是怎么实现的?看懂etcdmain/etcd.go rpc_proxy, http_proxy. gateway都是什么原理 
util.go:discoverEndpoints发现端点是干什么的

//这个包是etcd的main函数入口,这个包只被main包使用过
main.go:Main()方法,是大写Main,根据配置启动proxy或者etcd实例
main.go:Main()->etcd.go:startEtcdOrProxyV2()->etcd.go:startEtcd 或者etcd.go:startProxy -->embed.StartEtcd到了embed包

//这个包是etcd的main函数入口,这个包只被main包使用过
main.go:Main()方法,是大写Main,根据配置启动proxy或者etcd实例
main.go:Main()->etcd.go:startEtcdOrProxyV2()->etcd.go:startEtcd 或者etcd.go:startProxy
// startEtcd runs StartEtcd in addition to hooks needed for standalone etcd.
//启用的是embed.StartEtcd. embed就说导入这个包,在任何你的代码里都能嵌入一个etcd服务。
func startEtcd(cfg *embed.Config) (<-chan struct{}, <-chan error, error) {
	e, err := embed.StartEtcd(cfg)
	if err != nil {
		return nil, nil, err
	}
	osutil.RegisterInterruptHandler(e.Close)
	select {
	case <-e.Server.ReadyNotify(): // wait for e.Server to join the cluster 等待加入集群
	case <-e.Server.StopNotify(): // publish aborted from 'ErrStopped'
	}
	return e.Server.StopNotify(), e.Err(), nil
}


//配置管理config.go,配置的加载解析,命令行参数解析
type config struct {
	ec           embed.Config
	cp           configProxy
	cf           configFlags
	configFile   string
	printVersion bool
	ignored      []string
}

type configFlags struct {
	flagSet      *flag.FlagSet
	clusterState *flags.SelectiveStringValue
	fallback     *flags.SelectiveStringValue
	proxy        *flags.SelectiveStringValue
}
//所有方法
func newConfig() *config {
func (cfg *config) parse(arguments []string) error {
func (cfg *config) configFromCmdLine() error {
func (cfg *config) configFromFile(path string) error {
func (cfg *config) mayBeProxy() bool {
func (cfg *config) validate() error {
func (cfg config) isProxy() bool               { return cfg.cf.proxy.String() != proxyFlagOff }
func (cfg config) isReadonlyProxy() bool       { return cfg.cf.proxy.String() == proxyFlagReadonly }
func (cfg config) shouldFallbackToProxy() bool { return cfg.cf.fallback.String() == fallbackFlagProxy }


//etcd.go ETCD有两各启动方式:Proxy方式,和直接启用
func startEtcdOrProxyV2() {   //启动etcd还是etcdproxy,根据配置文件决定
func startEtcd(cfg *embed.Config) (<-chan struct{}, <-chan error, error) {  //这才是真正启动ETCD
func startProxy(cfg *config) error {  //config是用来启动proxy的。
func identifyDataDirOrDie(lg *zap.Logger, dir string) dirType {
func checkSupportArch() {

//gateway.go 网关
func init() {
func newGatewayCommand() *cobra.Command {
func newGatewayStartCommand() *cobra.Command {
func stripSchema(eps []string) []string {
func startGateway(cmd *cobra.Command, args []string) {

//grpc_proxy.go grpc代理
func init() {
func newGRPCProxyCommand() *cobra.Command {
func newGRPCProxyStartCommand() *cobra.Command {
func startGRPCProxy(cmd *cobra.Command, args []string) {
func checkArgs() {
func mustNewClient(lg *zap.Logger) *clientv3.Client {
func newClientCfg(lg *zap.Logger, eps []string) (*clientv3.Config, error) {
func newTLS(ca, cert, key string) *transport.TLSInfo {
func mustListenCMux(lg *zap.Logger, tlsinfo *transport.TLSInfo) cmux.CMux {
func newGRPCProxyServer(lg *zap.Logger, client *clientv3.Client) *grpc.Server {
func mustHTTPListener(lg *zap.Logger, m cmux.CMux, tlsinfo *transport.TLSInfo, c *clientv3.Client) (*http.Server, net.Listener) {
func mustNewHTTPClient(lg *zap.Logger) *http.Client {
func newHTTPTransport(ca, cert, key string) (*http.Transport, error) {
func mustMetricsListener(lg *zap.Logger, tlsinfo *transport.TLSInfo) net.Listener {

help.go:帮助,打印帮助信息

util.go:只有个发现端点的函数
func discoverEndpoints(lg *zap.Logger, dns string, ca string, insecure bool, serviceName string) (s srv.SRVClients) {

embed包

真正启动etcd服务

embed/etcd.go: embed.StartEtcd->

     创建了embed/etcd.go: embed.Etcd对象

    创建了etcdserver/config.go: etcdserver.ServerConfig对象

    创建了etcdserver/server.go: etcdserver.EtcdServer对象,此对象实现了对外的接口,如put, range

    调用了 func (s *EtcdServer) Start()

注册RPC接口:func (e *Etcd) servePeers(), func (e *Etcd) serveClients() (err error)

注册所有RPC接口:embed/serve.go: func (sctx *serveCtx) serve  -->  etcdserver/api/v3rpc/grpc.go: gs = v3rpc.Server(s, nil, gopts...)

接着启动RPC,和HTTP服务

//embed/config.go:
//etcd的核心配置,可以看到集群,选举的配置
// Config holds the arguments for configuring an etcd server.
type Config struct {
	Name   string `json:"name"`
	Dir    string `json:"data-dir"`
	WalDir string `json:"wal-dir"`

	SnapshotCount uint64 `json:"snapshot-count"`

	SnapshotCatchUpEntries uint64

	MaxSnapFiles uint `json:"max-snapshots"`
	MaxWalFiles  uint `json:"max-wals"`

	TickMs     uint `json:"heartbeat-interval"`
	ElectionMs uint `json:"election-timeout"`

	InitialElectionTickAdvance bool `json:"initial-election-tick-advance"`

	// BackendBatchInterval is the maximum time before commit the backend transaction.
	BackendBatchInterval time.Duration `json:"backend-batch-interval"`
	// BackendBatchLimit is the maximum operations before commit the backend transaction.
	BackendBatchLimit int   `json:"backend-batch-limit"`
	QuotaBackendBytes int64 `json:"quota-backend-bytes"`
	MaxTxnOps         uint  `json:"max-txn-ops"`
	MaxRequestBytes   uint  `json:"max-request-bytes"`

	LPUrls, LCUrls []url.URL
	APUrls, ACUrls []url.URL
	ClientTLSInfo  transport.TLSInfo
	ClientAutoTLS  bool
	PeerTLSInfo    transport.TLSInfo
	PeerAutoTLS    bool

	// CipherSuites is a list of supported TLS cipher suites between
	// client/server and peers. If empty, Go auto-populates the list.
	// Note that cipher suites are prioritized in the given order.
	CipherSuites []string `json:"cipher-suites"`

	ClusterState          string `json:"initial-cluster-state"`
	DNSCluster            string `json:"discovery-srv"`
	DNSClusterServiceName string `json:"discovery-srv-name"`
	Dproxy                string `json:"discovery-proxy"`
	Durl                  string `json:"discovery"`
	InitialCluster        string `json:"initial-cluster"`
	InitialClusterToken   string `json:"initial-cluster-token"`
	StrictReconfigCheck   bool   `json:"strict-reconfig-check"`
	EnableV2              bool   `json:"enable-v2"`

	// AutoCompactionMode is either 'periodic' or 'revision'.
	AutoCompactionMode string `json:"auto-compaction-mode"`
	// AutoCompactionRetention is either duration string with time unit
	// (e.g. '5m' for 5-minute), or revision unit (e.g. '5000').
	// If no time unit is provided and compaction mode is 'periodic',
	// the unit defaults to hour. For example, '5' translates into 5-hour.
	AutoCompactionRetention string `json:"auto-compaction-retention"`

	GRPCKeepAliveMinTime time.Duration `json:"grpc-keepalive-min-time"`
	GRPCKeepAliveInterval time.Duration `json:"grpc-keepalive-interval"`
	GRPCKeepAliveTimeout time.Duration `json:"grpc-keepalive-timeout"`

	PreVote bool `json:"pre-vote"`

	CORS map[string]struct{}

	
	HostWhitelist map[string]struct{}

	UserHandlers map[string]http.Handler `json:"-"`
	// ServiceRegister is for registering users' gRPC services. A simple usage example:
	//	cfg := embed.NewConfig()
	//	cfg.ServerRegister = func(s *grpc.Server) {
	//		pb.RegisterFooServer(s, &fooServer{})
	//		pb.RegisterBarServer(s, &barServer{})
	//	}
	//	embed.StartEtcd(cfg)
	ServiceRegister func(*grpc.Server) `json:"-"`

	AuthToken  string `json:"auth-token"`
	BcryptCost uint   `json:"bcrypt-cost"`

	//The AuthTokenTTL in seconds of the simple token
	AuthTokenTTL uint `json:"auth-token-ttl"`

	ExperimentalInitialCorruptCheck bool          `json:"experimental-initial-corrupt-check"`
	ExperimentalCorruptCheckTime    time.Duration `json:"experimental-corrupt-check-time"`
	ExperimentalEnableV2V3          string        `json:"experimental-enable-v2v3"`
	// ExperimentalBackendFreelistType specifies the type of freelist that boltdb backend uses (array and map are supported types).
	ExperimentalBackendFreelistType string `json:"experimental-backend-bbolt-freelist-type"`
	// ExperimentalEnableLeaseCheckpoint enables primary lessor to persist lease remainingTTL to prevent indefinite auto-renewal of long lived leases.
	ExperimentalEnableLeaseCheckpoint       bool          `json:"experimental-enable-lease-checkpoint"`
	ExperimentalCompactionBatchLimit        int           `json:"experimental-compaction-batch-limit"`
	ExperimentalWatchProgressNotifyInterval time.Duration `json:"experimental-watch-progress-notify-interval"`
	// ExperimentalWarningApplyDuration is the time duration after which a warning is generated if applying request
	// takes more time than this value.
	ExperimentalWarningApplyDuration time.Duration `json:"experimental-warning-apply-duration"`

	// ForceNewCluster starts a new cluster even if previously started; unsafe.
	ForceNewCluster bool `json:"force-new-cluster"`

	EnablePprof           bool   `json:"enable-pprof"`
	Metrics               string `json:"metrics"`
	ListenMetricsUrls     []url.URL
	ListenMetricsUrlsJSON string `json:"listen-metrics-urls"`

	// Logger is logger options: "zap", "capnslog".
	// WARN: "capnslog" is being deprecated in v3.5.
	Logger string `json:"logger"`
	// LogLevel configures log level. Only supports debug, info, warn, error, panic, or fatal. Default 'info'.
	LogLevel string `json:"log-level"`
	// LogOutputs is either:
	//  - "default" as os.Stderr,
	//  - "stderr" as os.Stderr,
	//  - "stdout" as os.Stdout,
	//  - file path to append server logs to.
	// It can be multiple when "Logger" is zap.
	LogOutputs []string `json:"log-outputs"`

	// ZapLoggerBuilder is used to build the zap logger.
	ZapLoggerBuilder func(*Config) error

	// logger logs server-side operations. The default is nil,
	// and "setupLogging" must be called before starting server.
	// Do not set logger directly.
	loggerMu *sync.RWMutex
	logger   *zap.Logger

	// loggerConfig is server logger configuration for Raft logger.
	// Must be either: "loggerConfig != nil" or "loggerCore != nil && loggerWriteSyncer != nil".
	loggerConfig *zap.Config
	// loggerCore is "zapcore.Core" for raft logger.
	// Must be either: "loggerConfig != nil" or "loggerCore != nil && loggerWriteSyncer != nil".
	loggerCore        zapcore.Core
	loggerWriteSyncer zapcore.WriteSyncer

	// EnableGRPCGateway is false to disable grpc gateway.
	EnableGRPCGateway bool `json:"enable-grpc-gateway"`

	// TO BE DEPRECATED

	// DeprecatedLogOutput is to be deprecated in v3.5.
	// Just here for safe migration in v3.4.
	DeprecatedLogOutput []string `json:"log-output"`
	// Debug is true, to enable debug level logging.
	// WARNING: to be deprecated in 3.5. Use "--log-level=debug" instead.
	Debug bool `json:"debug"`
	// LogPkgLevels is being deprecated in v3.5.
	// Only valid if "logger" option is "capnslog".
	// WARN: DO NOT USE THIS!
	LogPkgLevels string `json:"log-package-levels"`

	// UnsafeNoFsync disables all uses of fsync.
	// Setting this is unsafe and will cause data loss.
	UnsafeNoFsync bool `json:"unsafe-no-fsync"`
}

func init() {
func NewConfig() *Config {
func logTLSHandshakeFailure(conn *tls.Conn, err error) {
func ConfigFromFile(path string) (*Config, error) {
func (cfg *configYAML) configFromFile(path string) error {
func updateCipherSuites(tls *transport.TLSInfo, ss []string) error {
func (cfg *Config) Validate() error {
func (cfg *Config) PeerURLsMapAndToken(which string) (urlsmap types.URLsMap, token string, err error) {
func (cfg *Config) GetDNSClusterNames() ([]string, error) {
func (cfg Config) InitialClusterFromName(name string) (ret string) {
func (cfg Config) IsNewCluster() bool { return cfg.ClusterState == ClusterStateFlagNew }
func (cfg Config) ElectionTicks() int { return int(cfg.ElectionMs / cfg.TickMs) }
func (cfg Config) defaultPeerHost() bool {
func (cfg Config) defaultClientHost() bool {
func (cfg *Config) ClientSelfCert() (err error) {
func (cfg *Config) PeerSelfCert() (err error) {
func (cfg *Config) UpdateDefaultClusterFromName(defaultInitialCluster string) (string, error) {
func checkBindURLs(urls []url.URL) error {
func checkHostURLs(urls []url.URL) error {
func (cfg *Config) getAPURLs() (ss []string) {
func (cfg *Config) getLPURLs() (ss []string) {
func (cfg *Config) getACURLs() (ss []string) {
func (cfg *Config) getLCURLs() (ss []string) {
func (cfg *Config) getMetricsURLs() (ss []string) {
func parseBackendFreelistType(freelistType string) bolt.FreelistType {



embed/config_logging.go: 日志
func (cfg Config) GetLogger() *zap.Logger {
func (cfg *Config) setupLogging() error {
func NewZapCoreLoggerBuilder(lg *zap.Logger, cr zapcore.Core, syncer zapcore.WriteSyncer) func(*Config) error {


embed/etcd.go:
// Etcd contains a running etcd server and its listeners.
type Etcd struct {
	Peers   []*peerListener
	Clients []net.Listener
	// a map of contexts for the servers that serves client requests.
	sctxs            map[string]*serveCtx
	metricsListeners []net.Listener

	Server *etcdserver.EtcdServer  //ETCD服务器,真正实现各种服务接口功能的对象

	cfg   Config
	stopc chan struct{}
	errc  chan error

	closeOnce sync.Once
}

type peerListener struct {
	net.Listener
	serve func() error
	close func(context.Context) error
}


func StartEtcd(inCfg *Config) (e *Etcd, err error) {  //没错,这就是核心,启动类
func print(lg *zap.Logger, ec Config, sc etcdserver.ServerConfig, memberInitialized bool) {
func (e *Etcd) Config() Config {
func (e *Etcd) Close() {
func stopServers(ctx context.Context, ss *servers) {
func (e *Etcd) Err() <-chan error { return e.errc }
func configurePeerListeners(cfg *Config) (peers []*peerListener, err error) {
func (e *Etcd) servePeers() (err error) {  //cluster用的吧
func configureClientListeners(cfg *Config) (sctxs map[string]*serveCtx, err error) {
func (e *Etcd) serveClients() (err error) { //对外提供的服务,像put
func (e *Etcd) serveMetrics() (err error) { //监控吧
func (e *Etcd) errHandler(err error) {
func (e *Etcd) GetLogger() *zap.Logger {
func parseCompactionRetention(mode, retention string) (ret time.Duration, err error) {

StartEtcd方法创建了Etcd对象,并创建etcdserver.ServerConfig,监听端口
调用etcdserver.NewServer,创建etcd服务对象,
StartEtcd中这几步非常重要:
	e.Server.Start()

	if err = e.servePeers(); err != nil {   //注册服务,给其他etcdServer用
		return e, err
	}
	if err = e.serveClients(); err != nil {  //注册服务给客户端用
		return e, err
	}
	if err = e.serveMetrics(); err != nil {  //注册服务给监控用
		return e, err
	}

//关键函数,注册提供给客户端的RPC服务
func (e *Etcd) serveClients() (err error) {

    // Start a client server goroutine for each listen address
    //http服务
	var h http.Handler
	if e.Config().EnableV2 {
		if len(e.Config().ExperimentalEnableV2V3) > 0 {
			srv := v2v3.NewServer(e.cfg.logger, v3client.New(e.Server), e.cfg.ExperimentalEnableV2V3)
			h = v2http.NewClientHandler(e.GetLogger(), srv, e.Server.Cfg.ReqTimeout())
		} else {
			h = v2http.NewClientHandler(e.GetLogger(), e.Server, e.Server.Cfg.ReqTimeout())
		}
	} else {
		mux := http.NewServeMux()
		etcdhttp.HandleBasic(mux, e.Server)
		h = mux
	}
	for _, sctx := range e.sctxs {
		go func(s *serveCtx) {
           //这里真正注册了RPC接口
			e.errHandler(s.serve(e.Server, &e.cfg.ClientTLSInfo, h, e.errHandler, gopts...))
		}(sctx)
	}


//embed/serve.go:监听一个端口,提供服务, http, rpc
type serveCtx struct {
	lg       *zap.Logger
	l        net.Listener
	addr     string
	network  string
	secure   bool
	insecure bool

	ctx    context.Context
	cancel context.CancelFunc

	userHandlers    map[string]http.Handler
	serviceRegister func(*grpc.Server)
	serversC        chan *servers
}

type servers struct {
	secure bool
	grpc   *grpc.Server
	http   *http.Server
}

func newServeCtx(lg *zap.Logger) *serveCtx {
func (sctx *serveCtx) serve( //注册rpc服务
func grpcHandlerFunc(grpcServer *grpc.Server, otherHandler http.Handler) http.Handler {
func (sctx *serveCtx) registerGateway(opts []grpc.DialOption) (*gw.ServeMux, error) {
func (sctx *serveCtx) createMux(gwmux *gw.ServeMux, handler http.Handler) *http.ServeMux {
func createAccessController(lg *zap.Logger, s *etcdserver.EtcdServer, mux *http.ServeMux) http.Handler {
func (ac *accessController) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
func addCORSHeader(w http.ResponseWriter, origin string) {
func errCVE20185702(host string) string {
func WrapCORS(cors map[string]struct{}, h http.Handler) http.Handler {
func (ch *corsHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
func (sctx *serveCtx) registerUserHandler(s string, h http.Handler) {
func (sctx *serveCtx) registerPprof() {
func (sctx *serveCtx) registerTrace() {


// serve accepts incoming connections on the listener l,
// creating a new service goroutine for each. The service goroutines
// read requests and then call handler to reply to them.
func (sctx *serveCtx) serve(
	s *etcdserver.EtcdServer,
	tlsinfo *transport.TLSInfo,
	handler http.Handler,
	errHandler func(error),
	gopts ...grpc.ServerOption) (err error) {
	logger := defaultLog.New(ioutil.Discard, "etcdhttp", 0)
	<-s.ReadyNotify()

	if sctx.lg == nil {
		plog.Info("ready to serve client requests")
	}

	m := cmux.New(sctx.l)
	v3c := v3client.New(s)
	servElection := v3election.NewElectionServer(v3c)
	servLock := v3lock.NewLockServer(v3c)

	var gs *grpc.Server  //grpc服务
	defer func() {
		if err != nil && gs != nil {
			gs.Stop()
		}
	}()

	if sctx.insecure {
        //这里到etcdserver/api/v3rpc/grpc.go
		gs = v3rpc.Server(s, nil, gopts...)  //grpc服务,所有接口在这里注册,这里传入了etcd_sverver
		v3electionpb.RegisterElectionServer(gs, servElection)
		v3lockpb.RegisterLockServer(gs, servLock)
		if sctx.serviceRegister != nil {
			sctx.serviceRegister(gs)
		}
		grpcl := m.Match(cmux.HTTP2())
		go func() { errHandler(gs.Serve(grpcl)) }()

		var gwmux *gw.ServeMux
		if s.Cfg.EnableGRPCGateway {
			gwmux, err = sctx.registerGateway([]grpc.DialOption{grpc.WithInsecure()})
			if err != nil {
				return err
			}
		}

		httpmux := sctx.createMux(gwmux, handler)

		srvhttp := &http.Server{
			Handler:  createAccessController(sctx.lg, s, httpmux),
			ErrorLog: logger, // do not log user error
		}
		httpl := m.Match(cmux.HTTP1())
		go func() { errHandler(srvhttp.Serve(httpl)) }()

		sctx.serversC <- &servers{grpc: gs, http: srvhttp}
		if sctx.lg != nil {
			sctx.lg.Info(
				"serving client traffic insecurely; this is strongly discouraged!",
				zap.String("address", sctx.l.Addr().String()),
			)
		} else {
			plog.Noticef("serving insecure client requests on %s, this is strongly discouraged!", sctx.l.Addr().String())
		}
	}

	if sctx.secure {
		tlscfg, tlsErr := tlsinfo.ServerConfig()
		if tlsErr != nil {
			return tlsErr
		}
		gs = v3rpc.Server(s, tlscfg, gopts...)
		v3electionpb.RegisterElectionServer(gs, servElection)
		v3lockpb.RegisterLockServer(gs, servLock)
		if sctx.serviceRegister != nil {
			sctx.serviceRegister(gs)
		}
		handler = grpcHandlerFunc(gs, handler)

		var gwmux *gw.ServeMux
		if s.Cfg.EnableGRPCGateway {
			dtls := tlscfg.Clone()
			// trust local server
			dtls.InsecureSkipVerify = true
			bundle := credentials.NewBundle(credentials.Config{TLSConfig: dtls})
			opts := []grpc.DialOption{grpc.WithTransportCredentials(bundle.TransportCredentials())}
			gwmux, err = sctx.registerGateway(opts)
			if err != nil {
				return err
			}
		}

		var tlsl net.Listener
		tlsl, err = transport.NewTLSListener(m.Match(cmux.Any()), tlsinfo)
		if err != nil {
			return err
		}
		// TODO: add debug flag; enable logging when debug flag is set
		httpmux := sctx.createMux(gwmux, handler)

		srv := &http.Server{
			Handler:   createAccessController(sctx.lg, s, httpmux),
			TLSConfig: tlscfg,
			ErrorLog:  logger, // do not log user error
		}
		go func() { errHandler(srv.Serve(tlsl)) }()

		sctx.serversC <- &servers{secure: true, grpc: gs, http: srv}
		if sctx.lg != nil {
			sctx.lg.Info(
				"serving client traffic securely",
				zap.String("address", sctx.l.Addr().String()),
			)
		} else {
			plog.Infof("serving client requests on %s", sctx.l.Addr().String())
		}
	}

	close(sctx.serversC)
	return m.Serve()  //开始进入循环
}

 

核心接口

type RaftKV interface {
	Range(ctx context.Context, r *pb.RangeRequest) (*pb.RangeResponse, error)
	Put(ctx context.Context, r *pb.PutRequest) (*pb.PutResponse, error)
	DeleteRange(ctx context.Context, r *pb.DeleteRangeRequest) (*pb.DeleteRangeResponse, error)
	Txn(ctx context.Context, r *pb.TxnRequest) (*pb.TxnResponse, error)
	Compact(ctx context.Context, r *pb.CompactionRequest) (*pb.CompactionResponse, error)
}

type Lessor interface {
	// LeaseGrant sends LeaseGrant request to raft and apply it after committed.
	LeaseGrant(ctx context.Context, r *pb.LeaseGrantRequest) (*pb.LeaseGrantResponse, error)
	// LeaseRevoke sends LeaseRevoke request to raft and apply it after committed.
	LeaseRevoke(ctx context.Context, r *pb.LeaseRevokeRequest) (*pb.LeaseRevokeResponse, error)

	// LeaseRenew renews the lease with given ID. The renewed TTL is returned. Or an error
	// is returned.
	LeaseRenew(ctx context.Context, id lease.LeaseID) (int64, error)

	// LeaseTimeToLive retrieves lease information.
	LeaseTimeToLive(ctx context.Context, r *pb.LeaseTimeToLiveRequest) (*pb.LeaseTimeToLiveResponse, error)

	// LeaseLeases lists all leases.
	LeaseLeases(ctx context.Context, r *pb.LeaseLeasesRequest) (*pb.LeaseLeasesResponse, error)
}

type Authenticator interface {
	AuthEnable(ctx context.Context, r *pb.AuthEnableRequest) (*pb.AuthEnableResponse, error)
	AuthDisable(ctx context.Context, r *pb.AuthDisableRequest) (*pb.AuthDisableResponse, error)
	Authenticate(ctx context.Context, r *pb.AuthenticateRequest) (*pb.AuthenticateResponse, error)
	UserAdd(ctx context.Context, r *pb.AuthUserAddRequest) (*pb.AuthUserAddResponse, error)
	UserDelete(ctx context.Context, r *pb.AuthUserDeleteRequest) (*pb.AuthUserDeleteResponse, error)
	UserChangePassword(ctx context.Context, r *pb.AuthUserChangePasswordRequest) (*pb.AuthUserChangePasswordResponse, error)
	UserGrantRole(ctx context.Context, r *pb.AuthUserGrantRoleRequest) (*pb.AuthUserGrantRoleResponse, error)
	UserGet(ctx context.Context, r *pb.AuthUserGetRequest) (*pb.AuthUserGetResponse, error)
	UserRevokeRole(ctx context.Context, r *pb.AuthUserRevokeRoleRequest) (*pb.AuthUserRevokeRoleResponse, error)
	RoleAdd(ctx context.Context, r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse, error)
	RoleGrantPermission(ctx context.Context, r *pb.AuthRoleGrantPermissionRequest) (*pb.AuthRoleGrantPermissionResponse, error)
	RoleGet(ctx context.Context, r *pb.AuthRoleGetRequest) (*pb.AuthRoleGetResponse, error)
	RoleRevokePermission(ctx context.Context, r *pb.AuthRoleRevokePermissionRequest) (*pb.AuthRoleRevokePermissionResponse, error)
	RoleDelete(ctx context.Context, r *pb.AuthRoleDeleteRequest) (*pb.AuthRoleDeleteResponse, error)
	UserList(ctx context.Context, r *pb.AuthUserListRequest) (*pb.AuthUserListResponse, error)
	RoleList(ctx context.Context, r *pb.AuthRoleListRequest) (*pb.AuthRoleListResponse, error)
}

接口实现

/ EtcdServer is the production implementation of the Server interface
type EtcdServer struct {
	// inflightSnapshots holds count the number of snapshots currently inflight.
	inflightSnapshots int64  // must use atomic operations to access; keep 64-bit aligned.
	appliedIndex      uint64 // must use atomic operations to access; keep 64-bit aligned.
	committedIndex    uint64 // must use atomic operations to access; keep 64-bit aligned.
	term              uint64 // must use atomic operations to access; keep 64-bit aligned.
	lead              uint64 // must use atomic operations to access; keep 64-bit aligned.

	// consistIndex used to hold the offset of current executing entry
	// It is initialized to 0 before executing any entry.
	consistIndex consistentIndex // must use atomic operations to access; keep 64-bit aligned.
	r            raftNode        // uses 64-bit atomics; keep 64-bit aligned.

	readych chan struct{}
	Cfg     ServerConfig

	lgMu *sync.RWMutex
	lg   *zap.Logger

	w wait.Wait

	readMu sync.RWMutex
	// read routine notifies etcd server that it waits for reading by sending an empty struct to
	// readwaitC
	readwaitc chan struct{}
	// readNotifier is used to notify the read routine that it can process the request
	// when there is no error
	readNotifier *notifier

	// stop signals the run goroutine should shutdown.
	stop chan struct{}
	// stopping is closed by run goroutine on shutdown.
	stopping chan struct{}
	// done is closed when all goroutines from start() complete.
	done chan struct{}
	// leaderChanged is used to notify the linearizable read loop to drop the old read requests.
	leaderChanged   chan struct{}
	leaderChangedMu sync.RWMutex

	errorc     chan error
	id         types.ID
	attributes membership.Attributes

	cluster *membership.RaftCluster

	v2store     v2store.Store
	snapshotter *snap.Snapshotter

	applyV2 ApplierV2

	// applyV3 is the applier with auth and quotas
	applyV3 applierV3
	// applyV3Base is the core applier without auth or quotas
	applyV3Base applierV3
	applyWait   wait.WaitTime

	kv         mvcc.ConsistentWatchableKV
	lessor     lease.Lessor
	bemu       sync.Mutex
	be         backend.Backend
	authStore  auth.AuthStore
	alarmStore *v3alarm.AlarmStore

	stats  *stats.ServerStats
	lstats *stats.LeaderStats

	SyncTicker *time.Ticker
	// compactor is used to auto-compact the KV.
	compactor v3compactor.Compactor

	// peerRt used to send requests (version, lease) to peers.
	peerRt   http.RoundTripper
	reqIDGen *idutil.Generator

	// forceVersionC is used to force the version monitor loop
	// to detect the cluster version immediately.
	forceVersionC chan struct{}

	// wgMu blocks concurrent waitgroup mutation while server stopping
	wgMu sync.RWMutex
	// wg is used to wait for the go routines that depends on the server state
	// to exit when stopping the server.
	wg sync.WaitGroup

	// ctx is used for etcd-initiated requests that may need to be canceled
	// on etcd server shutdown.
	ctx    context.Context
	cancel context.CancelFunc

	leadTimeMu      sync.RWMutex
	leadElectedTime time.Time

	*AccessController
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值