项目作者: cperez08

项目描述 :
Resolver based on IP lookup useful for gRPC and http/http2 clients
高级语言: Go
项目地址: git://github.com/cperez08/dm-resolver.git
创建时间: 2020-08-06T20:21:39Z
项目社区:https://github.com/cperez08/dm-resolver

开源协议:MIT License

下载


dm-resolver

GoDoc
codebeat badge
Go Report Card
codecov

dm-resolver is a light way resolver library based on IP lookup and inspired by the default gRPC resolver.

Usage

The library can be used as a resolver for the gRPC go client or can be used to keep up to date your HTTP connection pool up to date.

dm-resolver is also used here as a library in the h2-proxy to help to update the domain and refresh the http2 connection pool.

Motivation

Trying to balance gRPC traffic properly in Kubernetes I came across a problem with the gRPC DNS resolver + Docker Alpine image + Kubernetes.

The problem laid in the balancing after changes in the initial mapping of the IPs against the domain. the gRPC client was actually balancing correctly the request, however, at the time Kubernetes scale up the pods or assign new IP for some reason to the pods the DNS resolver never updated the connection state hence stopped to balance correctly the request.

For instance:

  • the initial lookup returned for the domain test.kubernetes 2 IPs (10.0.0.0 and 11.0.0.0)
  • the gRPC client started to work correctly and balance (round-robin algorithm) the request properly
  • after scaling up the new set of IPs was something like 3 IPs (10.0.0.0, 11.0.0.0 and 12.0.0.0)
  • the gRPC client never sent a new request to the new IP 12.0.0.0

Usage for gRPC

  1. package main
  2. import (
  3. dmresolver "github.com/cperez08/dm-resolver/pkg/resolver"
  4. "google.golang.org/grpc"
  5. "google.golang.org/grpc/balancer/roundrobin"
  6. "google.golang.org/grpc/metadata"
  7. "google.golang.org/grpc/resolver"
  8. )
  9. var (
  10. scheme = "my-scheme-name"
  11. host = "service-address.com"
  12. port = "50051"
  13. refreshRate = time.Duration(15) // will be parsed in seconds
  14. )
  15. func main() {
  16. address := fmt.Sprintf("%s:///%s", scheme, host+":"+port)
  17. conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBalancerName(roundrobin.Name))
  18. if err != nil {
  19. log.Fatalf("did not connect: %v", err)
  20. }
  21. defer conn.Close()
  22. cli = mypkg.NewPkgServiceClient(conn)
  23. cli.Call(ctx, &myRequest{})
  24. }
  25. func init(){
  26. // scheme is the custom dns name
  27. // host is the ip or domain name
  28. // port number
  29. // true indicates if the resolver needs to watch for changes - only aplicable for domains
  30. // 50 indicates the value in seconds the resolver look for the changes in the domain.
  31. resolver.Register(dmresolver.NewDomainResolverBuilder(scheme, host, port, true, &refreshRate))
  32. }

Usage outside gRPC

  1. import "github.com/cperez08/dm-resolver/pkg/resolver"
  2. func main(){
  3. listener := make(chan bool)
  4. // host that wants to be resolved (domain or IP)
  5. // port to connecto to
  6. // true indicates if the wants the resolver to watch for domain changes
  7. // time.Duration(50) in case the previous parameter is true, is the refresh rate (new domain lookup)
  8. refreshRate := time.Duration(50)
  9. // listener listen for changes in the IPs, in case there is no change in the initial set of ips nothing is triggered
  10. r = resolver.NewResolver(host, port, true, &refreshRate, listener)
  11. // StartResolver resolves the domain the firstime and starts the domain watcher if enabled and if the address is not an IP
  12. r.StartResolver()
  13. // for knowing the current Addresses stored by the resolver
  14. r.Addresses // return a list of string in the format host:port
  15. // for stopping the watcher
  16. r.Close()
  17. }

Disclaimer: the issue commented above occurred on linux alpine and ubuntu bionic in Kubernetes