3年前 (2021-11-01)  相关技术 |   抢沙发  950 
文章评分 0 次,平均分 0.0

gRPC是用于进程间通信的最流行的现代RPC框架之一。对于微服务体系结构来说,这是一个很好的选择。毫无疑问,部署微服务应用程序最流行的方法之一是Kubernetes

Kubernetes部署可以有相同的后端实例来服务许多客户端请求。Kubernetes的ClusterIP服务提供负载平衡的IP地址。但是,这种默认的负载平衡在gRPC中无法立即实现。如果您将gRPC与许多部署在Kubernetes上的后端一起使用,则本文档适用于您。

为什么要进行负载平衡?

大规模部署具有许多相同的后端实例和许多客户端。每个后端服务器都有一定的容量。负载平衡用于将来自客户端的负载分布到可用服务器上。

在您开始详细了解Kubernetes中的gRPC负载平衡之前,让我们试着了解负载平衡的好处。

负载平衡有很多好处,其中一些好处是:

  • 故障容忍度:如果您的一个副本出现故障,那么其他服务器可以为该请求提供服务。
  • 提高了可伸缩性:您可以跨多个服务器分发用户流量,从而提高了可伸缩性。
  • 提高吞吐量:您可以通过在各种后端服务器上分布流量来提高应用程序的吞吐量。
  • 无缺点部署:您可以使用滚动部署技术实现无停机部署。

gRPC中的负载平衡选项

gRPC中有两种类型的负载平衡选项—代理和客户端。

代理负载平衡

在代理负载平衡中,客户端向负载平衡器(LB)代理发出RPC。LB将RPC调用分发给一个可用的后端服务器,该后端服务器实现为调用提供服务的实际逻辑。LB跟踪每个后端上的负载,并实现公平分配负载的算法。客户端本身不知道后端服务器。客户端可能不受信任。此体系结构通常用于面向用户的服务,其中来自开放internet的客户端可以连接到服务器

客户端负载平衡

在客户端负载平衡中,客户端知道许多后端服务器,并为每个RPC选择一个。如果客户端希望,它可以根据服务器的负载报告实现负载平衡算法。对于简单的部署,客户端可以在可用服务器之间循环请求。

与gRPC负载平衡相关的挑战

gRPC在HTTP/2上工作。HHTP/2上的TCP连接是长期的。一个连接可以多路传输多个请求。这减少了与连接管理相关的开销。但这也意味着连接级负载平衡不是很有用。Kubernetes中的默认负载平衡基于连接级负载平衡。因此,Kubernetes的默认负载平衡不适用于gRPC。

为了证实这个假设,让我们创建一个Kubernetes应用程序。此应用程序包括——

  • 服务器pod:Kubernetes部署有三个gRPC服务器pod。
  • 客户端pod:Kubernetes部署,带有一个gRPC客户端pod。
  • 服务:集群服务,它选择所有服务器pod。

Kubernetes上的gRPC负载均衡服务

创建服务器部署

要创建部署,请将以下代码保存在YAML文件中,比如deployment-server.yaml,然后运行命令kubectl apply -f deployment-server.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: grpc-server
  labels:
    app: grpc-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: grpc-server
  template:
    metadata:
      labels:
        app: grpc-server
    spec:
      containers:
        - name: grpc-server
          image: techdozo/grpc-lb-server:1.0.0

这将创建一个具有三个副本的gRPC服务器。gRPC服务器正在端口8001上运行。

要验证pod是否已成功创建,请运行命令kubectl get pods

NAME                           READY   STATUS    RESTARTS   AGE
grpc-server-6c9cd849-5pdbr     1/1     Running   0          1m
grpc-server-6c9cd849-86z7m     1/1     Running   0          1m
grpc-server-6c9cd849-mw9sb     1/1     Running   0          1m

您可以运行命令kubectl logs --follow grpc-server-<>查看日志。

创建服务

要创建服务,请将以下代码保存在YAML文件中,比如service.yaml,然后运行命令kubectl apply-f service.yaml

apiVersion: v1
kind: Service
metadata:
  name: grpc-server-service
spec:
  type: ClusterIP
  selector:
    app: grpc-server
  ports:
    - port: 80
      targetPort: 8001

ClusterIP服务提供负载平衡的IP地址。它负载平衡通过标签选择器匹配的pod端点之间的流量。

Name:              grpc-server-service
Namespace:         default      
Selector:          app=grpc-server
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.96.28.234
IPs:               10.96.28.234
Port:              <unset>  80/TCP
TargetPort:        8001/TCP
Endpoints:         10.244.0.11:8001,10.244.0.12:8001,10.244.0.13:8001
Session Affinity:  None

如上所述,POD的IP地址为–10.244.0.11:8001,10.244.0.12:8001,10.244.0.13:8001。若客户端在端口80上调用服务,那个么它将跨端点(POD的IP地址)进行负载平衡调用。但这对于gRPC是不正确的,您很快就会看到。

创建客户端部署

要创建客户端部署,请将以下代码保存在YAML文件中,比如deployment-client.yaml,然后运行命令kubectl apply-f deployment-client.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: grpc-client
  labels:
    app: grpc-client
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grpc-client
  template:
    metadata:
      labels:
        app: grpc-client
    spec:
      containers:
        - name: grpc-client
          image: techdozo/grpc-lb-client:1.0.0
          env:
            - name: SERVER_HOST
              value: grpc-server-service:80

gRPC客户端应用程序在启动时使用一个通道在10个并发线程中对服务器进行1000000次调用。SERVER_HOST环境变量指向服务grpc服务器服务的DNS。在gRPC客户端上,通过将SERVER_HOST(serverHost)传递为以下内容来创建通道:

ManagedChannelBuilder.forTarget(serverHost)
    .defaultLoadBalancingPolicy("round_robin")
    .usePlaintext()
    .build();

如果查看服务器日志,您会注意到所有客户端调用都只由一个服务器pod提供服务。

使用headless服务的客户端负载平衡

您可以使用Kubernetes headless服务进行客户端循环负载平衡。这种简单的负载平衡与gRPC一起开箱即用。缺点是它没有考虑服务器上的负载。

什么是Headless服务?

幸运的是,Kubernetes允许客户端通过DNS查找来发现pod IP。通常,当您对服务执行DNS查找时,DNS服务器返回单个IP—服务的群集IP。但是,如果您告诉Kubernetes您的服务不需要群集IP(您可以通过在服务规范中将clusterIP字段设置为None来实现),DNS服务器将返回pod IP而不是单个服务IP。DNS服务器不会返回单个DNS a记录,而是返回服务的多个a记录,每个记录都指向当时支持服务的单个pod的IP。因此,客户端可以进行简单的DNS a记录查找,并获取作为服务一部分的所有POD的IP。然后,客户机可以使用该信息连接到其中一个、多个或全部。

将服务规范中的clusterIP字段设置为None会使服务无头,因为Kubernetes不会为其分配群集IP,客户端可以通过该群集IP连接到支持它的POD。

Kubernetes在行动——Marko Lukša

将Headless服务定义为:

apiVersion: v1
kind: Service
metadata:
  name: grpc-server-service
spec:
  clusterIP: None
  selector:
    app: grpc-server
  ports:
    - port: 80
      targetPort: 8001

要使服务成为headless服务,唯一需要更改的字段是将.spec.clusterIP字段设置为None

验证DNS

要确认headless服务的DNS,请创建一个pod,其图像tutum/dnsutils为:

kubectl run dnsutils --image=tutum/dnsutils --command -- sleep infinity

然后运行命令

kubectl exec dnsutils --  nslookup grpc-server-service

此headless服务的返回FQDN为:

Server:         10.96.0.10
Address:        10.96.0.10#53
Name:   grpc-server-service.default.svc.cluster.local
Address: 10.244.0.22
Name:   grpc-server-service.default.svc.cluster.local
Address: 10.244.0.20
Name:   grpc-server-service.default.svc.cluster.local
Address: 10.244.0.21

正如您所见,headless服务解析为通过该服务连接的所有POD的IP地址。将此与非headless服务返回的输出进行对比。

Server:         10.96.0.10
Address:        10.96.0.10#53
Name:   grpc-server-service.default.svc.cluster.local
Address: 10.96.158.232

配置客户端

剩下的唯一更改是在客户端应用程序上,指向带有服务器pods端口的headless服务,如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: grpc-client
  labels:
    app: grpc-client
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grpc-client
  template:
    metadata:
      labels:
        app: grpc-client
    spec:
      containers:
        - name: grpc-client
          image: techdozo/grpc-lb-client:1.0.0
          env:
            - name: SERVER_HOST
              value: grpc-server-service:8001

注意,SERVER_HOST现在指向无头服务grpc服务器服务和服务器端口8001

您还可以将SERVER_HOST用作FQDN,如下所示:

name: SERVER_HOST
value: "grpc-server-service.default.svc.cluster.local:8001"

如果通过首先删除客户端部署来再次部署客户端,请执行以下操作:

kubectl delete deployment.apps/grpc-client 

然后再次将客户端部署为:

kubectl apply -f deployment-client.yaml

代码示例

本文的工作代码示例列在GitHub上:https://github.com/techdozo/grpc-lb

总结

gRPC中有两种负载平衡选项—代理和客户端。由于gRPC连接的寿命较长,Kubernetes的默认连接级别负载平衡不适用于gRPC。Kubernetes headless服务是一种可以实现负载平衡的机制。Kubernetes headless服务DNS解析为支持pods的IP。

原文地址:https://techdozo.dev/grpc-load-balancing-on-kubernetes-using-headless-service/

 

除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/2492.html

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册