grpc在k8s中的负载均衡问题

标签: 分布式 Distributed gRPC Kubernetes | 发表时间:2021-10-11 13:25 | 作者:
出处:https://blog.hufeifei.cn/

skywalking

两台skywalking-oap接受并分析由agent采集的trace数据,但是问题是两台oap服务负载不均衡。

grpc-in-k8s

#k8s的service四层负载均衡

为了排除k8s的service负载均衡的问题,在线下环境还原了请求的过程。

skywalking提供了grpc(11800端口)和rest(12800端口)两种协议的服务。

从下图可以看到,skywalking提供了11800和12800的监听端口,以及连接ElasticSearch的9200端口

skywalking

第一次请求连上了skywalking-oap1

第二次请求连上了skywalking-oap2

多次请求负载均衡是没有问题的。但是请求会断开连接,实际上是两次 连接连向了两台不同的server。这个概念很重要,请求和连接不是一个事物,多个请求可以复用一个连接。

#grpc长连接导致负载不均衡

观察线上的两台oap发现,两台server都维持了大量的长连接,其中负载高的一台明显连接数更多。

由于线上skywalking-agent和skywalking-oap使用的是grpc进行通信的,grpc基于http/2会维持一个长连接。k8s的service无法识别应用层的负载均衡。

#对比常见的负载均衡实现

dubbo与SpringCloudRibbon的客户端负载均衡

Dubbo因为有自己的注册中心可以直接获取服务ip,负载均衡直接由Dubbo客户端实现,两次调用会路由到不同的service,即使client持有多个service实例的连接,客户端也能根据连接个数进行负载均衡。这本质上和SpringCloud中的Ribbon原理一样。这种情况直接就不需要k8s的service来实现负载均衡。

Dubbo Architecture

基于反向代理的负载均衡

Nginx,Apache,HAProxy等反向代理服务器都支持负载均衡的功能。

像Nginx是能识别HTTP消息的,即使是维持了长连接,也能截取出完整的http消息,从而实现应用层的负载均衡。

Nginx在1.9.0添加了 ngx_stream_proxy_module模块支持TCP/UDP的反向代理,但是它只能处理TCP连接,但是处理不了应用层的请求负载均衡。

比如 使用nginx为mysql建立高可用的反向代理,它解析不了同一个mysql连接中的两条sql请求。比如想进行读写分离,nginx就实现不了,这些大多是在应用端实现的,或者使用专业的反向代理,比如 ProxySQL

k8s的service就有点类似于nginx的tcp反向代理。当然只是说很像,实际上区别还是很大的。

下面看一下k8s的service实现原理。

#k8s的service实现原理

k8s的service是基于虚拟ip实现的:使用iptables实现路由转发。k8s的service代理有三种运行模式:

#1、userspace代理模式

这种模式,kube-proxy 会监控 Kubernetes control plane 对 Service 对象和 Endpoints 对象的添加和移除操作。 对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。 任何连接到“代理端口”的请求,都会被代理到 Service 后端的某个Pod上(如 Endpoints 所报告的一样)。 使用哪个后端 Pod,是 kube-proxy 基于 SessionAffinity 来确定的。

最后,它配置 iptables 规则,将到达该 Service 的 clusterIP(是虚拟 IP) 和 Port 的请求重定向到代理的后端Pod的端口。

默认情况下,用户空间模式下的 kube-proxy 通过 轮询算法选择后端服务。

Services overview diagram for userspace proxy

#2、iptables 代理模式

这种模式, kube-proxy 会监控 Kubernetes control plane 对 Service 对象和 Endpoints 对象的添加和移除。对每个 Service,它会配置 iptables 规则,从而捕获到达该 Service 的 clusterIP 和端口的请求,进而将请求重定向到 Service 的后端中的某个 Pod 上面。 对于每个 Endpoints 对象,它也会配置 iptables 规则,这个规则会选择一个后端Pod。

默认情况下,kube-proxy 在 iptables 模式下 随机选择一个后端。

使用 iptables 处理流量具有较低的系统开销,因为流量由 Linux netfilter 处理, 而无需在用户空间和内核空间之间切换。 这种方法也可能更可靠。

如果 kube-proxy 在 iptables 模式下运行,并且所选的第一个 Pod 没有响应, 则连接失败。 这与用户空间模式不同:在这种情况下,kube-proxy 将检测到与第一个 Pod 的连接已失败, 并会自动使用其他后端 Pod 重试。

你可以使用 Pod 就绪探针 验证后端 Pod 可以正常工作,以便 iptables 模式下的 kube-proxy 仅看到测试正常的Pod。 这样做意味着你避免将流量通过 kube-proxy 发送到已知已失败的 Pod。

iptables代理模式下Service概览图

#3、IPVS模式

ipvs 模式下,kube-proxy 监控 Kubernetes Services和Endpoints,调用 netlink 接口相应地创建 IPVS 规则, 并定期将 IPVS 规则与 Kubernetes 服务和端点同步。 该控制循环可确保IPVS 状态与所需状态匹配。访问Service时,IPVS 将流量定向到后端Pod之一。

IPVS代理模式基于类似于 iptables 模式的 netfilter hook函数, 但是使用哈希表作为基础数据结构,并且在内核空间中工作。 这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。 与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。

IPVS 提供了更多选项来平衡后端 Pod 的流量。 这些是:

  • rr:轮替(Round-Robin)
  • lc:最少链接(Least Connection),即打开链接数量最少者优先
  • dh:目标地址哈希(Destination Hashing)
  • sh:源地址哈希(Source Hashing)
  • sed:最短预期延迟(Shortest Expected Delay)
  • nq:从不排队(Never Queue)

说明:

要在 IPVS 模式下运行 kube-proxy,必须在启动 kube-proxy 之前使 IPVS 在节点上可用。

当 kube-proxy 以 IPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。 如果未检测到 IPVS 内核模块,则 kube-proxy 将退回到以 iptables 代理模式运行。

IPVS代理的 Services 概述图

在这些代理模型中,绑定到服务 IP 的流量: 在客户端不了解 Kubernetes 或服务或 Pod 的任何信息的情况下,将 Port 代理到适当的后端。

如果要确保每次都将来自特定客户端的连接传递到同一 Pod, 则可以通过将 service.spec.sessionAffinity 设置为 “ClientIP” (默认值是 “None”),来基于客户端的 IP 地址选择会话关联。 你还可以通过适当设置 service.spec.sessionAffinityConfig.clientIP.timeoutSeconds 来设置最大会话停留时间。 (默认值为 10800 秒,即 3 小时)。

#K8s中grpc负载均衡的解决方案

前面已经分析了k8s的service是无法实现应用层的负载均衡的。grpc基于http/2,因为http/2是长连接,负载均衡需要发生在每次调用,而非每次连接。K8s识别不了http/2的请求,就无法实现grpc的负载均衡。

#1、使用Nginx进行反向代理

既然grpc基于http/2,那么可以使用Nginx进行grpc的反向代理,因为 Nginx在1.9.5开始支持Http/2协议。这个方案能完全保证流量的均匀分配。

但是架构上就比较复杂,为了防止skywalking-oap的pod重启,ip改变后nginx需要重新修改配置。那么需要为每个skywalking-oap创建一个Service。另外为了防止Nginx重启后Pod的ip改变,Nginx也需要创建一个Service。

一个简单的方法是使用K8s的Ingress代替Nginx, Ingress本身也有nginx的实现

#2、修改K8s的service运行模式

我们退而求其次,无法实现每次grpc调用的负载均衡,保证连接数的均衡,也算进一大步了。

前面分析K8s的Service运行原理的时候,Service有三种运行模式:

  • userspace代理模式:过 轮询算法选择后端服务
  • iptables代理模式: 随机选择后端服务
  • IPVS模式:支持多种模式
    • rr:轮替(Round-Robin)
    • lc:最少链接(Least Connection),即打开链接数量最少者优先
    • dh:目标地址哈希(Destination Hashing)
    • sh:源地址哈希(Source Hashing)
    • sed:最短预期延迟(Shortest Expected Delay)
    • nq:从不排队(Never Queue)

使用轮询和随机的方式创建连接,问题是连接断了后重连,会出现连接不均衡的问题。

那么可以使用IPVS的 lc模式,让连接优先分配给打开链接数少的server。这样能保证连接数的均衡。

#3、为grpc添加LoaderBalancer组件

原生grpc就没有服务发现这个概念,而是使用 另外的LoaderBalancer组件实现负载均衡。

这种方式类似于Dubbo的方案,让客户端实现负载均衡。但是实现起来就比较复杂了,除了要多部署一个LoadBalancer,还需要在skywalking-agent中配置grpc负载均衡的策略。skywalking-oap注册到LoadBalancer中也是一个大问题。

相关 [grpc k8s 负载均衡] 推荐:

grpc在k8s中的负载均衡问题

- - holmofy
两台skywalking-oap接受并分析由agent采集的trace数据,但是问题是两台oap服务负载不均衡. #k8s的service四层负载均衡. 为了排除k8s的service负载均衡的问题,在线下环境还原了请求的过程. skywalking提供了grpc(11800端口)和rest(12800端口)两种协议的服务.

Nginx gRPC Streaming 负载均衡的排坑和思考

- - IT瘾-dev
我们知道nginx在1.13版本之后就可以支持grpc的负载均衡了. 官方给出的使用也很简单,类似proxy_pass的语法. 但在使用的过程中遇到短连接的问题. 该文章后续仍在不断的更新修改中, 请移步到原文地址 http://xiaorui.cc/?p=5970. 大量的timewait短连接:.

基于 gRPC 的注册发现与负载均衡的原理和实战

- - V2EX - 技术
gRPC是一个现代的、高性能、开源的和语言无关的通用 RPC 框架,基于 HTTP2 协议设计,序列化使用 PB(Protocol Buffer),PB 是一种语言无关的高性能序列化框架,基于 HTTP2+PB 保证了的高性能. go-zero是一个开源的微服务框架,支持 http 和 rpc 协议,其中 rpc 底层依赖 gRPC,本文会结合 gRPC 和 go-zero 源码从实战的角度和大家一起分析下服务注册与发现和负载均衡的实现原理.

浅谈 gRPC

- - SegmentFault 最新的文章
原文地址: 浅谈 gRPC. gRPC 在 Go 语言中大放异彩,越来越多的小伙伴在使用,最近也在公司安利了一波,希望能通过这篇文章能带你一览 gRPC 的爱与恨. 本文篇幅较长,希望你做好阅读准备,目录如下:. gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计.

nginx负载均衡配置

- - 开心平淡对待每一天。热爱生活
  使用负载均衡的话,可以修改配置http节点如下:. #设定http服务器,利用它的反向代理功能提供负载均衡支持. #设定mime类型,类型由mime.type文件定义. #省略上文有的一些配置节点. #设定负载均衡的服务器列表. #weigth参数表示权值,权值越高被分配到的几率越大. server 192.168.8.1x:3128 weight=5;#本机上的Squid开启3128端口.

解析nginx负载均衡

- - 搜索研发部官方博客
摘要:对于一个大型网站来说,负载均衡是永恒的话题. 随着硬件技术的迅猛发展,越来越多的负载均衡硬件设备涌现出来,如F5 BIG-IP、Citrix NetScaler、Radware等等,虽然可以解决问题,但其高昂的价格却往往令人望而却步,因此负载均衡软件仍然是大部分公司的不二之选. nginx作为webserver的后起之秀,其优秀的反向代理功能和灵活的负载均衡策略受到了业界广泛的关注.

Haproxy+KeepAlived 负载均衡

- - CSDN博客系统运维推荐文章
软件负载均衡一般通过两种方式来实现:基于操作系统的软负载实现和基于第三方应用的软负载实现. LVS就是基于Linux操作系统实现的一种软负载,HAProxy就是开源的并且基于第三应用实现的软负载. 还可以使用nginx来实现,不过nginx只工作在7层网络之上. 详细请参考 抚琴煮酒写的“ 软件级负载均衡器(LVS/HAProxy/Nginx)的特点简介和对比”这篇文章,简单很详细,很好.

lvs+keepalived 负载均衡

- - CSDN博客系统运维推荐文章
LVS是一个开源的软件,可以实现LINUX平台下的简单负载均衡. LVS是Linux Virtual Server的缩写,意思是Linux虚拟服务器. 目前有三种IP负 载均衡技术(VS/NAT、VS/TUN和VS/DR);八种调度算法(rr,wrr,lc,wlc,lblc,lblcr,dh,sh).

负载均衡技术

- - ITeye博客
 Internet的规模每一百天就会增长一倍,客户希望获得7天24小时的不间断可用性及较快的系统反应时间,而不愿屡次看到某个站点"Server Too Busy"及频繁的系统故障.   网络的各个核心部分随着业务量的提高、访问量和数据流量的快速增长,其处理能力和计算强度也相应增大,使得单一设备 根本无法承担.

haproxy负载均衡 xtracluster

- - x-marker的博客
上一篇为xtracluster的安装(http://xmarker.blog.163.com/blog/static/226484057201472610520306/),本篇将记录下使用haproxy在三个数据节点做负载均衡,haproxy可以安装在数据节点,也可以安装在别的节点,如果安装在数据节点,需要注意端口号不能和mysql的3306冲突.