【问题标题】:Only 1 pod handles all requests in Kubernetes cluster只有 1 个 pod 处理 Kubernetes 集群中的所有请求
【发布时间】:2020-02-23 02:52:56
【问题描述】:

这是 minikube Kubernetes 的清单文件,用于部署和服务:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-deployment
spec:
  selector:
    matchLabels:
      app: hello
  replicas: 3
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: hello_hello
        imagePullPolicy: Never
        ports:
        - containerPort: 4001
          protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: hello
spec:
  selector:
    app: hello
  ports:
  - port: 4001
    nodePort: 30036
    protocol: TCP
  type: NodePort

还有一个用 Golang 编写的简单 HTTP 服务器

package main
import (
    http "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })

    server := &http.Server{
        Addr:    ":4001",
        Handler: r,
    }

    server.ListenAndServe()
}

当我向 IP:30036/ping 发出多个请求然后打开 pod 的日志时,我可以看到 3 个 pod 中只有 1 个处理所有请求。如何让其他 Pod 响应请求?

【问题讨论】:

  • 你是如何提出请求的?
  • @Thomas 我打开 Postman,输入带有端口 30036 的 IP 地址和路径 /ping。之后,我多次单击“发送”按钮并收到回复。然后我打开 pod 日志,看到所有请求都发送到 3 个 pod 中的 1 个。

标签: go kubernetes load-balancing


【解决方案1】:

您正在使用 NodePort 公开服务,因此没有反向代理,但您直接连接到您的 Pod。这是一个不错的选择。 (稍后您可能想要使用 Ingress)

您看到的是只有一个 Pod 处理您的请求。您希望每个请求都负载平衡到不同的 pod。而且你的假设是正确的,但是负载均衡不是发生在 HTTP 请求层,而是发生在 TCP 层。

因此,当您拥有持久的 TCP 连接并重新使用它时,您将不会体验到您期望的负载平衡。由于建立 TCP 连接的延迟非常昂贵,因此通常会进行优化以避免重复打开新的 TCP 连接:HTTP keep-alive。

在大多数框架和客户端中默认启用 Keep alive,Go 也是如此。 试试s.SetKeepAlivesEnabled(false) 看看是否能解决您的问题。 (仅推荐用于测试!)

您还可以使用多个不同的客户端,例如从命令行使用 curl 或在 Postman 中禁用 keep-alive。

【讨论】:

    【解决方案2】:

    在 Kubernetes 集群中,发送到 k8s 服务的请求通过kube-proxy 路由。

    自 Kubernetes v1.2 起,默认的 kube-proxy 模式为 Iptalbles,它允许在服务和后端 Pod 之间更快地解析数据包。后端 Pod 之间的负载均衡直接通过 iptables rules 完成。

    也许你没有产生足够的负载,一个 pod 无法处理,这就是为什么你从kube-proxy 被路由到同一个 pod。

    你也可以看到实现自定义iptalbes-rule这个问题的答案:

    【讨论】:

      【解决方案3】:

      感谢@Thomas 的深刻见解!我尝试使用请求标头,它解决了所有请求仅命中单个副本的负载平衡问题,而对于演示或测试,能够将请求分发到所有副本很有用

      来自文档:

      https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection 连接:保持活动 连接:关闭

      这个请求总是命中同一个 pod

      curl -H "Connection: keep-alive" http://your-service:port/path
      

      但是,使用 close,请求平衡到所有 pod

      curl -H "Connection: close" http://your-service:port/path
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-07-22
        • 1970-01-01
        • 2020-09-14
        • 2023-01-09
        • 1970-01-01
        • 2020-03-26
        • 2018-09-11
        相关资源
        最近更新 更多