Grpc在kubernetes集群中的负载均衡


很多人觉得,在Kubernetes中不是只要用 Service就可以做负载均衡了吗?SVC确实有负载均衡的作用。它是由Kube-proxy提供,但是由于Grpc的特性没有办法让它很好的处理负载均衡。

SVC负载调度原理

在k8s的文档中阐述了kube-proxy的特点:

The kube proxy:

runs on each node  #运行在每个节点
proxies UDP, TCP and SCTP #可以代理UDP、TCP、SCTP协议
does not understand HTTP  #但是不能识别HTTP协议
provides load balancing  #提供负载均衡
is just used to reach services #只用于到达服务

其中阐述了kube-proxy的iptbles代理,是不能支持应用层协议识别的。所以存在一个消费者与生产者之间过载复用一条tcp链接的情况,导致后端pod副本的应用载荷不一致。

下面是查看svc的负载均衡实现

service 的集群ip实现负载均衡

创建service后,kubernetes会在kube-proxy里面设置iptables相应规则,从api-server获取到后端pod的ip以及端口情况。生产相应转发规则

当目标地址为service的地址10.97.211.12/32和目标端口为8000时,跳转到KUBE-SVC-EHPSUHUW2JIVMPQD链

-A KUBE-SERVICES -d 10.97.211.12/32 -p tcp -m comment 
--comment "default/backend:grpc cluster IP" -m tcp --dport 8000 \
-j KUBE-SVC-EHPSUHUW2JIVMPQD

链KUBE-SVC-EHPSUHUW2JIVMPQD为3条规则,副本数是3

30.333%的几率去KUBE-SEP-MPFDKKCFY2PBGU4S链(pod1 的ip)
-A KUBE-SVC-EHPSUHUW2JIVMPQD -m statistic --mode random --probability 0.33332999982 \
-j KUBE-SEP-MPFDKKCFY2PBGU4S
50%的几率去KUBE-SEP-LMG22MVGXQA364F6链(pod2的ip地址)
-A KUBE-SVC-EHPSUHUW2JIVMPQD -m statistic --mode random --probability 0.50000000000 \
-j KUBE-SEP-LMG22MVGXQA364F6
其余的全部走KUBE-SEP-EX64MF3TTLO7J5EC链(pod3的ip地址)
-A KUBE-SVC-EHPSUHUW2JIVMPQD -j KUBE-SEP-EX64MF3TTLO7J5EC

pod3的ip地址

-A KUBE-SEP-EX64MF3TTLO7J5EC -s 10.80.167.226/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-EX64MF3TTLO7J5EC -p tcp -m tcp -j DNAT --to-destination 10.80.167.226:8000

pod1的ip地址

-A KUBE-SEP-MPFDKKCFY2PBGU4S -s 10.80.128.247/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-MPFDKKCFY2PBGU4S -p tcp -m tcp -j DNAT --to-destination 10.80.128.247:8000

pod2的ip地址

-A KUBE-SEP-LMG22MVGXQA364F6 -s 10.80.153.167/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-LMG22MVGXQA364F6 -p tcp -m tcp -j DNAT --to-destination 10.80.153.167:8000

所以得到:

pod3:10.80.167.226
pod2:10.80.128.247
pod1:10.80.153.167

这些ip和上面的comment信息,均来自apiserver,apiserver最终是在etcd里面存储并及时更新并管理这些对象。

所以在GRPC的技术棧中,生产者和消费者之间的互相调用,并达到真正的负载均衡的目的。使用其他方法进行,这里介绍两种方法。

使用无头服务

Headless Service的负载均衡,是通过内部coredns进行dns解析pod所有地址列表进行的。

kind: Service
apiVersion: v1
metadata:
  name: backendh
spec:
  selector:
    app: backend #对应后端生产者或者消费者
  ports:
  - port: 8000
    protocol: TCP
    targetPort: 8000
  clusterIP: None

在grpc的生产者与者消费者之间的通信,通过在发起方预埋变量名方式获取dns解析后向具体服务进行发起请求。

使用 istio 服务网格

1.在集群中部署好istio基础设施

2.编排VirtualService和DestinationRule CRD

因为是内部互相调用,并不需要Gateway。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: backend
spec:
  hosts:
  - backend
  http:
  - route:
    - destination:
        host: backend
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: backend
spec:
  host: backend
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
istio  Grpc