k8s 最佳實踐:解決長連接服務擴容失效

Kubernetes 最佳實踐:解決長連接服務擴容失效

1.問題背景

在現網運營中,有很多場景爲了提高效率,一般都採用建立長連接的方式來請求。我們發現在客戶端以長連接請求服務端的場景下,K8S的自動擴容會失效。

原因是客戶端長連接一直保留在老的Pod容器中,新擴容的Pod沒有新的連接過來,導致K8S按照步長擴容第一批Pod之後就停止了擴容操作,而且新擴容的Pod沒能承載請求,進而出現服務過載的情況,自動擴容失去了意義

2.解決方案

對長連接擴容失效的問題,我們的解決方法是將長連接轉換爲短連接。我們參考了 nginx keepalive 的設計,nginx 中 keepalive_requests 這個配置項設定了一個TCP連接能處理的最大請求數,達到設定值(比如1000)之後服務端會在 http 的 Header 頭標記 “Connection:close”,通知客戶端處理完當前的請求後關閉連接,新的請求需要重新建立TCP連接,所以這個過程中不會出現請求失敗,同時又達到了將長連接按需轉換爲短連接的目的。通過這個辦法客戶端和雲K8S服務端處理完一批請求後不斷的更新TCP連接,自動擴容的新Pod能接收到新的連接請求,從而解決了自動擴容失效的問題。

由於Golang並沒有提供方法可以獲取到每個連接處理過的請求數,我們重寫了 net.Listenernet.Conn,注入請求計數器,對每個連接處理的請求做計數,並通過 net.Conn.LocalAddr() 獲得計數值,判斷達到閾值 1000 後在返回的 Header 中插入 “Connection:close” 通知客戶端關閉連接,重新建立連接來發起請求。以上處理邏輯用 Golang 實現示例代碼如下:

package main

import (
 "net"
 "github.com/gin-gonic/gin"
 "net/http"
)

//重新定義net.Listener
type counterListener struct {
 net.Listener
}
//重寫net.Listener.Accept(),對接收到的連接注入請求計數器
func (c *counterListener) Accept() (net.Conn, error) {
 conn, err := c.Listener.Accept()
 if err != nil {
  return nil, err
 }
 return &counterConn{Conn: conn}, nil
}
//定義計數器counter和計數方法Increment()
type counter int
func (c *counter) Increment() int {
 *c++
 return int(*c)
}

//重新定義net.Conn,注入計數器ct
type counterConn struct {
 net.Conn
 ct counter
}

//重寫net.Conn.LocalAddr(),返回本地網絡地址的同時返回該連接累計處理過的請求數
func (c *counterConn) LocalAddr() net.Addr {
 return &counterAddr{c.Conn.LocalAddr(), &c.ct}
}

//定義TCP連接計數器,指向連接累計請求的計數器
type counterAddr struct {
 net.Addr
 *counter
}

func main() {
 r := gin.New()
 r.Use(func(c *gin.Context) {
  localAddr := c.Request.Context().Value(http.LocalAddrContextKey)
  if ct, ok := localAddr.(interface{ Increment() int }); ok {
   if ct.Increment() >= 1000 {
    c.Header("Connection", "close")
   }
  }
  c.Next()
 })
 r.GET("/", func(c *gin.Context) {
  c.String(200, "plain/text", "hello")
 })
 l, err := net.Listen("tcp", ":8080")
 if err != nil {
  panic(err)
 }
 err = http.Serve(&counterListener{l}, r)
 if err != nil {
  panic(err)
 }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章