39

在 Kubernetes 集群中 gRPC 的负载均衡

 3 years ago
source link: https://mp.weixin.qq.com/s/R9D1a3a7g3HjN8r2EnO-ow
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

很多人觉得,在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 #只用于到达服务

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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK