写点什么

基于 Kubernets 简单实现 gRPC 负载均衡

  • 2018-12-10
  • 本文字数:2356 字

    阅读完需:约 8 分钟

基于Kubernets简单实现gRPC负载均衡

很多刚刚接触 gRPC 的用户,通常会惊讶于 Kubernetes 默认提供的负载均衡对于 gRPC 来说无法实现开箱即用的效果。比如,将一个简单的基于 Node.js 实现的 gRPC 微服务部署在 Kubernetes 后,如下图所示:



尽管选举服务显示存在多个 pod,但是从 Kubernetes 的 CPU 图表可以清晰的看出,只有一个 pod 能够接收到流量,处于工作状态。这是为什么?


在本文中,会解释该现象对应的原因,以及如何在任意 Kubernetes 应用上修复 gRPC 负载均衡存在的问题。这需要增加名为 Linkerd 的服务网格(service mesh),同时也是一种服务 sidecar。

为什么 gRPC 需要额外的负载均衡设置?

首先需要一起来了解下,为什么 gRPC 需要额外的设置。


gRPC 正逐渐成为应用开发者的常见选择。相比于其他服务协议,如基于 HTTP 的 JSON,gRPC 能够提供更好的特性,包括更低的(反)序列化开销、自动类型检查、格式化 API,以及更小的 TCP 管理开销。


但是,gRPC 也打破了标准的连接层负载均衡约定,也就是 Kubernetes 中默认提供的负载均衡方式。这是因为 gRPC 是基于 HTTP/2 构建,而 HTTP/2 是面向单个 TCP 长连接进行设计的,全部的请求都会复用这一个 TCP 连接。通常情况下,这种方式很棒,因为这样可以减少连接管理的开销。但是,这也意味着(读者也可以想象到)连接层的负载均衡会失效。一旦连接创建之后,就不会再次触发负载均衡。指向某个 pod 的全部请求会封装在相同的连接之中,如下图所示:


为什么 HTTP/1.1 不受影响?

在 HTTP/1.1 中也存在相同的长连接概念,但却不存在类似问题。这是因为 HTTP/1.1 某些特性会使得 TCP 连接被回收。正因如此,连接层负载均衡对于 HTTP/1.1 来说就够用了,无需其他特殊配置。


为了理解其中原理,需要深入了解一下 HTTP/1.1。与 HTTP/2 不同,HTTP/1.1 不支持请求复用。每个 TCP 连接在同一时间只能处理一个 HTTP 请求。假设客户端发起请求 GET /foo,需要一直等待直到服务端返回。在一个请求–应答周期内,该连接不能处理其他请求。


通常情况下人们都希望多个请求能够并发处理。因此为了实现 HTTP/1.1 下的并发请求,需要创建多个 HTTP/1.1 连接,基于这些连接来发送全部请求。此外,HTTP/1.1 中的长连接在一段时间后是会过期的,过期连接会被客户端(或者服务端)销毁。在这两点共同作用下,HTTP/1.1 请求会在多个 TCP 连接之间进行循环,所以连接层的负载均衡才会生效。

gRPC 如何实现负载均衡?

回过头来看一下 gRPC。因为不能在连接层实现负载均衡,所以需要在应用层来完成。换句话说,需要为每个目标地址创建一个 HTTP/2 连接,对请求实现负载均衡,如下所示:



在网络模型中,这意味着需要实现 L5/L7 层的负载均衡,而不是 L3/L4。这样就需要感知 TCP 连接上传输的协议格式。


如何实现?有这么几种选择。第一种,可以在应用之中手工创建并维护目标地址的连接池,通过配置 gRPC 客户端使用该连接池来实现。这种方式控制起来最灵活,但是在 Kubernetes 这种环境中实现起来非常复杂,因为 Kubernetes 每次进行 pod 层面的调度,连接池都需要进行相应变更。应用需要监控 Kubernetes 的 API,并与 pod 信息保持实时同步。


在 Kubernetes 中,还有另外一种方式,是将服务按照无状态方式进行部署。在该情况下,Kubernetes 会在 DNS 中为服务创建多条记录。如果所使用的 gRPC 客户端足够先进,就能通过上述多个 DNS 记录来实现负载均衡。但是这种实现方式依赖于使用特定的 gRPC 客户端,并且只能使用无状态模式部署服务。


最后,还有第三种方式:使用一个轻量级代理。

在 Kubernetes 上使用 Linkerd 实现 gRPC 负载均衡

Linkerd 是一种基于 CNCF 的 Kubernetes 服务网格。Linkerd 通过 sidecar 的方式来实现负载均衡,可以单独部署到某个服务,甚至不需要集群许可。这意味着为服务添加 Linkerd,等价于为每个 pod 添加了一个很小并且很高效的代理,由这些代理来监控 Kubernetes 的 API,并自动实现 gRPC 的负载均衡。具体部署方式如下:



使用 Linkerd 有如下几个好处。首先,Linkerd 支持任何语言下的 gRPC 客户端,也支持每种部署模式(无状态部署或者有状态部署)。这是因为 Linkerd 代理是在传输层完成,会自动对 HTTP/2 和 HTTP/1.x 进行检测,并实现 L7 层的负载均衡,而对其他的流量不做任何处理。这意味着不会产生额外的影响。


其次,Linkerd 负载均衡是非常复杂的。除了需要监听 Kubernetes API,并且在 pod 发生调度后自动更新负载均衡的连接池之外,Linkerd 还会根据响应的延迟,使用指数级权重对请求进行调整,优先将请求发送到相应延迟低的 pod。如果某个 pod 响应很慢,甚至只是偶然抖动,Linkerd 都会将其上的流量摘掉。这样做可以减少端到端的延迟。


最后,Linkerd 基于 rust 实现的代理体积非常小,并且速度快的难以置信。Linkerd 声称百分之 99 的请求开销小于 1ms,并且对于 pod 上物理内存的占用小于 10mb。这意味着 Linkerd 对于系统性能的影响可以忽略不计。

60s 实现 gRPC 负载均衡

测试 Linkerd 非常简单。只需要按照 Linkerd 入门介绍即可。在笔记本上安装 CLI,在集群上安装控制层,然后对服务“网格化”(将代理注入每个 pod)。Linkerd 立刻就能在服务中生效,并实现合理的 gRPC 路由。


安装 Linkerd 之后,再看下选举服务:



可以看到,CPU 图表中每个 pod 都被激活,表示每个 pod 都开始接受流量。而实现这些无需改动任何一行代码。哈哈,Linkerd 就像有魔力一般,实现了 gRPC 负载均衡。


Linkerd 也提供了内置的流量大盘,所以也无需猜测 CPU 图表中的变化究竟代表着什么。下面就是 Linkerd 的大盘,包括每个 pod 的成功率,请求大小,以及延迟。



可以看到每个 pod 每秒大概处理 5 个请求。同时通过大盘还能发现,服务成功率还存在一些问题需要解决。(在示例应用中,特意构造了一些异常,方便为读者演示可以通过 Linkerd 大盘来观察服务质量!)


2018-12-10 17:264064

评论 1 条评论

发布
暂无评论
发现更多内容

DDos攻击分类

穿过生命散发芬芳

DDoS 7月月更

“你真的入门前端了吗”

bo

前端 7月月更

C#入门系列(三十) -- 异常处理

陈言必行

7月月更

做好项目管理的10个关键点和5大措施

PingCode

Qt | 事件系统 QEvent

YOLO.

qt 7月月更

阿里 Seata 新版本终于解决了 TCC 模式的幂等、悬挂和空回滚问题

阿里巴巴云原生

阿里云 开源 微服务 云原生 seata

Prometheus 运维工具 Promtool (一)Check 功能

耳东@Erdong

Prometheus 7月月更 Promtool

LeetCode-69. x的平方根(java)

bug菌

Leet Code 7月月更

Qt|QLable多行展示时更改行间距

中国好公民st

qt 7月月更

一张图进阶 RocketMQ - 通信机制

三此君

RocketMQ Netty MQ 消息队列 异步通信

你还不会Vue3吗

bo

前端 Vue 3 7月月更

UART

贾献华

7月月更

【数据库学习】Redis 解析器&&单线程&&模型

恒山其若陋兮

7月月更

Apipost签约中国电信!携手加速企业数字化变革

Xd

《ArchSummit:从珍爱微服务框架看架构演进》

后台技术汇

架构 后台开发 架构师 后台 ArchSummit

一张图进阶 RocketMQ - 整体架构

三此君

kafka RocketMQ MQ 消息队列 消息中间件

一张图进阶 RocketMQ - NameServer

三此君

kafka RocketMQ MQ 消息队列 分布式消息中间件

java零基础入门-异常、线程(中)

喵手

Java 7月月更

高阶产品如何提出有效解决方案?(1方法论+2案例+1清单)

张姣发

产品经理

QDir类的使用 以及部分解释

小肉球

qt 7月月更

把字符串转换成整数与不要二

未见花闻

7月月更

RocketMQ 消息集成:多类型业务消息-普通消息

阿里巴巴云原生

阿里云 RocketMQ 云原生 消息队列

idea / eclipse 配置 Tomcat 并发布 Web 项目

攻城狮杰森

eclipse tomcat IDEA javaWeb 7月月更

如何创建和管理自定义的配置信息

Damon

7月月更

给生活加点惊喜,做创意生活的原型设计师丨编程挑战赛 x 选手分享

声网

人工智能’

一张图进阶 RocketMQ - 消息发送

三此君

kafka RocketMQ MQ 消息队列 消息发送

iOS中对象等同性isEqual:和hash

NewBoy

ios 前端 移动端 iOS 知识体系 7月月更

数据中台建设(一):数据中台出现的背景

Lansonli

数据中台 7月月更

JDBC 驱动升级到 Version 8.0.28 连接 MySQL 的踩坑记录

攻城狮杰森

MySQL JDBC database 7月月更

一张图进阶 RocketMQ - 消息存储

三此君

RocketMQ MQ 消息队列 broker commitlog

云计算三类巨头:IaaS、PaaS、SaaS,分别是什么意思,应用场景是什么?

wljslmz

云计算 IaaS PaaS SaaS 7月月更

基于Kubernets简单实现gRPC负载均衡_云原生_William Morgan_InfoQ精选文章