1. 程式人生 > >grpc中的dns負載均衡

grpc中的dns負載均衡

grpc中的dns負載均衡

(金慶的專欄 2018.8)

grpc-go 中如下連線伺服器,請求將在多個IP之間輪轉。

    conn, err := grpc.Dial(
        "dns:///rng-headless:8081",
        grpc.WithBalancerName(roundrobin.Name),
        grpc.WithInsecure())

標準的目標名應該是這樣的:"dns://authority/endpoint_name",
此處 authority 為空,詳見:https://github.com/grpc/grpc/blob/master/doc/naming.md

伺服器開3個例項,所有請求在3個例項上輪轉:

[[email protected]10-2-3-4 RoundRobin]$ kubectl run -it --rm jinqing-roundrobin --image=jinq0123/roundrobin:4
If you don't see a command prompt, try pressing enter.
2018/08/28 10:18:01 request 7754383576636566559
2018/08/28 10:18:02 request 2543876599219675746
2018/08/28 10:18:03 request 927204261937181213
2018/08/28 10:18:04 request 7754383576636566559 2018/08/28 10:18:05 request 2543876599219675746 2018/08/28 10:18:06 request 927204261937181213 ...

伺服器返回一個隨機數,不同例項的隨機數不同。程式碼是從
https://github.com/kcollasarundell/balancing-on-k8s 修改的。

...
const (
        port = ":8081"
)

type server struct{}

var r int64

func init(){
    rand.Seed
(time.Now().UnixNano()) r = rand.Int63() } func (s *server) Rng(context.Context, *rng.Source) (*rng.RN, error) { return &rng.RN{RN: r}, nil } func main() { lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() rng.RegisterRngServer(s, &server{}) // Register reflection service on gRPC server. reflection.Register(s) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } }

先編譯,打包成映象,然後用 balancing-on-k8s\backend\kube.yaml 執行:

kubectl apply -f kube.yaml

backend\kube.yaml 建立了一個 ClusterIP 服務和一個 Headless 服務,部署了 3 個伺服器例項。

[[email protected] RoundRobin]$ kubectl get svc
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
kubernetes     ClusterIP   10.96.0.1       <none>        443/TCP             93d
rng-cluster    ClusterIP   10.111.30.205   <none>        8081/TCP            4h
rng-headless   ClusterIP   None            <none>        8081/TCP,8080/TCP   4h

客戶端是一個簡單的grpc, 定時傳送請求,列印返回的隨機數。
balancing-on-k8s\clientSideBalancer\RoundRobin\main.go中的地址需要新增埠,
不然grpc會去連線 443 埠而失敗。

擴容後,測到大概3分鐘後才看到負載轉移。縮容後會立即生效。

kubectl scale --replicas=5 deployment/rng

如果是 ClusterIP 服務, 則服務名對應一個ClusterIP;
如果是 Headless 服務,則服務名對應各個Pod的IP:

/ # nslookup rng-headless
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   rng-headless.default.svc.cluster.local
Address: 10.244.3.27
Name:   rng-headless.default.svc.cluster.local
Address: 10.244.0.108
Name:   rng-headless.default.svc.cluster.local
Address: 10.244.2.66

/ # nslookup rng-cluster
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   rng-cluster.default.svc.cluster.local
Address: 10.111.30.205

/ #

如果去除 “dns:///”, 僅僅是域名加埠:

conn, err := grpc.Dial(
        "rng-headless:8081",
        grpc.WithBalancerName(roundrobin.Name),
        ...

則只會請求同一個例項。只有當該例項pod被刪除後才會切換到另一個例項。
使用縮容時發現會優先刪除沒有客戶端連線的例項。
用2個客戶端連線到不同伺服器例項,然後縮容為1例項,就可以看到請求切換。

如果客戶端和伺服器數量很大,這個dns負載均衡就不合適了,因為客戶端會連線每個伺服器例項。

參考:
Exploring Kubernetes Service Discovery and loadbalancing ( https://kca.id.au/post/k8s_service/ )