本文转载自微信公众号《浅谈架构技术》,作者LA0WAN9。转载本文请联系建筑技术谈公众号。一般来说,在K8S下部署服务是很简单的,但是如果是部署gRPC服务,一不小心就可能掉坑里。让我告诉你原因。在K8S下部署服务时,默认会分配一个地址(即ClusterIP[1]),客户端的请求会发给它,然后通过负载均衡转发给一个后端的pod:如果ClusterIP是HTTP/1.1如果是gRPC服务,那么ClusterIP会造成负载不均衡。原因是gRPC基于HTTP/2,多个请求在一个TCP连接上进行多路复用。一旦ClusterIP与一个pod建立了gRPC连接,由于多路复用,后续其他的请求也会被转发到这个pod上,导致其他pod完全被忽略。看到这里,可能有读者会有疑问:HTTP/1.1不是基于KeepAlive来实现连接复用的吗?为什么HTTP/1.1多路复用没有问题,而HTTP/2多路复用有问题?答案是HTTP/1.1的多路复用是串行的。当请求到达时,如果没有空闲连接,就会创建一个新的连接。如果有一个空闲连接,那么它可以被多路复用。同一时间点,连接最多只能携带一个Request,结果是HTTP/1.1可以连接多个pod;而HTTP/2多路复用是并行的,当请求到来时,如果没有连接,则创建一个连接,如果有连接,那么无论空闲与否,都可以重复使用,在同一个点中一次,连接可以携带多个请求,结果是HTTP/2只连接到一个pod。了解了K8S下gRPC负载均衡问题的来龙去脉,我们不难想出一个解决方案:在Proxy中实现负载均衡:使用Envoy作为代理,与各个后端服务器保持长连接.当客户端请求到达时,代理服务器按照规则将请求转发给后端服务器,实现负载均衡。Proxy在Client实现负载均衡:将服务部署为headlessservice[2],让服务有域名,然后client通过域名访问gRPC服务,DNS解析器会查询到gRPC服务的地址多台后端服务器通过DNS,再通过算法实现负载均衡。两种客户端方案优缺点很明显:Proxy方案结构清晰,客户端不需要了解后端服务器,对架构没有侵入性,但性能会因为存在转发;Client解决方案结构复杂,客户端需要在Endserver之后才能理解,对架构有侵入性,但性能更好。参考资料[1]ClusterIP:https://kubernetes.io/docs/concepts/services-networking/service/[2]headlessservice:https://kubernetes.io/docs/concepts/services-networking/serv
