Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

请教一些问题 #12

Closed
sirodeneko opened this issue Jun 11, 2021 · 2 comments
Closed

请教一些问题 #12

sirodeneko opened this issue Jun 11, 2021 · 2 comments

Comments

@sirodeneko
Copy link

1.本例子中是网关是只有一个服务的,但是如果我有多个服务,网关的代码应该如何编写,grpc是如何确定要选择那个路由的。

2.这行代码中的第二个参数为什么是"://authority/",有什么含义吗

conn, err := grpc.DialContext(ctx, r.Scheme()+"://authority/"+*svc, grpc.WithInsecure(), grpc.WithBalancerName(roundrobin.Name), grpc.WithBlock())
@wwcd
Copy link
Owner

wwcd commented Jun 11, 2021

问题1,多个grpc服务后端话,每个后端是一个conn,然后通过注册其支持的接口,

err = pb.RegisterGreeterHandler(ctx, mux, conn)

问题2,参见代码注释的链接https://github.com/grpc/grpc/blob/master/doc/naming.md#name-syntax

@sirodeneko
Copy link
Author

我大概知道是怎么回事了,
调用 grpc.DialContext(ctx, r.Scheme()+"://authority/"+"serviceName",...)时
会根据第二个参数解析出一个resolver.Target{}
Scheme=r.Scheme()
Authority="authority"
Endpoint="serviceName"
根据Scheme将拿到我们注册的Builder.

还有一个问题,grpc每次调用我们的Build方法,就会进行watch一个服务,但是我看grpc是根据schema来区分不同的Resolver,但是我要求可以查询每个不同的服务,请问如果schema相同,Endpoint(即服务)不同会重复调用Build方法吗。
这是我的代码,进行了一些修改,服务名从resolver.Target中拿

const schema = "wethedevelop/resolver"

// resolver is the implementaion of grpc.resolve.Builder
type Resolver struct {
	endpoints  string
	cli     *clientv3.Client
	cc      resolver.ClientConn
}

// NewResolver return resolver builder
// target example: "http://127.0.0.1:2379,http://127.0.0.1:12379,http://127.0.0.1:22379"
// service is service name
func NewResolver(endpoints string) resolver.Builder {
	return &Resolver{endpoints: endpoints}
}

// Scheme return etcdv3 schema
func (r *Resolver) Scheme() string {
	return schema
}

// ResolveNow
func (r *Resolver) ResolveNow(rn resolver.ResolveNowOptions) {
}

// Close
func (r *Resolver) Close() {
}

// Build to resolver.Resolver
func (r *Resolver) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
	var err error

	r.cli, err = clientv3.New(clientv3.Config{
		Endpoints: strings.Split(r.endpoints, ","),
	})
	if err != nil {
		return nil, fmt.Errorf("gateway: create clientv3 client failed: %v", err)
	}

	r.cc = cc

	go r.watch(fmt.Sprintf("/%s/%s/", schema, target.Endpoint))

	return r, nil
}

func (r *Resolver) watch(prefix string) {
	addrDict := make(map[string]resolver.Address)

	update := func() {
		addrList := make([]resolver.Address, 0, len(addrDict))
		for _, v := range addrDict {
			addrList = append(addrList, v)
		}
		r.cc.UpdateState(resolver.State{Addresses: addrList})
	}

	resp, err := r.cli.Get(context.Background(), prefix, clientv3.WithPrefix())
	if err == nil {
		for i := range resp.Kvs {
			addrDict[string(resp.Kvs[i].Value)] = resolver.Address{Addr: string(resp.Kvs[i].Value)}
		}
	}

	update()

	rch := r.cli.Watch(context.Background(), prefix, clientv3.WithPrefix(), clientv3.WithPrevKV())
	for n := range rch {
		for _, ev := range n.Events {
			switch ev.Type {
			case mvccpb.PUT:
				addrDict[string(ev.Kv.Key)] = resolver.Address{Addr: string(ev.Kv.Value)}
			case mvccpb.DELETE:
				delete(addrDict, string(ev.PrevKv.Key))
			}
		}
		update()
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants