当前位置:首页 > 科技  > 软件

在 Kubernetes 环境中实现 gRPC 负载均衡

来源: 责编: 时间:2023-10-17 09:38:22 439观看
导读前言前段时间写过一篇 gRPC 的入门文章,在最后还留了一个坑没有填:图片也就是 gRPC 的负载均衡问题,因为当时的业务请求量不算大,再加上公司没有对 Istio 这类服务网格比较熟悉的大牛,所以我们也就一直拖着没有解决,依然只

前言

前段时间写过一篇 gRPC 的入门文章,在最后还留了一个坑没有填:0JM28资讯网——每日最新资讯28at.com

图片图片0JM28资讯网——每日最新资讯28at.com

也就是 gRPC 的负载均衡问题,因为当时的业务请求量不算大,再加上公司没有对 Istio 这类服务网格比较熟悉的大牛,所以我们也就一直拖着没有解决,依然只是使用了 kubernetes 的 service 进行负载,好在也没有出什么问题。0JM28资讯网——每日最新资讯28at.com

由于现在换了公司后也需要维护公司的服务网格服务,结合公司内部对 Istio 的使用现在终于不再停留在理论阶段了。0JM28资讯网——每日最新资讯28at.com

所以也终有机会将这个坑填了。0JM28资讯网——每日最新资讯28at.com

gRPC 负载均衡

负载不均衡

原理

先来回顾下背景,为什么会有 gRPC 负债不均衡的问题。由于 gRPC 是基于 HTTP/2 协议的,所以客户端和服务端会保持长链接,一旦链接建立成功后就会一直使用这个连接处理后续的请求。0JM28资讯网——每日最新资讯28at.com

图片图片0JM28资讯网——每日最新资讯28at.com

除非我们每次请求之后都新建一个连接,这显然是不合理的。0JM28资讯网——每日最新资讯28at.com

所以要解决 gRPC 的负载均衡通常有两种方案:0JM28资讯网——每日最新资讯28at.com

  • 服务端负载均衡
  • 客户端负载均衡 在 gRPC 这个场景服务端负载均衡不是很合适,所有的请求都需要经过一个负载均衡器,这样它就成为整个系统的瓶颈,所以更推荐使用客户端负载均衡。

客户端负载均衡目前也有两种方案,最常见也是传统方案。0JM28资讯网——每日最新资讯28at.com

图片图片0JM28资讯网——每日最新资讯28at.com

这里以 Dubbo 的调用过程为例,调用的时候需要从服务注册中心获取到提供者的节点信息,然后在客户端本地根据一定的负载均衡算法得出一个节点然后发起请求。0JM28资讯网——每日最新资讯28at.com

换成 gRPC 也是类似的,这里以 go-zero 负载均衡的原理为例:0JM28资讯网——每日最新资讯28at.com

图片图片0JM28资讯网——每日最新资讯28at.com

gRPC 官方库也提供了对应的负载均衡接口,但我们依然需要自己维护服务列表然后在客户端编写负载均衡算法,这里有个官方 demo:0JM28资讯网——每日最新资讯28at.com

https://github.com/grpc/grpc-go/blob/87eb5b7502493f758e76c4d09430c0049a81a557/examples/features/load_balancing/client/main.go0JM28资讯网——每日最新资讯28at.com

但切换到 kubernetes 环境中时再使用以上的方式就不够优雅了,因为我们使用 kubernetes 的目的就是不想再额外的维护这个客户端包,这部分能力最好是由 kubernetes 自己就能提供。0JM28资讯网——每日最新资讯28at.com

但遗憾的是 kubernetes 提供的 service 只是基于 L4 的负载,所以我们每次请求的时候都只能将请求发往同一个 Provider 节点。0JM28资讯网——每日最新资讯28at.com

测试

这里我写了一个小程序来验证负债不均衡的示例:0JM28资讯网——每日最新资讯28at.com

// Create gRPC servergo 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  }

使用同一个 gRPC 连接发起一次 gRPC 请求,服务端会返回它的 hostname0JM28资讯网——每日最新资讯28at.com

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()))  })

创建一个 service 用于给 gRPC 提供域名:0JM28资讯网——每日最新资讯28at.com

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

同时将我们的 gRPC server 部署三个节点,再部署了一个客户端节点:0JM28资讯网——每日最新资讯28at.com

❯ k get podNAME                                READY   STATUS    RESTARTSnative-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

我们进入客户端节点执行多次 grpc 请求:0JM28资讯网——每日最新资讯28at.com

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

会发现每次请求的都是同一个节点 native-tools-2-d6c454689-zpwxt,这也就证明了在 kubernetes 中直接使用 gRPC 负载是不均衡的,一旦连接建立后就只能将请求发往那个节点。0JM28资讯网——每日最新资讯28at.com

使用 Istio

Istio 可以拿来解决这个问题,我们换到一个注入了 Istio 的 namespace 下还是同样的 代码,同样的 service 资源进行测试。0JM28资讯网——每日最新资讯28at.com

关于开启 namespace 的 Istio 注入会在后续更新,现在感兴趣的可以查看下官方文档:https://istio.io/latest/docs/setup/additional-setup/sidecar-injection/0JM28资讯网——每日最新资讯28at.com

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

可以发现同样的请求已经被负载到了多个 server 后端,这样我们就可以不再单独维护一个客户端 SDK 的情况下实现了负载均衡。0JM28资讯网——每日最新资讯28at.com

原理

其实本质上 Istio 也是客户端负载均衡的一种实现。0JM28资讯网——每日最新资讯28at.com

图片图片0JM28资讯网——每日最新资讯28at.com

以 Istio 的架构图为例:0JM28资讯网——每日最新资讯28at.com

  • 每一个 Pod 下会新增一个 Proxy 的 container,所有的流量入口和出口都会经过它。
  • 它会从控制平面 Istiod 中拿到服务的注册信息,也就是 kubernetes 中的 service。
  • 发生请求时由 proxy 容器中的 Envoy 进行最终的负载请求。

可以在使用了 Istio 的 Pod 中查看到具体的容器:0JM28资讯网——每日最新资讯28at.com

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

可以发现这里存在一个 istio-proxy 的容器,也就是我们常说的 sidecar,这样我们就可以把原本的 SDK 里的功能全部交给 Istio 去处理。0JM28资讯网——每日最新资讯28at.com

总结

当然 Istio 的功能远不止于此,比如:0JM28资讯网——每日最新资讯28at.com

  • 统一网关,处理东西、南北向流量。
  • 灰度发布
  • 流量控制
  • 接口粒度的超时配置
  • 自动重试等

这次只是一个开胃菜,更多关于 Istio 的内容会在后续更新,比如会从如何在 kubernetes 集群中安装 Istio 讲起,带大家一步步使用好 Istio。0JM28资讯网——每日最新资讯28at.com

本文相关源码:https://github.com/crossoverJie/k8s-combat0JM28资讯网——每日最新资讯28at.com

参考链接:0JM28资讯网——每日最新资讯28at.com

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

本文链接:http://www.28at.com/showinfo-26-13632-0.html在 Kubernetes 环境中实现 gRPC 负载均衡

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: C++中的外部链接性和内部链接性:探究其区别与应用

下一篇: 一文彻底掌握MQ消息积压全部解决方案

标签:
  • 热门焦点
  • 6月iOS设备好评榜:第一蝉联榜首近一年

    作为安兔兔各种榜单里变化最小的那个,2023年6月的iOS好评榜和上个月相比没有任何排名上的变化,仅仅是部分设备好评率的下降,长年累月的用户评价和逐渐退出市场的老款机器让这
  • 6月安卓手机性能榜:vivo/iQOO霸占旗舰排行榜前三

    2023年上半年已经正式过去了,我们也迎来了安兔兔V10版本,在新的骁龙8Gen3和天玑9300发布之前,性能榜的榜单大体会以骁龙8Gen2和天玑9200+为主,至于那颗3.36GHz的骁龙8Gen2领先
  • Rust中的高吞吐量流处理

    作者 | Noz编译 | 王瑞平本篇文章主要介绍了Rust中流处理的概念、方法和优化。作者不仅介绍了流处理的基本概念以及Rust中常用的流处理库,还使用这些库实现了一个流处理程序
  • SpringBoot中使用Cache提升接口性能详解

    环境:springboot2.3.12.RELEASE + JSR107 + Ehcache + JPASpring 框架从 3.1 开始,对 Spring 应用程序提供了透明式添加缓存的支持。和事务支持一样,抽象缓存允许一致地使用各
  • 梁柱接棒两年,腾讯音乐闯出新路子

    文丨田静 出品丨牛刀财经(niudaocaijing)7月5日,企鹅FM发布官方公告称由于业务调整,将于9月6日正式停止运营,这意味着腾讯音乐长音频业务走向消亡。腾讯在长音频领域还在摸索。为
  • 中国家电海外掘金正当时|出海专题

    作者|吴南南编辑|胡展嘉运营|陈佳慧出品|零态LT(ID:LingTai_LT)2023年,出海市场战况空前,中国创业者在海外纷纷摩拳擦掌,以期能够把中国的商业模式、创业理念、战略打法输出海外,他们依
  • 一条抖音4亿人围观 ! 这家MCN比无忧传媒还野

    作者:Hiu 来源:互联网品牌官01 擦边少女空降热搜,幕后推手曝光被网友誉为“纯欲天花板”的女网红井川里予,近期因为一组哥特风照片登上热搜,引发了一场互联网世界关于
  • 冯提莫签约抖音公会 前“斗鱼一姐”消失在直播间

    来源:直播观察提起“冯提莫”这个名字,很多网友或许听过,但应该不记得她是哪位主播了。其实,作为曾经的“斗鱼一姐”,冯提莫在游戏直播的年代影响力不输于现
  • 7月4日见!iQOO 11S官宣:“鸡血版”骁龙8 Gen2+200W快充加持

    上半年已接近尾声,截至目前各大品牌旗下的顶级旗舰都已悉数亮相,而下半年即将推出的顶级旗舰已经成为了数码圈爆料的主流,其中就包括全新的iQOO 11S系
Top