在Kubernetes中实现gRPC流量负载均衡

在尝试将gRPC服务部署到Kubernetes集群中时,一些用户(包括我)面临的挑战之一是实现适当的负载均衡。在深入了解如何平衡gRPC的方式之前,我们首先需要回答一个问题,即为什么需要平衡流量,如果Kubernetes已经完成了这项工作。

本文关注于Kubernetes和Golang。

为什么在Kubernetes中无法适当地平衡gRPC流量?

之所以难以平衡gRPC流量的主要原因是人们将gRPC视为HTTP,这就是问题的根源。设计上它们是不同的,虽然HTTP为每个请求创建和关闭连接,但gRPC使用HTTP2协议,在长时间的TCP连接上运行,使得平衡更加困难,因为多个请求通过同一个连接进行多路复用。然而,这并不是配置gRPC服务在Kubernetes中出现平衡问题的唯一原因,以下是一些常见的错误配置:

  • 错误的gRPC客户端配置
  • 错误的Kubernetes服务配置

错误的gRPC客户端配置

设置gRPC客户端时常见的情况是选择默认配置,这对于1-1连接类型完全有效,但对于生产环境来说并不如我们所希望的有效。这背后的原因是因为默认的gRPC客户端提供了使用简单的IP/DNS记录连接的可能性,这只会创建一个与目标服务的连接。

因此,需要为与多个服务器建立连接进行不同的设置,将连接类型从1-1转换为1-N。

默认设置

func main(){conn, err := grpc.Dial("my-domain:50051", grpc.WithInsecure())if err != nil {log.Fatalf("error connecting with gRPC server: %v", err)}defer conn.Close()cli := test.NewTestServiceClient(conn)rs, err := cli.DoSomething(context.Background(), ...)...
}

新的设置

func main() {address := fmt.Sprintf("%s:///%s", "dns", "my-domain:50051")conn, err := grpc.Dial(address,grpc.WithInsecure(),grpc.WithBalancerName(roundrobin.Name))if err != nil {log.Fatalf("did not connect: %v", err)}defer conn.Close()...
}

这里有两个重要的更改需要注意:

  • 地址: 最终解析的地址将类似于 dns:///my-domain:50051,之所以使用这种格式是因为Dial函数允许我们使用由Scheme://Authority/Endpoint组成的目标,而在我们的情况下,我跳过了Authority。因此,首先我添加了dns作为方案,因为我希望解析一个域并持续观察其更改,解析器选项有透传(默认)、dns和手动,更多详情请参阅这里。
  • 负载均衡器选项: 如果我们的客户端现在连接到多个服务器,那么我们的gRPC客户端可以根据所选择的负载均衡算法平衡请求。

总结一下,我们的gRPC客户端现在能够创建不同的连接,前提是域名解析为多个A或AAAA记录,而且不仅如此,现在还能够将请求均匀地分配到不同的服务器。

现在让我们看看如何让它与Kubernetes一起工作的缺失部分。

错误的Kubernetes服务配置

在Kubernetes中创建服务非常简单,我们只需要定义服务名称、端口和选择器,以便服务可以动态地将Pod分组并自动平衡请求,如下所示:

apiVersion: v1
kind: Service
metadata:name: my-service
spec:selector:app: my-appports:- name: grpcprotocol: TCPport: 50051targetPort: 50051

那么,对于先前的设置,问题在于默认的Kubernetes服务只创建了一个DNS记录,链接到单个IP。因此,当您执行类似 nslookup my-service.{namespace}.svc.cluster.local 的操作时,返回的是一个单个IP,这使得在常见的gRPC实现中连接图看起来像这样:

img

例如,使用默认的Kubernetes服务的连接图:

绿线表示与客户端的活动连接,黄色表示未活动的Pod。客户端与Kubernetes服务创建了持久连接,同时服务也与其中一个Pod创建了连接,但这并不意味着服务与其余的Pod没有连接。

让我们使用一个无头服务来解决这个问题:

apiVersion: v1
kind: Service
metadata:name: my-service
spec:clusterIP: None **this is the key***selector:app: my-appports:- name: grpcprotocol: TCPport: 50051targetPort: 50051

创建了无头服务后,nslookup看起来有些不同,现在它返回与之关联的记录(将Pod的IP分组到服务中),从而使gRPC客户端更好地了解需要连接的服务器数量。

现在您已经看到了gRPC客户端的配置,您必须知道为什么Kubernetes服务返回与一组Pod关联的IP非常重要。原因是客户端可以看到所有需要建立连接的服务器。在这一点上,您可能已经意识到了一个注意事项,即平衡的责任现在在客户端部分,而不在Kubernetes的一侧。我们现在需要从Kubernetes那里得到的主要任务是保持与服务关联的Pod列表的最新状态。

img

例如,在具有无头Kubernetes服务的连接图中,可以看到连接发生了一些变化,现在我们不通过Kubernetes服务来访问Pod,而是使用Kubernetes服务来检索与域名关联的Pod列表,然后直接与Pod建立连接。但是不要因为直接连接到Pod而感到惊慌,因为我们在客户端中设置了DNS解析器类型,该解析器将持续监视与无头服务的更改,并将与可用的Pod保持最新的连接。

为什么不使用服务网格?

如果可以的话,请使用服务网格,因为在服务网格中,所有这些设置都是透明的,而且最重要的是它是与编程语言无关的。关键区别在于服务网格利用了Sidecar模式和控制平面来编排入站和出站流量,还可以看到所有网络和流量类型(HTTP、TCP等),从而能够正确平衡请求。简而言之,如果您不使用服务网格,那么您需要直接从每个客户端连接到多个服务器,或者连接到一个L7代理来帮助平衡请求。

附加信息

尽管先前的设置可以工作,但我在尝试在alpine Linux映像中进行Pod轮换或扩展时重新平衡连接时遇到了问题。经过一些研究,我意识到我并不是唯一遇到这种问题的人,可以查看这里和这里的一些相关的GitHub问题。这就是为什么我决定创建自己的解析器的原因,您可以在这里查看我创建的自定义解析器,我创建的自定义解析器非常基础,但现在可以正常工作,gRPC客户端现在可以再次监听域名的更改,我还为该库添加了一个可配置的监听器,它每隔一段时间查找域名并更新提供给gRPC连接管理器的IP集合,如果您想贡献,欢迎加入。

另一方面,因为我想深入了解,所以我决定创建自己的gRPC代理(我也学到了很多东西),利用了gRPC的http2基础,我可以创建一个代理,而无需更改proto负载消息或甚至不知道proto文件的定义(还使用了前面提到的自定义解析器)。

最后,我想说的是,如果您的gRPC客户端需要与许多服务器连接,我强烈建议使用代理作为平衡的机制,因为将这个机制放在主应用程序中将增加复杂性和资源消耗,尝试保持许多打开的连接并重新平衡它们,想象一下,如果最终的平衡在应用程序中,您将有一个与N个服务器连接的实例(1-N),但是使用代理,您将有一个与M个代理连接到N个服务器的实例(1-M-N),其中M<N,因为每个代理实例可以处理与不同服务器的许多连接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/153437.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

苹果遭遇安全危机,应用商店曝出不良APP,或影响iPhone的销售

据澎湃新闻报道指苹果的App Store被曝出不良APP位居下载榜前列&#xff0c;这对于向来强调APP严格审核的苹果来说是巨大的打击&#xff0c;更影响向来被认为信息安全遥遥领先的名声&#xff0c;对当下正热销的iPhone15或造成打击。 据了解被曝的软件以“学习XX字母”为命名&…

2020架构真题(四十六)

、以下关于操作系统微内核架构特征的说法&#xff0c;不正确的是&#xff08;&#xff09;。 微内核的系统结构清晰&#xff0c;利于协作开发微内核代码量少&#xff0c;系统具有良好的可移植性微内核有良好的的伸缩性和扩展性微内核功能代码可以互相调用&#xff0c;性能很高…

Unity官方文档中关于内存管理的翻译(2021.3)

原文:Memory in Unity - Unity 手册 Unity内存管理 为了确保您的应用程序运行时没有性能问题&#xff0c;了解Unity如何使用和分配内存非常重要。本文档的这一部分解释了Unity中内存是如何工作的&#xff0c;适用于希望了解如何提高应用程序内存性能的读者。 Unity使用三个内…

第二证券:汽车产业链股活跃,恒勃股份、博俊科技“20cm”涨停

轿车产业链股9日盘中走势活跃&#xff0c;截至发稿&#xff0c;恒勃股份、博俊科技“20cm”涨停&#xff0c;德迈仕涨超17%&#xff0c;上声电子涨超14%&#xff0c;川环科技涨超10%&#xff0c;圣龙股份、科华控股、沪光股份、上海沿浦、日盈电子、赛力斯等均涨停。 工作方面…

扬尘监测:智能化解决方案让生活更美好

随着工业化和城市化的快速发展&#xff0c;扬尘污染问题越来越受到人们的关注。扬尘不仅影响城市环境&#xff0c;还会对人们的健康造成威胁。为了解决这一问题&#xff0c;扬尘监测成为了一个重要的手段。本文将介绍扬尘监测的现状、重要性以及智能化解决方案&#xff0c;帮助…

基于goravel的CMS,企业官网通用golang后台管理系统

2023年9月11日10:47:00 仓库地址&#xff1a; https://gitee.com/open-php/zx-goravel-website 框架介绍 Goravel SCUI 后端开发组件 go 1.20 Goravel 1.13 数据库 sql(使用最新日期文件) goravel\doc\sql_bak mysql 8.0 前端开发组件 scui 1.6.9 node v14.21.3 效果图…

QT:SQLITE数据库编程

pro文件&#xff1a;QT core gui sql widget.ui main.cpp #include "widget.h" #include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w("./student.db"); //传入文件名w.show();return a.exec…

微信小程序通过createSelectorQuery获取元素 高度,宽度与界面距离

小程序官方有提供给我们一个 const query wx.createSelectorQuery() 函数 我们可以先编写这样一段代码 wxml <view><button bindtap"getDom">点击查看</button><view class "textIn" style "height: 100px;width: 30px;&quo…

基于KubeAdm搭建多节点K8S集群

基于KubeAdm搭建多节点K8S集群 1、基本流程&#xff08;注意 docker 版本和kubeadm、kubelet、kubectl的关系&#xff09;2、安装utils依赖&#xff08;安装范围&#xff1a;主节点工作节点&#xff09;3、安装docker &#xff08;安装范围&#xff1a;主节点工作节点&#xff…

数据输出流和数据输入流

数据输出流 package dataOutputSmTest;import java.io.DataOutputStream; import java.io.FileOutputStream; import java.io.OutputStream;public class dataOS {//掌握数据输出流public static void main(String[] args) {//创建一个数据输出流 包装低级的字节输出流try(Dat…

接口自动化测试yaml+requests+allure技术,你学会了吗?

前言 接口自动化测试是在软件开发过程中常用的一种测试方式&#xff0c;通过对接口进行自动化测试&#xff0c;可以提高测试效率、降低测试成本。在接口自动化测试中&#xff0c;yaml、requests和allure三种技术经常被使用。 一、什么是接口自动化测试 接口自动化测试是指通…

【C++】哈希的应用 —— 布隆过滤器

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C学习 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【C】STL…

基于微信小程序的个人健康数据管理平台设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

微服务技术栈-Docker应用部署

文章目录 前言一、数据卷二、Docker 应用部署1、MySQL部署2、Tomcat部署3、Nginx部署4、Redis部署5、Kafka部署 总结 前言 之前文章讲到过&#xff0c;docker运行程序的过程就是去仓库把镜像拉到本地&#xff0c;然后用一条命令把镜像运行起来变成容器&#xff0c;接下来我们将…

【数据库问题】删除数据库失败,提示:there is 1 other session using the database

删除数据库失败&#xff0c;提示&#xff1a;there is 1 other session using the database 解决办法&#xff1a; SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE datnametest_database AND pid<>pg_backend_pid(); 使用上述命令先关…

HTML5+CSS3+JS小实例:仿优酷视频轮播图

实例:仿优酷视频轮播图 技术栈:HTML+CSS+JS 效果: 源码: 【html】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" content=&quo…

自然语言处理 | WordNet

WordNet是词汇数据库,即英语词典,专为自然语言处理而设计。 Synset是一种特殊的简单接口,存在于 NLTK 中, 用于在 WordNet 中查找单词。同义词集实例是表达相同概念的同义词的分组。有些单词只有一个同义词集,有些则有多个。

三点式振荡器

相关说明 http://www.360doc.com/content/19/0527/16/61619294_838545271.shtml 高频信号发生器设计—电容三点式振荡电路_电容三点式振荡电路工作原理_北辰-尘的博客-CSDN博客 如上图所示&#xff0c;典型的Colpitts振荡电路。首先忽略所有的电阻&#xff0c;他们是用来设置…

Linux通过QQ邮箱账号使用mailx发送邮件

Linux通过QQ邮箱账号使用mailx发送邮件 第一步&#xff1a;安装mailx 第二步&#xff1a;获取邮箱的授权码 第三步&#xff1a;配置mailx服务 第四步&#xff1a;添加数字证书 第五步&#xff1a;发送邮件测试&#xff01; 第一步&#xff1a;安装mailx # 安装mailx yum…

Android多线程学习:线程池(二)

一、线程池运行流程 具体执行流程如下&#xff1a; 1、首先检测线程池运行状态&#xff0c;如果不是RUNNING&#xff0c;则直接拒绝&#xff0c;线程池要保证在RUNNING的状态下执行任务&#xff1b; 2、如果workerCount < corePoolSize&#xff0c;则创建并启动一个线程来…