日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
在Kubernetes環(huán)境中實(shí)現(xiàn)gRPC負(fù)載均衡

前言

前段時(shí)間寫(xiě)過(guò)一篇 gRPC 的入門(mén)文章,在最后還留了一個(gè)坑沒(méi)有填:

圖片

也就是 gRPC 的負(fù)載均衡問(wèn)題,因?yàn)楫?dāng)時(shí)的業(yè)務(wù)請(qǐng)求量不算大,再加上公司沒(méi)有對(duì) Istio 這類(lèi)服務(wù)網(wǎng)格比較熟悉的大牛,所以我們也就一直拖著沒(méi)有解決,依然只是使用了 kubernetes 的 service 進(jìn)行負(fù)載,好在也沒(méi)有出什么問(wèn)題。

由于現(xiàn)在換了公司后也需要維護(hù)公司的服務(wù)網(wǎng)格服務(wù),結(jié)合公司內(nèi)部對(duì) Istio 的使用現(xiàn)在終于不再停留在理論階段了。

所以也終有機(jī)會(huì)將這個(gè)坑填了。

gRPC 負(fù)載均衡

負(fù)載不均衡

原理

先來(lái)回顧下背景,為什么會(huì)有 gRPC 負(fù)債不均衡的問(wèn)題。由于 gRPC 是基于 HTTP/2 協(xié)議的,所以客戶端和服務(wù)端會(huì)保持長(zhǎng)鏈接,一旦鏈接建立成功后就會(huì)一直使用這個(gè)連接處理后續(xù)的請(qǐng)求。

圖片

除非我們每次請(qǐng)求之后都新建一個(gè)連接,這顯然是不合理的。

所以要解決 gRPC 的負(fù)載均衡通常有兩種方案:

  • 服務(wù)端負(fù)載均衡
  • 客戶端負(fù)載均衡 在 gRPC 這個(gè)場(chǎng)景服務(wù)端負(fù)載均衡不是很合適,所有的請(qǐng)求都需要經(jīng)過(guò)一個(gè)負(fù)載均衡器,這樣它就成為整個(gè)系統(tǒng)的瓶頸,所以更推薦使用客戶端負(fù)載均衡。

客戶端負(fù)載均衡目前也有兩種方案,最常見(jiàn)也是傳統(tǒng)方案。

圖片

這里以 Dubbo 的調(diào)用過(guò)程為例,調(diào)用的時(shí)候需要從服務(wù)注冊(cè)中心獲取到提供者的節(jié)點(diǎn)信息,然后在客戶端本地根據(jù)一定的負(fù)載均衡算法得出一個(gè)節(jié)點(diǎn)然后發(fā)起請(qǐng)求。

換成 gRPC 也是類(lèi)似的,這里以 go-zero 負(fù)載均衡的原理為例:

圖片

gRPC 官方庫(kù)也提供了對(duì)應(yīng)的負(fù)載均衡接口,但我們依然需要自己維護(hù)服務(wù)列表然后在客戶端編寫(xiě)負(fù)載均衡算法,這里有個(gè)官方 demo:

https://github.com/grpc/grpc-go/blob/87eb5b7502493f758e76c4d09430c0049a81a557/examples/features/load_balancing/client/main.go

但切換到 kubernetes 環(huán)境中時(shí)再使用以上的方式就不夠優(yōu)雅了,因?yàn)槲覀兪褂?kubernetes 的目的就是不想再額外的維護(hù)這個(gè)客戶端包,這部分能力最好是由 kubernetes 自己就能提供。

但遺憾的是 kubernetes 提供的 service 只是基于 L4 的負(fù)載,所以我們每次請(qǐng)求的時(shí)候都只能將請(qǐng)求發(fā)往同一個(gè) Provider 節(jié)點(diǎn)。

測(cè)試

這里我寫(xiě)了一個(gè)小程序來(lái)驗(yàn)證負(fù)債不均衡的示例:

// Create gRPC server
go func() {  
   var port = ":50051"  
   lis, err := net.Listen("tcp", port)  
   if err != nil {  
      log.Fatalf("failed to listen: %v", err)  
   }  
   s := grpc.NewServer()  
   pb.RegisterGreeterServer(s, &server{})  
   if err := s.Serve(lis); err != nil {  
      log.Fatalf("failed to serve: %v", err)  
   } else {  
      log.Printf("served on %s \n", port)  
   }  
}()
// server is used to implement helloworld.GreeterServer.  
type server struct {  
   pb.UnimplementedGreeterServer  
}  
  
// SayHello implements helloworld.GreeterServer  
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {  
   log.Printf("Received: %v", in.GetName())  
   name, _ := os.Hostname()  
   // Return hostname of Server
   return &pb.HelloReply{Message: fmt.Sprintf("hostname:%s, in:%s", name, in.Name)}, nil  
}

使用同一個(gè) gRPC 連接發(fā)起一次 gRPC 請(qǐng)求,服務(wù)端會(huì)返回它的 hostname

var (  
   once sync.Once  
   c    pb.GreeterClient  
)  
http.HandleFunc("/grpc_client", func(w http.ResponseWriter, r *http.Request) {  
   once.Do(func() {  
      service := r.URL.Query().Get("name")  
      conn, err := grpc.Dial(fmt.Sprintf("%s:50051", service), grpc.WithInsecure(), grpc.WithBlock())  
      if err != nil {  
         log.Fatalf("did not connect: %v", err)  
      }  
      c = pb.NewGreeterClient(conn)  
   })  
  
   // Contact the server and print out its response.  
   name := "world"  
   ctx, cancel := context.WithTimeout(context.Background(), time.Second)  
   defer cancel()  
   g, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})  
   if err != nil {  
      log.Fatalf("could not greet: %v", err)  
   }  
   fmt.Fprint(w, fmt.Sprintf("Greeting: %s", g.GetMessage()))  
})

創(chuàng)建一個(gè) service 用于給 gRPC 提供域名:

apiVersion: v1  
kind: Service  
metadata:  
  name: native-tools-2
spec:  
  selector:  
    app: native-tools-2
  ports:  
    - name: http  
      port: 8081  
      targetPort: 8081  
    - name: grpc  
      port: 50051  
      targetPort: 50051

同時(shí)將我們的 gRPC server 部署三個(gè)節(jié)點(diǎn),再部署了一個(gè)客戶端節(jié)點(diǎn):

 k get pod
NAME                                READY   STATUS    RESTARTS
native-tools-2-d6c454689-52wgd      1/1     Running   0              
native-tools-2-d6c454689-67rx4      1/1     Running   0              
native-tools-2-d6c454689-zpwxt      1/1     Running   0              
native-tools-65c5bd87fc-2fsmc       2/2     Running   0

我們進(jìn)入客戶端節(jié)點(diǎn)執(zhí)行多次 grpc 請(qǐng)求:

k exec -it native-tools-65c5bd87fc-2fsmc bash
Greeting: hostname:native-tools-2-d6c454689-zpwxt, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2
Greeting: hostname:native-tools-2-d6c454689-zpwxt, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2
Greeting: hostname:native-tools-2-d6c454689-zpwxt, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2
Greeting: hostname:native-tools-2-d6c454689-zpwxt, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2
Greeting: hostname:native-tools-2-d6c454689-zpwxt, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2
Greeting: hostname:native-tools-2-d6c454689-zpwxt, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2
Greeting: hostname:native-tools-2-d6c454689-zpwxt, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2
Greeting: hostname:native-tools-2-d6c454689-zpwxt, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2

會(huì)發(fā)現(xiàn)每次請(qǐng)求的都是同一個(gè)節(jié)點(diǎn) native-tools-2-d6c454689-zpwxt,這也就證明了在 kubernetes 中直接使用 gRPC 負(fù)載是不均衡的,一旦連接建立后就只能將請(qǐng)求發(fā)往那個(gè)節(jié)點(diǎn)。

使用 Istio

Istio 可以拿來(lái)解決這個(gè)問(wèn)題,我們換到一個(gè)注入了 Istio 的 namespace 下還是同樣的 代碼,同樣的 service 資源進(jìn)行測(cè)試。

關(guān)于開(kāi)啟 namespace 的 Istio 注入會(huì)在后續(xù)更新,現(xiàn)在感興趣的可以查看下官方文檔:https://istio.io/latest/docs/setup/additional-setup/sidecar-injection/

Greeting: hostname:native-tools-2-5fbf46cf54-5m7dl, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2

Greeting: hostname:native-tools-2-5fbf46cf54-xprjz, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2

Greeting: hostname:native-tools-2-5fbf46cf54-5m7dl, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2

Greeting: hostname:native-tools-2-5fbf46cf54-5m7dl, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2

Greeting: hostname:native-tools-2-5fbf46cf54-xprjz, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2

Greeting: hostname:native-tools-2-5fbf46cf54-xprjz, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2

Greeting: hostname:native-tools-2-5fbf46cf54-5m7dl, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2

Greeting: hostname:native-tools-2-5fbf46cf54-5m7dl, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2

Greeting: hostname:native-tools-2-5fbf46cf54-nz8h5, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2

Greeting: hostname:native-tools-2-5fbf46cf54-nz8h5, in:worldistio-proxy@n:/$ curl http://127.0.0.1:8081/grpc_client?name=native-tools-2

可以發(fā)現(xiàn)同樣的請(qǐng)求已經(jīng)被負(fù)載到了多個(gè) server 后端,這樣我們就可以不再單獨(dú)維護(hù)一個(gè)客戶端 SDK 的情況下實(shí)現(xiàn)了負(fù)載均衡。

原理

其實(shí)本質(zhì)上 Istio 也是客戶端負(fù)載均衡的一種實(shí)現(xiàn)。

圖片

以 Istio 的架構(gòu)圖為例:

  • 每一個(gè) Pod 下會(huì)新增一個(gè) Proxy 的 container,所有的流量入口和出口都會(huì)經(jīng)過(guò)它。
  • 它會(huì)從控制平面 Istiod 中拿到服務(wù)的注冊(cè)信息,也就是 kubernetes 中的 service。
  • 發(fā)生請(qǐng)求時(shí)由 proxy 容器中的 Envoy 進(jìn)行最終的負(fù)載請(qǐng)求。

可以在使用了 Istio 的 Pod 中查看到具體的容器:

 k get pod native-tools-2-5fbf46cf54-5m7dl -n istio-test-2 -o json | jq '.spec.containers[].name'
"istio-proxy"
"native-tools-2"

可以發(fā)現(xiàn)這里存在一個(gè) istio-proxy 的容器,也就是我們常說(shuō)的 sidecar,這樣我們就可以把原本的 SDK 里的功能全部交給 Istio 去處理。

總結(jié)

當(dāng)然 Istio 的功能遠(yuǎn)不止于此,比如:

  • 統(tǒng)一網(wǎng)關(guān),處理東西、南北向流量。
  • 灰度發(fā)布
  • 流量控制
  • 接口粒度的超時(shí)配置
  • 自動(dòng)重試等

這次只是一個(gè)開(kāi)胃菜,更多關(guān)于 Istio 的內(nèi)容會(huì)在后續(xù)更新,比如會(huì)從如何在 kubernetes 集群中安裝 Istio 講起,帶大家一步步使用好 Istio。

本文相關(guān)源碼:https://github.com/crossoverJie/k8s-combat

參考鏈接:

  • https://istio.io/latest/docs/setup/getting-started/
  • https://segmentfault.com/a/1190000042295402
  • https://go-zero.dev/docs/tutorials/service/governance/lb

分享標(biāo)題:在Kubernetes環(huán)境中實(shí)現(xiàn)gRPC負(fù)載均衡
轉(zhuǎn)載源于:http://www.5511xx.com/article/djdpghi.html