ETCD《一》--Client監(jiān)聽(tīng)

開(kāi)啟Client監(jiān)聽(tīng)

Client監(jiān)聽(tīng)通常監(jiān)聽(tīng)在2379端口上,用于對(duì)外提供http+grpc服務(wù),如etcdctl客戶端等

http監(jiān)聽(tīng)

普通http監(jiān)聽(tīng)會(huì)注冊(cè)一些rest api

  • /debug/vars

  • /version

  • /metrics

  • /health

grpc監(jiān)聽(tīng)

grpc基于http2協(xié)議

grpc層也實(shí)現(xiàn)了一些keepalive策略

定義 服務(wù)器端主動(dòng)發(fā)送 ping 的時(shí)間間隔,用來(lái)確認(rèn)客戶端還在;Timeout: ping 發(fā)出后多長(zhǎng)時(shí)間沒(méi)收到 ACK 就斷開(kāi)連接

grpc.KeepaliveParams(keepalive.ServerParameters{
            Time:    e.cfg.GRPCKeepAliveInterval,  // 2h
            Timeout: e.cfg.GRPCKeepAliveTimeout,  // 20s
        }

限制客戶端的 ping 頻率,防止 DoS 攻擊或?yàn)E用資源(否則斷開(kāi)連接)

grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
            MinTime:             e.cfg.GRPCKeepAliveMinTime,  // 5s
            PermitWithoutStream: false,
        }

grpc中的注冊(cè)方法分為兩類:

  • Unary:類似HTTP rest請(qǐng)求,一次請(qǐng)求,一次響應(yīng);但仍然是基于http2的,可以在保持連接的時(shí)候做到tcp連接復(fù)用,在同一個(gè)tcp連接上復(fù)用http多路傳輸

  • Stream:流式請(qǐng)求,連接不斷開(kāi),采用推送的方式,類似SSE

在注冊(cè)方法的時(shí)候可以選擇注冊(cè)為Unary方法或者stream方法,在調(diào)用的時(shí)候通過(guò)不同的攔截器進(jìn)行處理

srv, knownService := s.services[service]
    if knownService {
        if md, ok := srv.methods[method]; ok {
            s.processUnaryRPC(ctx, stream, srv, md, ti)
            return
        }
        if sd, ok := srv.streams[method]; ok {
            s.processStreamingRPC(ctx, stream, srv, sd, ti)
            return
        }
    }

grpc監(jiān)聽(tīng)和http監(jiān)聽(tīng)是監(jiān)聽(tīng)在同一個(gè)端口上的,通過(guò) cmux 多路復(fù)用器同時(shí)運(yùn)行 gRPC 和 HTTP 服務(wù)

m := cmux.New(sctx.l)
server = m.Serve
err = server()

在處理請(qǐng)求時(shí),對(duì)于http2請(qǐng)求并且請(qǐng)求header中包含Content-Type=application/grpc的將其轉(zhuǎn)發(fā)到grpc服務(wù)、否則將其轉(zhuǎn)發(fā)到http服務(wù)

return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
            grpcServer.ServeHTTP(w, r)
        } else {
            otherHandler.ServeHTTP(w, r)
        }
    })

grpc注冊(cè)的服務(wù)端點(diǎn):

  • KVServer:服務(wù)名稱:/etcdserverpb.KV/ ;注冊(cè)的Unary方法包括:

    • Range
    • Put
    • DeleteRange
    • Txn
    • Compact
  • WatchServer:服務(wù)名稱:/etcdserverpb.Watch/ ;注冊(cè)的Stream方法包括:

    • Watch
  • LeaseServer:服務(wù)名稱:/etcdserverpb.Lease/ ;注冊(cè)的Unary方法包括:

    • LeaseGrant
    • LeaseRevoke
    • LeaseTimeToLive
    • LeaseLeases
      注冊(cè)的Stream方法包括:
    • LeaseKeepAlive
  • ClusterServer:服務(wù)名稱:/etcdserverpb.Cluster/ ;注冊(cè)的Unary方法包括:

    • MemberAdd
    • MemberRemove
    • MemberUpdate
    • MemberList
    • MemberPromote
  • AuthServer:服務(wù)名稱:/etcdserverpb.Auth/ ;注冊(cè)的Unary方法包括:AuthEnable、AuthDisable、UserAdd、RoleAdd等

  • HealthServer:服務(wù)名稱:/grpc.health.v1.Health/ ;注冊(cè)的Unary方法包括:

    • Check
    • List
      注冊(cè)的Stream方法包括:
    • Watch
  • MaintenanceServer:服務(wù)名稱:/etcdserverpb.Maintenance/ ;注冊(cè)的Unary方法包括:

    • Alarm、Status、Defragment、Hash、HashKV、MoveLeader、Downgrade
      注冊(cè)的Stream方法包括:
    • Snapshot
  • ElectionServer:服務(wù)名稱:/v3electionpb.Election/ ;注冊(cè)的Unary方法包括:

    • Campaign、Proclaim、Leader、Resign
      注冊(cè)的Stream方法包括:
    • Observe
  • LockServer:服務(wù)名稱:/v3lockpb.Lock/ ;注冊(cè)的Unary方法包括:

    • Lock、Unlock

grpc-gateway

grpc-gateway用于將grpc上注冊(cè)的方法同時(shí)注冊(cè)為http rest端點(diǎn),能夠使用http rest 方式來(lái)請(qǐng)求grpc服務(wù)

將自身做為grpc客戶端,dial client監(jiān)聽(tīng)的端口,用于接收http請(qǐng)求,并轉(zhuǎn)換為grpc請(qǐng)求轉(zhuǎn)發(fā)到 client監(jiān)聽(tīng)的端口

conn, err := dial(ctx)

構(gòu)建grpc gateway,定義接收到的http請(qǐng)求參數(shù)反序列話方式,UseProtoNames直接使用protobuf定義的字段名稱而不是駝峰命名等

gwmux := gw.NewServeMux(
        gw.WithMarshalerOption(gw.MIMEWildcard,
            &gw.HTTPBodyMarshaler{
                Marshaler: &gw.JSONPb{
                    MarshalOptions: protojson.MarshalOptions{
                        UseProtoNames:   true,
                        EmitUnpopulated: false,
                    },
                    UnmarshalOptions: protojson.UnmarshalOptions{
                        DiscardUnknown: true,
                    },
                },
            },
        ),
    )

將grpc服務(wù)注冊(cè)為http rest 端點(diǎn),對(duì)應(yīng)的就是上述grpc服務(wù)上注冊(cè)的那些服務(wù)方法

handlers := []registerHandlerFunc{
        etcdservergw.RegisterKVHandler,
        etcdservergw.RegisterWatchHandler,
        etcdservergw.RegisterLeaseHandler,
        etcdservergw.RegisterClusterHandler,
        etcdservergw.RegisterMaintenanceHandler,
        etcdservergw.RegisterAuthHandler,
        v3lockgw.RegisterLockHandler,
        v3electiongw.RegisterElectionHandler,
    }

注冊(cè)格式:

  • 全部使用POST方式注冊(cè)
mux.Handle(http.MethodPost, pattern_KV_Range_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
        //
    })
  • 映射路徑解析:[]int{2, 0, 2, 1, 2, 2} 是 opcode(操作碼),2 對(duì)應(yīng)的是入棧操作,操作的是[]string{"v3", "kv", "range"}這個(gè)數(shù)組元素,2,0相當(dāng)于把0號(hào)元素v3入棧,2,1相當(dāng)于把1號(hào)元素kv入棧,2,2相當(dāng)于把2號(hào)元素range入棧,最終構(gòu)成的請(qǐng)求路徑就是:/v3/kv/range

pattern_KV_Range_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v3", "kv", "range"}, ""))

因此可以通過(guò)POST http://127.0.0.1:2379/v3/kv/range來(lái)請(qǐng)求grpc方法:/etcdserverpb.KV/Range

還可以通過(guò)websocket來(lái)請(qǐng)求grpc方法,這里自動(dòng)將”/v3“開(kāi)頭的 WebSocket 請(qǐng)求轉(zhuǎn)成 HTTP POST請(qǐng)求,進(jìn)而在轉(zhuǎn)換為grpc請(qǐng)求

if gwmux != nil {
        httpmux.Handle(
            "/v3/",
            wsproxy.WebsocketProxy(
                gwmux,
                wsproxy.WithRequestMutator(
                    // Default to the POST method for streams
                    func(_ *http.Request, outgoing *http.Request) *http.Request {
                        outgoing.Method = "POST"
                        return outgoing
                    },
                ),
                wsproxy.WithMaxRespBodyBufferSize(0x7fffffff),
                wsproxy.WithLogger(wsProxyZapLogger{sctx.lg}),
            ),
        )
    }

總結(jié)

整個(gè)Client的監(jiān)聽(tīng)中,可以歸納為這類型的請(qǐng)求:

  • 普通http rest請(qǐng)求,如/version、/metrics等,直接交給 http 服務(wù)器處理

  • grpc請(qǐng)求,這部分請(qǐng)求是http2的,并且header種攜帶Content-Type=application/grpc,直接交給grpc 服務(wù)器處理

  • http rest請(qǐng)求,請(qǐng)求類路是/v3開(kāi)頭的,請(qǐng)求方法是POST,這部分請(qǐng)求交給grpc-gateway處理,grpc-gateway會(huì)將自身作為grpc client,進(jìn)而將http請(qǐng)求轉(zhuǎn)發(fā)給grpc服務(wù)處理

  • websocket 請(qǐng)求,請(qǐng)求路徑是/v3開(kāi)頭的,這部分請(qǐng)求也交給grpc-gateway處理,grpc-gateway會(huì)自動(dòng)把websocket請(qǐng)求轉(zhuǎn)換為 http post請(qǐng)求,進(jìn)而交給grpc服務(wù)處理

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容