grpc-go 中如下连接服务器,请求将在多个IP之间轮转。

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

    标准的目标名应该是这样的:”dns://authority/endpoint_name”,此处 authority 为空,详见:https://github.com/grpc/grpc/blob/master/doc/naming.md

    服务器开3个实例,所有请求在3个实例上轮转:

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

    服务器返回一个随机数,不同实例的随机数不同。代码是从https://github.com/kcollasarundell/balancing-on-k8s修改的。

    1. ...
    2. const (
    3. port = ":8081"
    4. )
    5. type server struct{}
    6. var r int64
    7. func init(){
    8. rand.Seed(time.Now().UnixNano())
    9. r = rand.Int63()
    10. }
    11. func (s *server) Rng(context.Context, *rng.Source) (*rng.RN, error) {
    12. return &rng.RN{RN: r}, nil
    13. }
    14. func main() {
    15. lis, err := net.Listen("tcp", port)
    16. if err != nil {
    17. log.Fatalf("failed to listen: %v", err)
    18. }
    19. s := grpc.NewServer()
    20. rng.RegisterRngServer(s, &server{})
    21. // Register reflection service on gRPC server.
    22. reflection.Register(s)
    23. if err := s.Serve(lis); err != nil {
    24. log.Fatalf("failed to serve: %v", err)
    25. }
    26. }

    先编译,打包成镜像,然后用balancing-on-k8s\backend\kube.yaml运行:

    1. kubectl apply -f kube.yaml

    backend\kube.yaml创建了一个 ClusterIP 服务和一个 Headless 服务,部署了 3 个服务器实例。

    1. [jinqing@host-10-2-3-4 RoundRobin]$ kubectl get svc
    2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    3. kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 93d
    4. rng-cluster ClusterIP 10.111.30.205 <none> 8081/TCP 4h
    5. rng-headless ClusterIP None <none> 8081/TCP,8080/TCP 4h

    客户端是一个简单的grpc, 定时发送请求,打印返回的随机数。balancing-on-k8s\clientSideBalancer\RoundRobin\main.go中的地址需要添加端口,不然grpc会去连接 443 端口而失败。

    扩容后,测到大概3分钟后才看到负载转移。缩容后会立即生效。

    1. kubectl scale --replicas=5 deployment/rng

    如果去除 “dns:///”, 仅仅是域名加端口:

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

    则只会请求同一个实例。只有当该实例pod被删除后才会切换到另一个实例。
    以上转自:https://blog.csdn.net/jq0123/article/details/82179864

    实际:经过测试,并没负载转移,可能是版本问题?例如:从1台扩容到3台,只要最开始连的那一台掉线,才会触发一次dns解析

    代码位置 :grpc@v1.40.0/internal/resolver/dns/dns_resolver.go:209
    image.png
    验证结果:解析成功后,代码会卡在这里,只有内部连接池里面有任意一条连接断掉,才会重新触发dns解析

    强迫症表示无法接受该方案!

    那我们换一种思路,自己手动写一个解析器,监听dns,只要dns发生了变化,立马更新连接,就如etcd实现的负载均衡一样。解决方案:kuberesolver

    1. // Import the module
    2. import "github.com/sercand/kuberesolver/v3"
    3. // Register kuberesolver to grpc before calling grpc.Dial
    4. kuberesolver.RegisterInCluster()
    5. // if schema is 'kubernetes' then grpc will use kuberesolver to resolve addresses
    6. cc, err := grpc.Dial("kubernetes:///service.namespace:portname", opts...)