dubbo.apache.org/dubbo-go/v3@v3.1.1/remoting/zookeeper/curator_discovery/service_discovery.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package curator_discovery 19 20 import ( 21 "encoding/json" 22 "path" 23 "strings" 24 "sync" 25 ) 26 27 import ( 28 "github.com/dubbogo/go-zookeeper/zk" 29 30 gxzookeeper "github.com/dubbogo/gost/database/kv/zk" 31 "github.com/dubbogo/gost/log/logger" 32 33 perrors "github.com/pkg/errors" 34 ) 35 36 import ( 37 "dubbo.apache.org/dubbo-go/v3/common/constant" 38 "dubbo.apache.org/dubbo-go/v3/remoting" 39 "dubbo.apache.org/dubbo-go/v3/remoting/zookeeper" 40 ) 41 42 // Entry contain a service instance 43 type Entry struct { 44 sync.Mutex 45 instance *ServiceInstance 46 } 47 48 // ServiceDiscovery which define in curator-x-discovery, please refer to 49 // https://github.com/apache/curator/blob/master/curator-x-discovery/src/main/java/org/apache/curator/x/discovery/ServiceDiscovery.java 50 // It's not exactly the same as curator-x-discovery's service discovery 51 type ServiceDiscovery struct { 52 client *gxzookeeper.ZookeeperClient 53 mutex *sync.Mutex 54 basePath string 55 services *sync.Map 56 listener *zookeeper.ZkEventListener 57 } 58 59 // NewServiceDiscovery the constructor of service discovery 60 func NewServiceDiscovery(client *gxzookeeper.ZookeeperClient, basePath string) *ServiceDiscovery { 61 return &ServiceDiscovery{ 62 client: client, 63 mutex: &sync.Mutex{}, 64 basePath: basePath, 65 services: &sync.Map{}, 66 listener: zookeeper.NewZkEventListener(client), 67 } 68 } 69 70 // registerService register service to zookeeper 71 func (sd *ServiceDiscovery) registerService(instance *ServiceInstance) error { 72 path := sd.pathForInstance(instance.Name, instance.ID) 73 data, err := json.Marshal(instance) 74 if err != nil { 75 return err 76 } 77 78 err = sd.client.Delete(path) 79 if err != nil { 80 logger.Infof("Failed when trying to delete node %s, will continue with the registration process. "+ 81 "This is designed to avoid previous ephemeral node hold the position,"+ 82 " so it's normal for this action to fail because the node might not exist or has been deleted, error msg is %s.", path, err.Error()) 83 } 84 85 err = sd.client.CreateTempWithValue(path, data) 86 if err == zk.ErrNodeExists { 87 _, state, _ := sd.client.GetContent(path) 88 if state != nil { 89 _, err = sd.client.SetContent(path, data, state.Version+1) 90 if err != nil { 91 logger.Debugf("Try to update the node data failed. In most cases, it's not a problem. ") 92 } 93 } 94 return nil 95 } 96 if err != nil { 97 return err 98 } 99 return nil 100 } 101 102 // RegisterService register service to zookeeper, and ensure cache is consistent with zookeeper 103 func (sd *ServiceDiscovery) RegisterService(instance *ServiceInstance) error { 104 value, loaded := sd.services.LoadOrStore(instance.ID, &Entry{}) 105 entry, ok := value.(*Entry) 106 if !ok { 107 return perrors.New("[ServiceDiscovery] services value not entry") 108 } 109 entry.Lock() 110 defer entry.Unlock() 111 entry.instance = instance 112 err := sd.registerService(instance) 113 if err != nil { 114 return err 115 } 116 if !loaded { 117 sd.ListenServiceInstanceEvent(instance.Name, instance.ID, sd) 118 } 119 return nil 120 } 121 122 // UpdateService update service in zookeeper, and ensure cache is consistent with zookeeper 123 func (sd *ServiceDiscovery) UpdateService(instance *ServiceInstance) error { 124 value, ok := sd.services.Load(instance.ID) 125 if !ok { 126 return perrors.Errorf("[ServiceDiscovery] Service{%s} not registered", instance.ID) 127 } 128 entry, ok := value.(*Entry) 129 if !ok { 130 return perrors.New("[ServiceDiscovery] services value not entry") 131 } 132 data, err := json.Marshal(instance) 133 if err != nil { 134 return err 135 } 136 137 entry.Lock() 138 defer entry.Unlock() 139 entry.instance = instance 140 path := sd.pathForInstance(instance.Name, instance.ID) 141 142 _, err = sd.client.SetContent(path, data, -1) 143 if err != nil { 144 return err 145 } 146 return nil 147 } 148 149 // updateInternalService update service in cache 150 func (sd *ServiceDiscovery) updateInternalService(name, id string) { 151 value, ok := sd.services.Load(id) 152 if !ok { 153 return 154 } 155 entry, ok := value.(*Entry) 156 if !ok { 157 return 158 } 159 entry.Lock() 160 defer entry.Unlock() 161 instance, err := sd.QueryForInstance(name, id) 162 if err != nil { 163 logger.Infof("[zkServiceDiscovery] UpdateInternalService{%s} error = err{%v}", id, err) 164 return 165 } 166 entry.instance = instance 167 } 168 169 // UnregisterService un-register service in zookeeper and delete service in cache 170 func (sd *ServiceDiscovery) UnregisterService(instance *ServiceInstance) error { 171 _, ok := sd.services.Load(instance.ID) 172 if !ok { 173 return nil 174 } 175 sd.services.Delete(instance.ID) 176 return sd.unregisterService(instance) 177 } 178 179 // unregisterService un-register service in zookeeper 180 func (sd *ServiceDiscovery) unregisterService(instance *ServiceInstance) error { 181 path := sd.pathForInstance(instance.Name, instance.ID) 182 return sd.client.Delete(path) 183 } 184 185 // ReRegisterServices re-register all cache services to zookeeper 186 func (sd *ServiceDiscovery) ReRegisterServices() { 187 sd.services.Range(func(key, value interface{}) bool { 188 entry, ok := value.(*Entry) 189 if !ok { 190 return true 191 } 192 entry.Lock() 193 defer entry.Unlock() 194 instance := entry.instance 195 err := sd.registerService(instance) 196 if err != nil { 197 logger.Errorf("[zkServiceDiscovery] registerService{%s} error = err{%v}", instance.ID, perrors.WithStack(err)) 198 return true 199 } 200 sd.ListenServiceInstanceEvent(instance.Name, instance.ID, sd) 201 return true 202 }) 203 } 204 205 // QueryForInstances query instances in zookeeper by name 206 func (sd *ServiceDiscovery) QueryForInstances(name string) ([]*ServiceInstance, error) { 207 ids, err := sd.client.GetChildren(sd.pathForName(name)) 208 if err != nil { 209 return nil, err 210 } 211 var ( 212 instance *ServiceInstance 213 instances []*ServiceInstance 214 ) 215 for _, id := range ids { 216 instance, err = sd.QueryForInstance(name, id) 217 if err != nil { 218 return nil, err 219 } 220 instances = append(instances, instance) 221 } 222 return instances, nil 223 } 224 225 // QueryForInstance query instances in zookeeper by name and id 226 func (sd *ServiceDiscovery) QueryForInstance(name string, id string) (*ServiceInstance, error) { 227 path := sd.pathForInstance(name, id) 228 data, _, err := sd.client.GetContent(path) 229 if err != nil { 230 return nil, err 231 } 232 instance := &ServiceInstance{} 233 err = json.Unmarshal(data, instance) 234 if err != nil { 235 return nil, err 236 } 237 return instance, nil 238 } 239 240 // QueryForNames query all service name in zookeeper 241 func (sd *ServiceDiscovery) QueryForNames() ([]string, error) { 242 return sd.client.GetChildren(sd.basePath) 243 } 244 245 // ListenServiceEvent add a listener in a service 246 func (sd *ServiceDiscovery) ListenServiceEvent(name string, listener remoting.DataListener) { 247 sd.listener.ListenServiceEvent(nil, sd.pathForName(name), listener) 248 } 249 250 // ListenServiceInstanceEvent add a listener in an instance 251 func (sd *ServiceDiscovery) ListenServiceInstanceEvent(name, id string, listener remoting.DataListener) { 252 sd.listener.ListenServiceNodeEvent(sd.pathForInstance(name, id), listener) 253 } 254 255 // DataChange implement DataListener's DataChange function 256 func (sd *ServiceDiscovery) DataChange(eventType remoting.Event) bool { 257 path := eventType.Path 258 name, id, err := sd.getNameAndID(path) 259 if err != nil { 260 logger.Errorf("[ServiceDiscovery] data change error = {%v}", err) 261 return true 262 } 263 sd.updateInternalService(name, id) 264 return true 265 } 266 267 // getNameAndID get service name and instance id by path 268 func (sd *ServiceDiscovery) getNameAndID(path string) (string, string, error) { 269 path = strings.TrimPrefix(path, sd.basePath) 270 path = strings.TrimPrefix(path, constant.PathSeparator) 271 pathSlice := strings.Split(path, constant.PathSeparator) 272 if len(pathSlice) < 2 { 273 return "", "", perrors.Errorf("[ServiceDiscovery] path{%s} dont contain name and id", path) 274 } 275 name := pathSlice[0] 276 id := pathSlice[1] 277 return name, id, nil 278 } 279 280 // nolint 281 func (sd *ServiceDiscovery) pathForInstance(name, id string) string { 282 return path.Join(sd.basePath, name, id) 283 } 284 285 // nolint 286 func (sd *ServiceDiscovery) prefixPathForInstance(name string) string { 287 return path.Join(sd.basePath, name) 288 } 289 290 // nolint 291 func (sd *ServiceDiscovery) pathForName(name string) string { 292 return path.Join(sd.basePath, name) 293 } 294 295 func (sd *ServiceDiscovery) Close() { 296 if sd.listener != nil { 297 sd.listener.Close() 298 } 299 if sd.client != nil { 300 sd.client.Close() 301 } 302 }