Micro-service architecture, each service will have a lot of nodes, if the traffic distribution is uneven, will cause the waste of resources, and even some of the machine crushing, this time requires load balancing, the simplest strategy is polling, sequentially select different node access
GRPC provides a load balancing implementation on the client side, and provides an interface for service address resolution and updates (DNS domain name resolution is provided by default) to facilitate integration of different services
Using the example
conn, err := grpc.Dial( "", grpc.WithInsecure(), // 负载均衡,使用 consul 作服务发现 grpc.WithBalancer(grpc.RoundRobin(grpclb.NewConsulResolver( "127.0.0.1:8500", "grpc.health.v1.add", ))),)
When creating a connection, you can use the WithBalancer
option to specify a load balancing policy, where the roundrobin algorithm is actually a polling policy
Integration with the consul
With the load balancing policy, you also need an address resolution and update policy that can be implemented using the DNS service, but if we use Consul to do the registration and discovery of services, we can implement naming.Resolver
and naming.Watcher
interface to support
naming.Resolver
: Implementing Address Resolution
naming.Watcher
: Implement node changes, add or remove
Func newconsulresolver (Address string, service string) naming. Resolver {return &consulresolver{address:address, Service:service,}}type consulresolver struc t {address string service String}func (R *consulresolver) Resolve (target string) (naming. Watcher, error) {config: = API. Defaultconfig () config. Address = r.address Client, err: = API. Newclient (config) if err! = Nil {return nil, err} return &consulwatcher{client:client, Service:r.service, addrs:map[string]struct{}{},}, Nil}type consulwatcher struct {client *api. Client service string Addrs map[string]struct{} lastIndex uint64}func (w *consulwatcher) Next ([]*naming]. Update, error) {for {services, metainfo, err: = W.client.health (). Service (W.service, "", True, &api. queryoptions{Waitindex:w.lastindex,//sync point, this call will always block until there is a new update}) if Err! = Nil {logr us. Warn ("Error REtrieving instances from Consul:%v ", err)} W.lastindex = MetaInfo. LastIndex Addrs: = map[string]struct{}{} for _, Service: = Range Services {addrs[net. Joinhostport (service. Service.address, StrConv. Itoa (service. Service.port)]] = struct{}{}} var updates []*naming. Update for addr: = Range W.addrs {If _, OK: = Addrs[addr];!ok {updates = append (update S, &naming. Update{op:naming. Delete, Addr:addr})}} for Addr: = Range Addrs {If _, OK: = W.addrs[addr];!ok { Updates = Append (updates, &naming. Update{op:naming. ADD, Addr:addr})}} If Len (updates)! = 0 {W.addrs = Addrs return updates , nil}}}func (w *consulwatcher) Close () {//do}
Reference links
- Grpc Name resolution:https://github.com/grpc/grpc/blob/master/doc/naming.md
- Load Balancing in Grpc:https://github.com/grpc/grpc/blob/master/doc/load-balancing.md
- Dns_resolver:https://github.com/grpc/grpc-go/blob/30fb59a4304034ce78ff68e21bd25776b1d79488/naming/dns_resolver.go
- Code Address: Https://github.com/hatlonely/hellogolang/blob/master/sample/addservice/cmd/client/main.go
Reprint please indicate the source
This article link: http://www.hatlonely.com/2018/06/23/golang-grpc-%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1/