etcd注册模块是如何保证节点的信息都是正确的,如果某个节点出现故障,是如何发现的,
在etcdRegistry模块的run函数中,有一个ticker 10秒钟执行一次,这个ticker的作用就是没10秒从etcd读取到新的节点信息,保存到allServiceInfo的map中
func (er *EtcdRegistry) run() {
ticker := time.NewTicker(MaxSyncServiceInterval)
for {
select {
case service := <-er.serviceCh:
case <-ticker.C:
//同步AllServiceInfo
er.syncServiceFromEtcd()
default:
}
}
}
etcdRegistry模块中的syncServiceFromEtcd函数就是这个ticker需要执行函数:
首先申请一个新的allserviceInfoNew,用于存放service节点信息
从atomic.value中读取出allServiceInfo的信息,
遍历allServiceInfo的ServieMap,从里面去出Service.Name然后拼接成key,拼接出来的key是这样的
/ibinarytree/koala/comment_service/
如果出现错误 ,把老的map中的这个节点的信息,还保存成原样,存放到新的allServiceInfoNew中,否则
遍历从etcd服务器中读取的信息resp.Kvs,申请一个tmpService是吧从etcd中读取到的service信息放到tmpService临时变量中,然后再遍历tmpService.Nodes节点信息,放到ServiceNew中
然后把节点信息放到tmpService的Node切片中,再存放到allSercieInfoNew中,最后把allSercieInfoNew在存放到atomic.Value中
func (er *EtcdRegistry)syncServiceFromEtcd(){
var allServiceInfoNew = &AllServiceInfo{
serviceMap: make(map[string]*registry.Service, MaxServiceNum),
}
allServiceInfo := er.value.Load().(*AllServiceInfo)
ctx := context.TODO()
//对于缓存中的每一个服务都需要从etcd中更新
for _, service :=range allServiceInfo.serviceMap{
key := er.servicePath(service.Name)
resp, err := er.client.Get(ctx, key, clientv3.WithPrefix())
if err != nil {
allServiceInfoNew.serviceMap[service.Name] = service
continue
}
serviceNew := ®istry.Service{
Name: service.Name,
}
for _, kv := range resp.Kvs {
value := kv.Value
var tmpService registry.Service
tmpErr := json.Unmarshal(value, &tmpService)
if tmpErr != nil {
return
}
for _, node := range tmpService.Nodes {
serviceNew.Nodes = append(serviceNew.Nodes, node)
}
}
allServiceInfoNew.serviceMap[serviceNew.Name] = serviceNew
}
er.value.Store(allServiceInfoNew)
fmt.Printf("background update all service success, len:%d\n",len(allServiceInfoNew.serviceMap))
}