dubbo.apache.org/dubbo-go/v3@v3.1.1/config/registry_config.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 config 19 20 import ( 21 "net/url" 22 "strconv" 23 "strings" 24 ) 25 26 import ( 27 "github.com/creasty/defaults" 28 29 "github.com/dubbogo/gost/log/logger" 30 31 perrors "github.com/pkg/errors" 32 ) 33 34 import ( 35 "dubbo.apache.org/dubbo-go/v3/common" 36 "dubbo.apache.org/dubbo-go/v3/common/constant" 37 "dubbo.apache.org/dubbo-go/v3/common/extension" 38 "dubbo.apache.org/dubbo-go/v3/config/instance" 39 "dubbo.apache.org/dubbo-go/v3/registry" 40 ) 41 42 // RegistryConfig is the configuration of the registry center 43 type RegistryConfig struct { 44 Protocol string `validate:"required" yaml:"protocol" json:"protocol,omitempty" property:"protocol"` 45 Timeout string `default:"5s" validate:"required" yaml:"timeout" json:"timeout,omitempty" property:"timeout"` // unit: second 46 Group string `yaml:"group" json:"group,omitempty" property:"group"` 47 Namespace string `yaml:"namespace" json:"namespace,omitempty" property:"namespace"` 48 TTL string `default:"15m" yaml:"ttl" json:"ttl,omitempty" property:"ttl"` // unit: minute 49 Address string `validate:"required" yaml:"address" json:"address,omitempty" property:"address"` 50 Username string `yaml:"username" json:"username,omitempty" property:"username"` 51 Password string `yaml:"password" json:"password,omitempty" property:"password"` 52 Simplified bool `yaml:"simplified" json:"simplified,omitempty" property:"simplified"` 53 Preferred bool `yaml:"preferred" json:"preferred,omitempty" property:"preferred"` // Always use this registry first if set to true, useful when subscribe to multiple registriesConfig 54 Zone string `yaml:"zone" json:"zone,omitempty" property:"zone"` // The region where the registry belongs, usually used to isolate traffics 55 Weight int64 `yaml:"weight" json:"weight,omitempty" property:"weight"` // Affects traffic distribution among registriesConfig, useful when subscribe to multiple registriesConfig Take effect only when no preferred registry is specified. 56 Params map[string]string `yaml:"params" json:"params,omitempty" property:"params"` 57 RegistryType string `yaml:"registry-type"` 58 UseAsMetaReport bool `default:"true" yaml:"use-as-meta-report" json:"use-as-meta-report,omitempty" property:"use-as-meta-report"` 59 UseAsConfigCenter bool `default:"true" yaml:"use-as-config-center" json:"use-as-config-center,omitempty" property:"use-as-config-center"` 60 } 61 62 // Prefix dubbo.registries 63 func (RegistryConfig) Prefix() string { 64 return constant.RegistryConfigPrefix 65 } 66 67 func (c *RegistryConfig) Init() error { 68 if err := defaults.Set(c); err != nil { 69 return err 70 } 71 return c.startRegistryConfig() 72 } 73 74 func (c *RegistryConfig) getUrlMap(roleType common.RoleType) url.Values { 75 urlMap := url.Values{} 76 urlMap.Set(constant.RegistryGroupKey, c.Group) 77 urlMap.Set(constant.RegistryRoleKey, strconv.Itoa(int(roleType))) 78 urlMap.Set(constant.RegistryKey, c.Protocol) 79 urlMap.Set(constant.RegistryTimeoutKey, c.Timeout) 80 // multi registry invoker weight label for load balance 81 urlMap.Set(constant.RegistryKey+"."+constant.RegistryLabelKey, strconv.FormatBool(true)) 82 urlMap.Set(constant.RegistryKey+"."+constant.PreferredKey, strconv.FormatBool(c.Preferred)) 83 urlMap.Set(constant.RegistryKey+"."+constant.RegistryZoneKey, c.Zone) 84 urlMap.Set(constant.RegistryKey+"."+constant.WeightKey, strconv.FormatInt(c.Weight, 10)) 85 urlMap.Set(constant.RegistryTTLKey, c.TTL) 86 urlMap.Set(constant.ClientNameKey, clientNameID(c, c.Protocol, c.Address)) 87 88 for k, v := range c.Params { 89 urlMap.Set(k, v) 90 } 91 return urlMap 92 } 93 94 func (c *RegistryConfig) startRegistryConfig() error { 95 c.translateRegistryAddress() 96 if c.UseAsMetaReport && isValid(c.Address) { 97 if tmpUrl, err := c.toMetadataReportUrl(); err == nil { 98 instance.SetMetadataReportInstanceByReg(tmpUrl) 99 } else { 100 return perrors.Wrap(err, "Start RegistryConfig failed.") 101 } 102 } 103 return verify(c) 104 } 105 106 // toMetadataReportUrl translate the registry configuration to the metadata reporting url 107 func (c *RegistryConfig) toMetadataReportUrl() (*common.URL, error) { 108 res, err := common.NewURL(c.Address, 109 common.WithLocation(c.Address), 110 common.WithProtocol(c.Protocol), 111 common.WithUsername(c.Username), 112 common.WithPassword(c.Password), 113 common.WithParamsValue(constant.TimeoutKey, c.Timeout), 114 common.WithParamsValue(constant.ClientNameKey, clientNameID(c, c.Protocol, c.Address)), 115 common.WithParamsValue(constant.MetadataReportGroupKey, c.Group), 116 common.WithParamsValue(constant.MetadataReportNamespaceKey, c.Namespace), 117 ) 118 if err != nil || len(res.Protocol) == 0 { 119 return nil, perrors.New("Invalid Registry Config.") 120 } 121 return res, nil 122 } 123 124 // translateRegistryAddress translate registry address 125 // 126 // eg:address=nacos://127.0.0.1:8848 will return 127.0.0.1:8848 and protocol will set nacos 127 func (c *RegistryConfig) translateRegistryAddress() string { 128 if strings.Contains(c.Address, "://") { 129 u, err := url.Parse(c.Address) 130 if err != nil { 131 logger.Errorf("The registry url is invalid, error: %#v", err) 132 panic(err) 133 } 134 c.Protocol = u.Scheme 135 c.Address = strings.Join([]string{u.Host, u.Path}, "") 136 } 137 return c.Address 138 } 139 140 func (c *RegistryConfig) GetInstance(roleType common.RoleType) (registry.Registry, error) { 141 u, err := c.toURL(roleType) 142 if err != nil { 143 return nil, err 144 } 145 // if the protocol == registry, set protocol the registry value in url.params 146 if u.Protocol == constant.RegistryProtocol { 147 u.Protocol = u.GetParam(constant.RegistryKey, "") 148 } 149 return extension.GetRegistry(u.Protocol, u) 150 } 151 152 func (c *RegistryConfig) toURL(roleType common.RoleType) (*common.URL, error) { 153 address := c.translateRegistryAddress() 154 var registryURLProtocol string 155 if c.RegistryType == constant.RegistryTypeService { 156 // service discovery protocol 157 registryURLProtocol = constant.ServiceRegistryProtocol 158 } else if c.RegistryType == constant.RegistryTypeInterface { 159 registryURLProtocol = constant.RegistryProtocol 160 } else { 161 registryURLProtocol = constant.ServiceRegistryProtocol 162 } 163 return common.NewURL(registryURLProtocol+"://"+address, 164 common.WithParams(c.getUrlMap(roleType)), 165 common.WithParamsValue(constant.RegistrySimplifiedKey, strconv.FormatBool(c.Simplified)), 166 common.WithParamsValue(constant.RegistryKey, c.Protocol), 167 common.WithParamsValue(constant.RegistryNamespaceKey, c.Namespace), 168 common.WithParamsValue(constant.RegistryTimeoutKey, c.Timeout), 169 common.WithUsername(c.Username), 170 common.WithPassword(c.Password), 171 common.WithLocation(c.Address), 172 ) 173 } 174 175 func (c *RegistryConfig) toURLs(roleType common.RoleType) ([]*common.URL, error) { 176 address := c.translateRegistryAddress() 177 var urls []*common.URL 178 var err error 179 var registryURL *common.URL 180 181 if !isValid(c.Address) { 182 logger.Infof("Empty or N/A registry address found, the process will work with no registry enabled " + 183 "which means that the address of this instance will not be registered and not able to be found by other consumer instances.") 184 return urls, nil 185 } 186 187 if c.RegistryType == constant.RegistryTypeService { 188 // service discovery protocol 189 if registryURL, err = c.createNewURL(constant.ServiceRegistryProtocol, address, roleType); err == nil { 190 urls = append(urls, registryURL) 191 } 192 } else if c.RegistryType == constant.RegistryTypeInterface { 193 if registryURL, err = c.createNewURL(constant.RegistryProtocol, address, roleType); err == nil { 194 urls = append(urls, registryURL) 195 } 196 } else if c.RegistryType == constant.RegistryTypeAll { 197 if registryURL, err = c.createNewURL(constant.ServiceRegistryProtocol, address, roleType); err == nil { 198 urls = append(urls, registryURL) 199 } 200 if registryURL, err = c.createNewURL(constant.RegistryProtocol, address, roleType); err == nil { 201 urls = append(urls, registryURL) 202 } 203 } else { 204 if registryURL, err = c.createNewURL(constant.ServiceRegistryProtocol, address, roleType); err == nil { 205 urls = append(urls, registryURL) 206 } 207 } 208 return urls, err 209 } 210 211 func loadRegistries(registryIds []string, registries map[string]*RegistryConfig, roleType common.RoleType) []*common.URL { 212 var registryURLs []*common.URL 213 //trSlice := strings.Split(targetRegistries, ",") 214 215 for k, registryConf := range registries { 216 target := false 217 218 // if user not config targetRegistries, default load all 219 // Notice: in func "func Split(s, sep string) []string" comment: 220 // if s does not contain sep and sep is not empty, SplitAfter returns 221 // a slice of length 1 whose only element is s. So we have to add the 222 // condition when targetRegistries string is not set (it will be "" when not set) 223 if len(registryIds) == 0 || (len(registryIds) == 1 && registryIds[0] == "") { 224 target = true 225 } else { 226 // else if user config targetRegistries 227 for _, tr := range registryIds { 228 if tr == k { 229 target = true 230 break 231 } 232 } 233 } 234 235 if target { 236 if urls, err := registryConf.toURLs(roleType); err != nil { 237 logger.Errorf("The registry id: %s url is invalid, error: %#v", k, err) 238 panic(err) 239 } else { 240 registryURLs = append(registryURLs, urls...) 241 } 242 } 243 } 244 245 return registryURLs 246 } 247 248 func (c *RegistryConfig) createNewURL(protocol string, address string, roleType common.RoleType) (*common.URL, error) { 249 return common.NewURL(protocol+"://"+address, 250 common.WithParams(c.getUrlMap(roleType)), 251 common.WithParamsValue(constant.RegistrySimplifiedKey, strconv.FormatBool(c.Simplified)), 252 common.WithParamsValue(constant.RegistryKey, c.Protocol), 253 common.WithParamsValue(constant.RegistryNamespaceKey, c.Namespace), 254 common.WithParamsValue(constant.RegistryTimeoutKey, c.Timeout), 255 common.WithUsername(c.Username), 256 common.WithPassword(c.Password), 257 common.WithLocation(c.Address), 258 ) 259 } 260 261 const ( 262 defaultZKAddr = "127.0.0.1:2181" // default registry address of zookeeper 263 defaultNacosAddr = "127.0.0.1:8848" // the default registry address of nacos 264 defaultRegistryTimeout = "3s" // the default registry timeout 265 ) 266 267 type RegistryConfigOpt func(config *RegistryConfig) *RegistryConfig 268 269 // NewRegistryConfigWithProtocolDefaultPort New default registry config 270 // the input @protocol can only be: 271 // "zookeeper" with default addr "127.0.0.1:2181" 272 // "nacos" with default addr "127.0.0.1:8848" 273 func NewRegistryConfigWithProtocolDefaultPort(protocol string) *RegistryConfig { 274 switch protocol { 275 case "zookeeper": 276 return &RegistryConfig{ 277 Protocol: protocol, 278 Address: defaultZKAddr, 279 Timeout: defaultRegistryTimeout, 280 } 281 case "nacos": 282 return &RegistryConfig{ 283 Protocol: protocol, 284 Address: defaultNacosAddr, 285 Timeout: defaultRegistryTimeout, 286 } 287 default: 288 return &RegistryConfig{ 289 Protocol: protocol, 290 } 291 } 292 } 293 294 // NewRegistryConfig creates New RegistryConfig with @opts 295 func NewRegistryConfig(opts ...RegistryConfigOpt) *RegistryConfig { 296 newRegistryConfig := NewRegistryConfigWithProtocolDefaultPort("") 297 for _, v := range opts { 298 newRegistryConfig = v(newRegistryConfig) 299 } 300 return newRegistryConfig 301 } 302 303 // WithRegistryProtocol returns RegistryConfigOpt with given @regProtocol name 304 func WithRegistryProtocol(regProtocol string) RegistryConfigOpt { 305 return func(config *RegistryConfig) *RegistryConfig { 306 config.Protocol = regProtocol 307 return config 308 } 309 } 310 311 // WithRegistryAddress returns RegistryConfigOpt with given @addr registry address 312 func WithRegistryAddress(addr string) RegistryConfigOpt { 313 return func(config *RegistryConfig) *RegistryConfig { 314 config.Address = addr 315 return config 316 } 317 } 318 319 // WithRegistryTimeOut returns RegistryConfigOpt with given @timeout registry config 320 func WithRegistryTimeOut(timeout string) RegistryConfigOpt { 321 return func(config *RegistryConfig) *RegistryConfig { 322 config.Timeout = timeout 323 return config 324 } 325 } 326 327 // WithRegistryGroup returns RegistryConfigOpt with given @group registry group 328 func WithRegistryGroup(group string) RegistryConfigOpt { 329 return func(config *RegistryConfig) *RegistryConfig { 330 config.Group = group 331 return config 332 } 333 } 334 335 // WithRegistryTTL returns RegistryConfigOpt with given @ttl registry ttl 336 func WithRegistryTTL(ttl string) RegistryConfigOpt { 337 return func(config *RegistryConfig) *RegistryConfig { 338 config.TTL = ttl 339 return config 340 } 341 } 342 343 // WithRegistryUserName returns RegistryConfigOpt with given @userName registry userName 344 func WithRegistryUserName(userName string) RegistryConfigOpt { 345 return func(config *RegistryConfig) *RegistryConfig { 346 config.Username = userName 347 return config 348 } 349 } 350 351 // WithRegistryPassword returns RegistryConfigOpt with given @psw registry password 352 func WithRegistryPassword(psw string) RegistryConfigOpt { 353 return func(config *RegistryConfig) *RegistryConfig { 354 config.Password = psw 355 return config 356 } 357 } 358 359 // WithRegistrySimplified returns RegistryConfigOpt with given @simplified registry simplified flag 360 func WithRegistrySimplified(simplified bool) RegistryConfigOpt { 361 return func(config *RegistryConfig) *RegistryConfig { 362 config.Simplified = simplified 363 return config 364 } 365 } 366 367 // WithRegistryPreferred returns RegistryConfig with given @preferred registry preferred flag 368 func WithRegistryPreferred(preferred bool) RegistryConfigOpt { 369 return func(config *RegistryConfig) *RegistryConfig { 370 config.Preferred = preferred 371 return config 372 } 373 } 374 375 // WithRegistryWeight returns RegistryConfigOpt with given @weight registry weight flag 376 func WithRegistryWeight(weight int64) RegistryConfigOpt { 377 return func(config *RegistryConfig) *RegistryConfig { 378 config.Weight = weight 379 return config 380 } 381 } 382 383 // WithRegistryParams returns RegistryConfigOpt with given registry @params 384 func WithRegistryParams(params map[string]string) RegistryConfigOpt { 385 return func(config *RegistryConfig) *RegistryConfig { 386 config.Params = params 387 return config 388 } 389 } 390 391 func NewRegistryConfigBuilder() *RegistryConfigBuilder { 392 return &RegistryConfigBuilder{ 393 registryConfig: &RegistryConfig{}, 394 } 395 } 396 397 type RegistryConfigBuilder struct { 398 registryConfig *RegistryConfig 399 } 400 401 func (rcb *RegistryConfigBuilder) SetProtocol(protocol string) *RegistryConfigBuilder { 402 rcb.registryConfig.Protocol = protocol 403 return rcb 404 } 405 406 func (rcb *RegistryConfigBuilder) SetTimeout(timeout string) *RegistryConfigBuilder { 407 rcb.registryConfig.Timeout = timeout 408 return rcb 409 } 410 411 func (rcb *RegistryConfigBuilder) SetGroup(group string) *RegistryConfigBuilder { 412 rcb.registryConfig.Group = group 413 return rcb 414 } 415 416 func (rcb *RegistryConfigBuilder) SetNamespace(namespace string) *RegistryConfigBuilder { 417 rcb.registryConfig.Namespace = namespace 418 return rcb 419 } 420 421 func (rcb *RegistryConfigBuilder) SetTTL(ttl string) *RegistryConfigBuilder { 422 rcb.registryConfig.TTL = ttl 423 return rcb 424 } 425 426 func (rcb *RegistryConfigBuilder) SetAddress(address string) *RegistryConfigBuilder { 427 rcb.registryConfig.Address = address 428 return rcb 429 } 430 431 func (rcb *RegistryConfigBuilder) SetUsername(username string) *RegistryConfigBuilder { 432 rcb.registryConfig.Username = username 433 return rcb 434 } 435 436 func (rcb *RegistryConfigBuilder) SetPassword(password string) *RegistryConfigBuilder { 437 rcb.registryConfig.Password = password 438 return rcb 439 } 440 441 func (rcb *RegistryConfigBuilder) SetSimplified(simplified bool) *RegistryConfigBuilder { 442 rcb.registryConfig.Simplified = simplified 443 return rcb 444 } 445 446 func (rcb *RegistryConfigBuilder) SetPreferred(preferred bool) *RegistryConfigBuilder { 447 rcb.registryConfig.Preferred = preferred 448 return rcb 449 } 450 451 func (rcb *RegistryConfigBuilder) SetZone(zone string) *RegistryConfigBuilder { 452 rcb.registryConfig.Zone = zone 453 return rcb 454 } 455 456 func (rcb *RegistryConfigBuilder) SetWeight(weight int64) *RegistryConfigBuilder { 457 rcb.registryConfig.Weight = weight 458 return rcb 459 } 460 461 func (rcb *RegistryConfigBuilder) SetParams(params map[string]string) *RegistryConfigBuilder { 462 rcb.registryConfig.Params = params 463 return rcb 464 } 465 466 func (rcb *RegistryConfigBuilder) AddParam(key, value string) *RegistryConfigBuilder { 467 if rcb.registryConfig.Params == nil { 468 rcb.registryConfig.Params = make(map[string]string) 469 } 470 rcb.registryConfig.Params[key] = value 471 return rcb 472 } 473 474 func (rcb *RegistryConfigBuilder) SetRegistryType(registryType string) *RegistryConfigBuilder { 475 rcb.registryConfig.RegistryType = registryType 476 return rcb 477 } 478 479 func (rcb *RegistryConfigBuilder) Build() *RegistryConfig { 480 if err := rcb.registryConfig.Init(); err != nil { 481 panic(err) 482 } 483 return rcb.registryConfig 484 } 485 486 // DynamicUpdateProperties update registry 487 func (c *RegistryConfig) DynamicUpdateProperties(updateRegistryConfig *RegistryConfig) { 488 // if nacos's registry timeout not equal local root config's registry timeout , update. 489 if updateRegistryConfig != nil && updateRegistryConfig.Timeout != c.Timeout { 490 c.Timeout = updateRegistryConfig.Timeout 491 logger.Infof("RegistryConfigs Timeout was dynamically updated, new value:%v", c.Timeout) 492 } 493 }