服务的注册与发现是微服务必不可少的功能,这样系统才能有更高的性能,更高的可用性。go-micro框架的服务发现有本身能用的接口Registry。只要实现这个接口就能够定制本身的服务注册和发现。算法
go-micro在客户端作的负载,典型的Balancing-aware Client模式。缓存
服务端把服务的地址信息保存到Registry, 而后定时的心跳检查,或者定时的从新注册服务。客户端监听Registry,最好是把服务信息保存到本地,监听服务的变更,更新缓存。当调用服务端的接口是时,根据客户端的服务列表和负载算法选择服务端进行通讯。服务器
go-micro的能用Registry接口框架
type Registry interface { Register(*Service, ...RegisterOption) error Deregister(*Service) error GetService(string) ([]*Service, error) ListServices() ([]*Service, error) Watch(...WatchOption) (Watcher, error) String() string Options() Options } type Watcher interface { // Next is a blocking call Next() (*Result, error) Stop() }
这个接口仍是很简单明了的,看方法也大概能猜到主要的做用微服务
Register方法和Deregister是服务端用于注册服务的,Watcher接口是客户端用于监听服务信息变化的。性能
接下来我以go-micro的etcdv3为Registry的例给你们详细讲解一下go-micro的详细服务发现过程spa
流程图3d
服务端看上去流程仍是比较简单的,当服务端调用Run()方法时,会调用service.Start()方法。这个除了监听端口,启动服务,还会把服务的ip端口号信息,和全部的公开接口的元数据信息保存到咱们选择的Register服务器上去。code
看上去没有问题,可是,若是咱们的节点发生故障,也是须要告诉Register把咱们的节点信息删除掉。协程
Run()方法中有个go s.run(ex) 方法的调用,这个方法就是根据咱们设置interval去从新注册服务,固然比较保险的方式是咱们把服务的ttl也设置上,这样当服务在未知的状况下崩溃,到了ttl的时间Register服务也会自动把信息删除掉。
设置服务的ttl和 interval
// 初始化服务 service := micro.NewService( micro.Name(common.ServiceName), micro.RegisterTTL(time.Second*30), micro.RegisterInterval(time.Second*20), micro.Registry(reg), )
ttl就是注册服务的过时时间,interval就是间隔多久再次注册服务。若是系统崩溃,过时时间也会把服务删除掉。客户端固然也会有相应的判断,下面会详细解说
客户端的服务发现要步骤多一些,但并不复杂,他涉及到服务选择Selector和服务发现Register两部分。
Selector是基于服务发现的,根据你选择的主机选择算法,返回主机的信息。默认的状况,go-micro是每次要获得服务器主机的信息都要去Register去获取。可是查看cmd.go的源码你会发现默认初始化的值,selector的默认flag是cache。DefaultSelectors里的cache对应的就是初始化cacheSelector方法
可是当你在执行service.Init()方法时
go-micro会把默认的selector替换成cacheSelector,具体的实现是在cmd.go的Before方法里
cacheSelector 会把从Register里获取的主机信息缓存起来。并设置超时时间,若是超时则从新获取。在获取主机信息的时候他会单独跑一个协程,去watch服务的注册,若是有新节点发现,则加到缓存中,若是有节点故障则删除缓存中的节点信息。当client还要根据selector选择的主机选择算法才能获得主机信息,目前只有两种算法,循环和随机法。为了增长执行效率,很client端也会设置缓存链接池,这个点,之后会详细说。
因此大概的客户端服务发现流程是下面这样
主要的调用过程都在Call方法内
主要的思路是
从Selector里获得选择主机策略方法next。
根据Retory是否重试调用服务,调用服务的过程是,从next 方法内获得主机,链接并传输数据 ,若是失败则重试,重试时,会根据主机选择策略方法next从新获得一个新的主机进行操做。