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
}