【ETCD】【源码阅读】configureClientListeners () 函数解析

发布于:2024-12-18 ⋅ 阅读:(91) ⋅ 点赞:(0)

逐步解析 configureClientListeners 函数

configureClientListeners 是 ETCD 的一个重要函数,用于配置客户端通信的监听器(Client Listeners)。这些监听器主要负责处理外部客户端与 ETCD 服务之间的通信,包括 HTTP 和 gRPC 请求。


函数签名:

func configureClientListeners(cfg *Config) (sctxs map[string]*serveCtx, err error)
  • 输入参数
    • cfg *Config:指向 ETCD 配置结构体的指针,包含监听器相关的所有配置项。
  • 返回值
    • sctxs map[string]*serveCtx:返回一个 serveCtx 的映射,键是监听地址,值是 serveCtx 实例。
    • err error:如果配置过程中出现错误,返回详细的错误信息。

函数解析

1. 更新加密套件配置
if err = updateCipherSuites(&cfg.ClientTLSInfo, cfg.CipherSuites); err != nil {
    return nil, err
}
  • 作用:更新客户端通信中 TLS 的加密套件。
  • 逻辑
    • 使用配置中的 CipherSuites 更新 cfg.ClientTLSInfo
    • 如果加密套件的配置不正确,返回错误。

2. 配置客户端自签名证书
if err = cfg.ClientSelfCert(); err != nil {
    cfg.logger.Fatal("failed to get client self-signed certs", zap.Error(err))
}
  • 作用:为客户端通信生成自签名证书(如果未提供证书文件)。
  • 逻辑
    • 调用 ClientSelfCert 方法生成自签名证书。
    • 如果生成失败,记录错误日志并终止程序。

3. 更新 TLS 版本
updateMinMaxVersions(&cfg.ClientTLSInfo, cfg.TlsMinVersion, cfg.TlsMaxVersion)
  • 作用:更新客户端通信中 TLS 的最小和最大版本。
  • 逻辑
    • 根据配置中的 TlsMinVersionTlsMaxVersion 更新 cfg.ClientTLSInfo

4. 启用 pprof
if cfg.EnablePprof {
    cfg.logger.Info("pprof is enabled", zap.String("path", debugutil.HTTPPrefixPProf))
}
  • 作用:如果启用了 pprof(性能剖析工具),记录日志说明已启用。

5. 初始化 serveCtx 映射
sctxs = make(map[string]*serveCtx)
  • 作用:创建一个空的 serveCtx 映射,用于存储每个客户端监听器的上下文。

6. 校验客户端 URL
for _, u := range append(cfg.ListenClientUrls, cfg.ListenClientHttpUrls...) {
    if u.Scheme == "http" || u.Scheme == "unix" {
        if !cfg.ClientTLSInfo.Empty() {
            cfg.logger.Warn("scheme is http or unix while key and cert files are present; ignoring key and cert files", zap.String("client-url", u.String()))
        }
        if cfg.ClientTLSInfo.ClientCertAuth {
            cfg.logger.Warn("scheme is http or unix while --client-cert-auth is enabled; ignoring client cert auth for this URL", zap.String("client-url", u.String()))
        }
    }
    if (u.Scheme == "https" || u.Scheme == "unixs") && cfg.ClientTLSInfo.Empty() {
        return nil, fmt.Errorf("TLS key/cert (--cert-file, --key-file) must be provided for client url %s with HTTPS scheme", u.String())
    }
}
  • 逻辑
    • HTTP/Unix 检查:如果 URL 协议是 httpunix 且配置了 TLS,发出警告,忽略 TLS 配置。
    • HTTPS/Unixs 检查:如果 URL 协议是 httpsunixs 且未提供证书文件,返回错误。

7. 为 ListenClientUrls 配置监听器
for _, u := range cfg.ListenClientUrls {
    addr, secure, network := resolveURL(u)
    sctx := sctxs[addr]
    if sctx == nil {
        sctx = newServeCtx(cfg.logger)
        sctxs[addr] = sctx
    }
    sctx.secure = sctx.secure || secure
    sctx.insecure = sctx.insecure || !secure
    sctx.scheme = u.Scheme
    sctx.addr = addr
    sctx.network = network
}
  • 作用:为所有 ListenClientUrls 配置监听器。
  • 逻辑
    • 解析每个 URL 的地址、是否安全(TLS)、网络类型。
    • 如果 serveCtx 不存在,则创建新的上下文并添加到 sctxs
    • 更新上下文的协议、地址和网络信息。

8. 为 ListenClientHttpUrls 配置监听器
for _, u := range cfg.ListenClientHttpUrls {
    addr, secure, network := resolveURL(u)

    sctx := sctxs[addr]
    if sctx == nil {
        sctx = newServeCtx(cfg.logger)
        sctxs[addr] = sctx
    } else if !sctx.httpOnly {
        return nil, fmt.Errorf("cannot bind both --listen-client-urls and --listen-client-http-urls on the same url %s", u.String())
    }
    sctx.secure = sctx.secure || secure
    sctx.insecure = sctx.insecure || !secure
    sctx.scheme = u.Scheme
    sctx.addr = addr
    sctx.network = network
    sctx.httpOnly = true
}
  • 逻辑
    • 如果 ListenClientHttpUrlsListenClientUrls 绑定到同一地址且 httpOnly 标志不一致,返回错误。
    • 配置上下文的安全标志、协议、地址和网络类型。

9. 创建实际监听器
for _, sctx := range sctxs {
    if sctx.l, err = transport.NewListenerWithOpts(sctx.addr, sctx.scheme,
        transport.WithSocketOpts(&cfg.SocketOpts),
        transport.WithSkipTLSInfoCheck(true),
    ); err != nil {
        return nil, err
    }
    ...
}
  • 作用:为每个上下文创建实际的网络监听器。
  • 逻辑
    • 调用 transport.NewListenerWithOpts 创建监听器。
    • 配置套接字选项和 TLS 信息。

10. 检查文件描述符限制
if fdLimit, fderr := runtimeutil.FDLimit(); fderr == nil {
    if fdLimit <= reservedInternalFDNum {
        cfg.logger.Fatal(
            "file descriptor limit of etcd process is too low; please set higher",
            zap.Uint64("limit", fdLimit),
            zap.Int("recommended-limit", reservedInternalFDNum),
        )
    }
    sctx.l = transport.LimitListener(sctx.l, int(fdLimit-reservedInternalFDNum))
}
  • 作用:检查进程的文件描述符限制,确保足够高以支持大规模连接。
  • 逻辑
    • 如果限制过低,记录致命错误并终止程序。

11. 注册调试和性能工具
if cfg.EnablePprof || cfg.LogLevel == "debug" {
    sctx.registerPprof()
}
if cfg.LogLevel == "debug" {
    sctx.registerTrace()
}
  • 作用:如果启用了 pprof 或调试日志,注册性能和跟踪工具。

总结

  • 功能configureClientListeners 负责为所有客户端通信 URL 创建监听器,并初始化对应的上下文(serveCtx)。
  • 关键点
    1. 检查和更新 TLS 配置。
    2. 支持 HTTP 和 HTTPS 协议,同时处理安全和非安全连接。
    3. 确保资源限制(如文件描述符)满足运行要求。
    4. 注册调试工具(如 pprof)。
  • 核心调用
    • transport.NewListenerWithOpts 创建网络监听器。
    • runtimeutil.FDLimit 检查文件描述符限制。
    • sctx.registerPprof 注册性能剖析工具。

网站公告

今日签到

点亮在社区的每一天
去签到