dubbo.apache.org/dubbo-go/v3@v3.1.1/registry/polaris/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 polaris 19 20 import ( 21 "fmt" 22 "sync" 23 ) 24 25 import ( 26 gxset "github.com/dubbogo/gost/container/set" 27 gxpage "github.com/dubbogo/gost/hash/page" 28 "github.com/dubbogo/gost/log/logger" 29 30 perrors "github.com/pkg/errors" 31 32 api "github.com/polarismesh/polaris-go" 33 "github.com/polarismesh/polaris-go/pkg/model" 34 ) 35 36 import ( 37 "dubbo.apache.org/dubbo-go/v3/common" 38 "dubbo.apache.org/dubbo-go/v3/common/constant" 39 "dubbo.apache.org/dubbo-go/v3/common/extension" 40 "dubbo.apache.org/dubbo-go/v3/registry" 41 "dubbo.apache.org/dubbo-go/v3/remoting" 42 "dubbo.apache.org/dubbo-go/v3/remoting/polaris" 43 ) 44 45 func init() { 46 extension.SetServiceDiscovery(constant.PolarisKey, newPolarisServiceDiscovery) 47 } 48 49 // newPolarisServiceDiscovery will create new service discovery instance 50 func newPolarisServiceDiscovery(url *common.URL) (registry.ServiceDiscovery, error) { 51 discoveryURL := common.NewURLWithOptions( 52 common.WithParams(url.GetParams()), 53 common.WithParamsValue(constant.TimeoutKey, url.GetParam(constant.RegistryTimeoutKey, constant.DefaultRegTimeout)), 54 common.WithParamsValue(constant.PolarisServiceToken, url.Password), 55 common.WithParamsValue(constant.RegistryNamespaceKey, url.GetParam(constant.RegistryNamespaceKey, constant.PolarisDefaultNamespace))) 56 discoveryURL.Location = url.Location 57 discoveryURL.Password = url.Password 58 59 if err := polaris.InitSDKContext(url); err != nil { 60 return nil, err 61 } 62 63 providerApi, err := polaris.GetProviderAPI() 64 if err != nil { 65 return nil, err 66 } 67 68 consumerApi, err := polaris.GetConsumerAPI() 69 if err != nil { 70 return nil, err 71 } 72 73 if err != nil { 74 return nil, perrors.WithMessage(err, "create polaris namingClient failed.") 75 } 76 77 descriptor := fmt.Sprintf("polaris-service-discovery[%s]", discoveryURL.Location) 78 79 newInstance := &polarisServiceDiscovery{ 80 namespace: discoveryURL.GetParam(constant.RegistryNamespaceKey, constant.PolarisDefaultNamespace), 81 descriptor: descriptor, 82 consumer: consumerApi, 83 provider: providerApi, 84 services: gxset.NewSet(), 85 registryInstances: make(map[string]*PolarisInstanceInfo), 86 watchers: make(map[string]*PolarisServiceWatcher), 87 } 88 return newInstance, nil 89 } 90 91 type polarisServiceDiscovery struct { 92 namespace string 93 descriptor string 94 provider api.ProviderAPI 95 consumer api.ConsumerAPI 96 services *gxset.HashSet 97 instanceLock sync.RWMutex 98 registryInstances map[string]*PolarisInstanceInfo 99 watchers map[string]*PolarisServiceWatcher 100 listenerLock sync.RWMutex 101 } 102 103 // Destroy destroy polarisServiceDiscovery, will do unregister all ServiceInstance 104 // and close polaris.ConsumerAPI and polaris.ProviderAPI 105 func (polaris *polarisServiceDiscovery) Destroy() error { 106 for _, inst := range polaris.registryInstances { 107 err := polaris.Unregister(inst.instance) 108 logger.Infof("Unregister polaris instance:%+v", inst) 109 if err != nil { 110 logger.Errorf("Unregister polaris instance:%+v, err:%+v", inst, err) 111 } 112 } 113 polaris.provider.Destroy() 114 polaris.consumer.Destroy() 115 return nil 116 } 117 118 // Register do register for ServiceInstance 119 func (polaris *polarisServiceDiscovery) Register(instance registry.ServiceInstance) error { 120 121 ins := convertToRegisterInstance(polaris.namespace, instance) 122 resp, err := polaris.provider.RegisterInstance(ins) 123 if err != nil { 124 return perrors.WithMessage(err, "could not register the instance. "+instance.GetServiceName()) 125 } 126 127 if resp.Existed { 128 logger.Warnf("instance already regist, namespace:%+v, service:%+v, host:%+v, port:%+v", 129 polaris.namespace, instance.GetServiceName(), instance.GetHost(), instance.GetPort()) 130 } 131 132 polaris.instanceLock.Lock() 133 defer polaris.instanceLock.Unlock() 134 135 polaris.registryInstances[getInstanceKey(polaris.namespace, instance)] = &PolarisInstanceInfo{ 136 instance: instance, 137 } 138 polaris.services.Add(instance.GetServiceName()) 139 140 return nil 141 } 142 143 // Update update ServiceInstance info 144 func (polaris *polarisServiceDiscovery) Update(instance registry.ServiceInstance) error { 145 err := polaris.Unregister(instance) 146 if err != nil { 147 return perrors.WithStack(err) 148 } 149 polaris.services.Add(instance.GetServiceName()) 150 return polaris.Register(instance) 151 } 152 153 // Unregister do Unregister for ServiceInstance 154 func (polaris *polarisServiceDiscovery) Unregister(instance registry.ServiceInstance) error { 155 156 func() { 157 polaris.instanceLock.Lock() 158 defer polaris.instanceLock.Unlock() 159 key := getInstanceKey(polaris.namespace, instance) 160 if _, exist := polaris.registryInstances[key]; exist { 161 delete(polaris.registryInstances, key) 162 } 163 }() 164 165 err := polaris.provider.Deregister(convertToDeregisterInstance(polaris.namespace, instance)) 166 if err != nil { 167 return perrors.WithMessage(err, "Could not unregister the instance. "+instance.GetServiceName()) 168 } 169 170 polaris.services.Remove(instance.GetServiceName()) 171 return nil 172 } 173 174 func (polaris *polarisServiceDiscovery) GetDefaultPageSize() int { 175 return registry.DefaultPageSize 176 } 177 178 func (polaris *polarisServiceDiscovery) GetServices() *gxset.HashSet { 179 return polaris.services 180 } 181 182 // GetInstances will return all service instances with serviceName 183 func (polaris *polarisServiceDiscovery) GetInstances(serviceName string) []registry.ServiceInstance { 184 resp, err := polaris.consumer.GetAllInstances(&api.GetAllInstancesRequest{ 185 GetAllInstancesRequest: model.GetAllInstancesRequest{ 186 Service: serviceName, 187 Namespace: polaris.namespace, 188 }, 189 }) 190 191 if err != nil { 192 logger.Errorf("Could not query the instances for service: %+v . It happened err %+v", serviceName, err) 193 return make([]registry.ServiceInstance, 0) 194 } 195 res := make([]registry.ServiceInstance, 0, len(resp.Instances)) 196 for _, ins := range resp.Instances { 197 metadata := ins.GetMetadata() 198 res = append(res, ®istry.DefaultServiceInstance{ 199 ID: ins.GetId(), 200 ServiceName: serviceName, 201 Host: ins.GetHost(), 202 Port: int(ins.GetPort()), 203 Enable: !ins.IsIsolated(), 204 Healthy: ins.IsHealthy(), 205 Metadata: metadata, 206 }) 207 } 208 return res 209 } 210 211 // GetInstancesByPage will return a page containing instances of ServiceInstance with the serviceName 212 // the page will start at offset 213 func (polaris *polarisServiceDiscovery) GetInstancesByPage(serviceName string, offset int, pageSize int) gxpage.Pager { 214 all := polaris.GetInstances(serviceName) 215 res := make([]interface{}, 0, pageSize) 216 for i := offset; i < len(all) && i < offset+pageSize; i++ { 217 res = append(res, all[i]) 218 } 219 return gxpage.NewPage(offset, pageSize, res, len(all)) 220 } 221 222 // GetHealthyInstancesByPage will return a page containing instances of ServiceInstance. 223 // The param healthy indices that the instance should be healthy or not. 224 // The page will start at offset 225 func (polaris *polarisServiceDiscovery) GetHealthyInstancesByPage(serviceName string, offset int, pageSize int, healthy bool) gxpage.Pager { 226 all := polaris.GetInstances(serviceName) 227 res := make([]interface{}, 0, pageSize) 228 // could not use res = all[a:b] here because the res should be []interface{}, not []ServiceInstance 229 var ( 230 i = offset 231 count = 0 232 ) 233 for i < len(all) && count < pageSize { 234 ins := all[i] 235 if ins.IsHealthy() == healthy { 236 res = append(res, all[i]) 237 count++ 238 } 239 i++ 240 } 241 return gxpage.NewPage(offset, pageSize, res, len(all)) 242 } 243 244 // GetRequestInstances get all instances by the specified service names 245 func (polaris *polarisServiceDiscovery) GetRequestInstances(serviceNames []string, offset int, requestedSize int) map[string]gxpage.Pager { 246 res := make(map[string]gxpage.Pager, len(serviceNames)) 247 for _, name := range serviceNames { 248 res[name] = polaris.GetInstancesByPage(name, offset, requestedSize) 249 } 250 return res 251 } 252 253 // AddListener add listener for ServiceInstancesChangedListener 254 func (polaris *polarisServiceDiscovery) AddListener(listener registry.ServiceInstancesChangedListener) error { 255 256 for _, val := range listener.GetServiceNames().Values() { 257 serviceName := val.(string) 258 watcher, err := polaris.createPolarisWatcherIfAbsent(serviceName) 259 if err != nil { 260 return err 261 } 262 263 watcher.AddSubscriber(func(et remoting.EventType, instances []model.Instance) { 264 dubboInstances := make([]registry.ServiceInstance, 0, len(instances)) 265 for _, instance := range instances { 266 dubboInstances = append(dubboInstances, ®istry.DefaultServiceInstance{ 267 ID: instance.GetId(), 268 ServiceName: instance.GetService(), 269 Host: instance.GetHost(), 270 Port: int(instance.GetPort()), 271 Enable: !instance.IsIsolated(), 272 Healthy: instance.IsHealthy(), 273 Metadata: instance.GetMetadata(), 274 GroupName: instance.GetMetadata()[constant.PolarisDubboGroup], 275 }) 276 } 277 278 listener.OnEvent(registry.NewServiceInstancesChangedEvent(serviceName, dubboInstances)) 279 }) 280 } 281 282 return nil 283 } 284 285 // createPolarisWatcherIfAbsent Calculate whether the corresponding PolarisWatcher needs to be created, 286 // if it does not exist, create one, otherwise return the existing one 287 func (polaris *polarisServiceDiscovery) createPolarisWatcherIfAbsent(serviceName string) (*PolarisServiceWatcher, error) { 288 289 polaris.listenerLock.Lock() 290 defer polaris.listenerLock.Unlock() 291 292 if _, exist := polaris.watchers[serviceName]; !exist { 293 subscribeParam := &api.WatchServiceRequest{ 294 WatchServiceRequest: model.WatchServiceRequest{ 295 Key: model.ServiceKey{ 296 Namespace: polaris.namespace, 297 Service: serviceName, 298 }, 299 }, 300 } 301 302 watcher, err := newPolarisWatcher(subscribeParam, polaris.consumer) 303 if err != nil { 304 return nil, err 305 } 306 polaris.watchers[serviceName] = watcher 307 } 308 309 return polaris.watchers[serviceName], nil 310 } 311 312 // String retuen descriptor 313 func (polaris *polarisServiceDiscovery) String() string { 314 return polaris.descriptor 315 } 316 317 func convertToRegisterInstance(namespace string, instance registry.ServiceInstance) *api.InstanceRegisterRequest { 318 319 var ( 320 health = instance.IsHealthy() 321 isolate = instance.IsEnable() 322 ttl = 5 323 protocolVal = string(constant.Dubbo) 324 ) 325 326 return &api.InstanceRegisterRequest{ 327 InstanceRegisterRequest: model.InstanceRegisterRequest{ 328 Service: instance.GetServiceName(), 329 Namespace: namespace, 330 Host: instance.GetHost(), 331 Port: instance.GetPort(), 332 Protocol: &protocolVal, 333 Metadata: instance.GetMetadata(), 334 Healthy: &health, 335 Isolate: &isolate, 336 TTL: &ttl, 337 }, 338 } 339 } 340 341 func convertToDeregisterInstance(namespace string, instance registry.ServiceInstance) *api.InstanceDeRegisterRequest { 342 return &api.InstanceDeRegisterRequest{ 343 InstanceDeRegisterRequest: model.InstanceDeRegisterRequest{ 344 Service: instance.GetServiceName(), 345 Namespace: namespace, 346 Host: instance.GetHost(), 347 Port: instance.GetPort(), 348 }, 349 } 350 }