dubbo.apache.org/dubbo-go/v3@v3.1.1/registry/protocol/protocol.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 protocol
    19  
    20  import (
    21  	"context"
    22  	"strings"
    23  	"sync"
    24  	"time"
    25  )
    26  
    27  import (
    28  	gxset "github.com/dubbogo/gost/container/set"
    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"
    39  	"dubbo.apache.org/dubbo-go/v3/config_center"
    40  	_ "dubbo.apache.org/dubbo-go/v3/config_center/configurator"
    41  	"dubbo.apache.org/dubbo-go/v3/protocol"
    42  	"dubbo.apache.org/dubbo-go/v3/protocol/dubbo3/health"
    43  	"dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper"
    44  	"dubbo.apache.org/dubbo-go/v3/registry"
    45  	"dubbo.apache.org/dubbo-go/v3/remoting"
    46  )
    47  
    48  var (
    49  	regProtocol   *registryProtocol
    50  	once          sync.Once
    51  	reserveParams = []string{
    52  		"application", "codec", "exchanger", "serialization", "cluster", "connections", "deprecated", "group",
    53  		"loadbalance", "mock", "path", "timeout", "token", "version", "warmup", "weight", "timestamp", "dubbo",
    54  		"release", "interface", "registry.role",
    55  	}
    56  )
    57  
    58  type registryProtocol struct {
    59  	// Registry Map<RegistryAddress, Registry>
    60  	registries *sync.Map
    61  	// To solve the problem of RMI repeated exposure port conflicts,
    62  	// the services that have been exposed are no longer exposed.
    63  	// providerurl <--> exporter
    64  	bounds                        *sync.Map
    65  	overrideListeners             *sync.Map
    66  	serviceConfigurationListeners *sync.Map
    67  	providerConfigurationListener *providerConfigurationListener
    68  	once                          sync.Once
    69  }
    70  
    71  func init() {
    72  	extension.SetProtocol(constant.RegistryProtocol, GetProtocol)
    73  }
    74  
    75  func newRegistryProtocol() *registryProtocol {
    76  	return &registryProtocol{
    77  		registries: &sync.Map{},
    78  		bounds:     &sync.Map{},
    79  	}
    80  }
    81  
    82  func (proto *registryProtocol) getRegistry(registryUrl *common.URL) registry.Registry {
    83  	var err error
    84  	reg, loaded := proto.registries.Load(registryUrl.PrimitiveURL)
    85  	if !loaded {
    86  		reg, err = extension.GetRegistry(registryUrl.Protocol, registryUrl)
    87  		if err != nil {
    88  			logger.Errorf("Registry can not connect success, program is going to panic.Error message is %s", err.Error())
    89  			panic(err)
    90  		}
    91  		proto.registries.Store(registryUrl.PrimitiveURL, reg)
    92  	}
    93  	return reg.(registry.Registry)
    94  }
    95  
    96  func getCacheKey(invoker protocol.Invoker) string {
    97  	url := getProviderUrl(invoker)
    98  	delKeys := gxset.NewSet("dynamic", "enabled")
    99  	return url.CloneExceptParams(delKeys).String()
   100  }
   101  
   102  func getUrlToRegistry(providerUrl *common.URL, registryUrl *common.URL) *common.URL {
   103  	if registryUrl.GetParamBool("simplified", false) {
   104  		return providerUrl.CloneWithParams(reserveParams)
   105  	} else {
   106  		return filterHideKey(providerUrl)
   107  	}
   108  }
   109  
   110  // filterHideKey filter the parameters that do not need to be output in url(Starting with .)
   111  func filterHideKey(url *common.URL) *common.URL {
   112  	// be careful params maps in url is map type
   113  	removeSet := gxset.NewSet()
   114  	for k := range url.GetParams() {
   115  		if strings.HasPrefix(k, ".") {
   116  			removeSet.Add(k)
   117  		}
   118  	}
   119  	return url.CloneExceptParams(removeSet)
   120  }
   121  
   122  func (proto *registryProtocol) initConfigurationListeners() {
   123  	proto.overrideListeners = &sync.Map{}
   124  	proto.serviceConfigurationListeners = &sync.Map{}
   125  	proto.providerConfigurationListener = newProviderConfigurationListener(proto.overrideListeners)
   126  }
   127  
   128  // nolint
   129  func (proto *registryProtocol) GetRegistries() []registry.Registry {
   130  	var rs []registry.Registry
   131  	proto.registries.Range(func(_, v interface{}) bool {
   132  		if r, ok := v.(registry.Registry); ok {
   133  			rs = append(rs, r)
   134  		}
   135  		return true
   136  	})
   137  	return rs
   138  }
   139  
   140  // Refer provider service from registry center
   141  func (proto *registryProtocol) Refer(url *common.URL) protocol.Invoker {
   142  	registryUrl := url
   143  	serviceUrl := registryUrl.SubURL
   144  	if registryUrl.Protocol == constant.RegistryProtocol {
   145  		registryUrl.Protocol = registryUrl.GetParam(constant.RegistryKey, "")
   146  	}
   147  
   148  	reg := proto.getRegistry(url)
   149  
   150  	// new registry directory for store service url from registry
   151  	dic, err := extension.GetDirectoryInstance(registryUrl, reg)
   152  	if err != nil {
   153  		logger.Errorf("consumer service %v create registry directory error, error message is %s, and will return nil invoker!",
   154  			serviceUrl.String(), err.Error())
   155  		return nil
   156  	}
   157  
   158  	// This will start a new routine and listen to instance changes.
   159  	err = dic.Subscribe(registryUrl.SubURL)
   160  
   161  	if err != nil {
   162  		logger.Errorf("consumer service %v register registry %v error, error message is %s",
   163  			serviceUrl.String(), registryUrl.String(), err.Error())
   164  	}
   165  
   166  	// new cluster invoker
   167  	clusterKey := serviceUrl.GetParam(constant.ClusterKey, constant.DefaultCluster)
   168  	cluster, err := extension.GetCluster(clusterKey)
   169  	if err != nil {
   170  		panic(err)
   171  	}
   172  	invoker := cluster.Join(dic)
   173  	return invoker
   174  }
   175  
   176  // Export provider service to registry center
   177  func (proto *registryProtocol) Export(originInvoker protocol.Invoker) protocol.Exporter {
   178  	proto.once.Do(func() {
   179  		proto.initConfigurationListeners()
   180  	})
   181  	registryUrl := getRegistryUrl(originInvoker)
   182  	providerUrl := getProviderUrl(originInvoker)
   183  
   184  	overriderUrl := getSubscribedOverrideUrl(providerUrl)
   185  	// Deprecated! subscribe to override rules in 2.6.x or before.
   186  	overrideSubscribeListener := newOverrideSubscribeListener(overriderUrl, originInvoker, proto)
   187  	proto.overrideListeners.Store(overriderUrl, overrideSubscribeListener)
   188  	proto.providerConfigurationListener.OverrideUrl(providerUrl)
   189  	serviceConfigurationListener := newServiceConfigurationListener(overrideSubscribeListener, providerUrl)
   190  	proto.serviceConfigurationListeners.Store(providerUrl.ServiceKey(), serviceConfigurationListener)
   191  	serviceConfigurationListener.OverrideUrl(providerUrl)
   192  
   193  	// export invoker
   194  	exporter := proto.doLocalExport(originInvoker, providerUrl)
   195  
   196  	// update health status
   197  	health.SetServingStatusServing(registryUrl.Service())
   198  
   199  	if len(registryUrl.Protocol) > 0 {
   200  		// url to registry
   201  		reg := proto.getRegistry(registryUrl)
   202  		registeredProviderUrl := getUrlToRegistry(providerUrl, registryUrl)
   203  
   204  		err := reg.Register(registeredProviderUrl)
   205  		if err != nil {
   206  			logger.Errorf("provider service %v register registry %v error, error message is %s",
   207  				providerUrl.Key(), registryUrl.Key(), err.Error())
   208  			return nil
   209  		}
   210  
   211  		go func() {
   212  			if err := reg.Subscribe(overriderUrl, overrideSubscribeListener); err != nil {
   213  				logger.Warnf("reg.subscribe(overriderUrl:%v) = error:%v", overriderUrl, err)
   214  			}
   215  		}()
   216  
   217  		exporter.SetRegisterUrl(registeredProviderUrl)
   218  		exporter.SetSubscribeUrl(overriderUrl)
   219  
   220  	} else {
   221  		logger.Warnf("provider service %v do not regist to registry %v. possible direct connection provider",
   222  			providerUrl.Key(), registryUrl.Key())
   223  	}
   224  
   225  	return exporter
   226  }
   227  
   228  func (proto *registryProtocol) doLocalExport(originInvoker protocol.Invoker, providerUrl *common.URL) *exporterChangeableWrapper {
   229  	key := getCacheKey(originInvoker)
   230  	cachedExporter, loaded := proto.bounds.Load(key)
   231  	if !loaded {
   232  		// new Exporter
   233  		invokerDelegate := newInvokerDelegate(originInvoker, providerUrl)
   234  		cachedExporter = newExporterChangeableWrapper(originInvoker,
   235  			extension.GetProtocol(protocolwrapper.FILTER).Export(invokerDelegate))
   236  		proto.bounds.Store(key, cachedExporter)
   237  	}
   238  	return cachedExporter.(*exporterChangeableWrapper)
   239  }
   240  
   241  func (proto *registryProtocol) reExport(invoker protocol.Invoker, newUrl *common.URL) {
   242  	key := getCacheKey(invoker)
   243  	if oldExporter, loaded := proto.bounds.Load(key); loaded {
   244  		wrappedNewInvoker := newInvokerDelegate(invoker, newUrl)
   245  		oldExporter.(protocol.Exporter).UnExport()
   246  		proto.bounds.Delete(key)
   247  		// oldExporter UnExport function unRegister rpcService from the serviceMap, so need register it again as far as possible
   248  		if err := registerServiceMap(invoker); err != nil {
   249  			logger.Error(err.Error())
   250  		}
   251  		proto.Export(wrappedNewInvoker)
   252  		// TODO:  unregister & unsubscribe
   253  	}
   254  }
   255  
   256  func registerServiceMap(invoker protocol.Invoker) error {
   257  	providerUrl := getProviderUrl(invoker)
   258  	// the bean.name param of providerUrl is the ServiceConfig id property
   259  	// such as dubbo://:20000/org.apache.dubbo.UserProvider?bean.name=UserProvider&cluster=failfast...
   260  	id := providerUrl.GetParam(constant.BeanNameKey, "")
   261  
   262  	serviceConfig := config.GetProviderConfig().Services[id]
   263  	if serviceConfig == nil {
   264  		s := "reExport can not get serviceConfig"
   265  		return perrors.New(s)
   266  	}
   267  	rpcService := config.GetProviderService(id)
   268  	if rpcService == nil {
   269  		s := "reExport can not get RPCService"
   270  		return perrors.New(s)
   271  	}
   272  
   273  	_, err := common.ServiceMap.Register(serviceConfig.Interface,
   274  		// FIXME
   275  		serviceConfig.ProtocolIDs[0], serviceConfig.Group,
   276  		serviceConfig.Version, rpcService)
   277  	if err != nil {
   278  		s := "reExport can not re register ServiceMap. Error message is " + err.Error()
   279  		return perrors.New(s)
   280  	}
   281  	return nil
   282  }
   283  
   284  type overrideSubscribeListener struct {
   285  	url           *common.URL
   286  	originInvoker protocol.Invoker
   287  	protocol      *registryProtocol
   288  	configurator  config_center.Configurator
   289  }
   290  
   291  func newOverrideSubscribeListener(overriderUrl *common.URL, invoker protocol.Invoker, proto *registryProtocol) *overrideSubscribeListener {
   292  	return &overrideSubscribeListener{url: overriderUrl, originInvoker: invoker, protocol: proto}
   293  }
   294  
   295  // Notify will be triggered when a service change notification is received.
   296  func (nl *overrideSubscribeListener) Notify(event *registry.ServiceEvent) {
   297  	if isMatched(event.Service, nl.url) && event.Action == remoting.EventTypeAdd {
   298  		nl.configurator = extension.GetDefaultConfigurator(event.Service)
   299  		nl.doOverrideIfNecessary()
   300  	}
   301  }
   302  
   303  func (nl *overrideSubscribeListener) NotifyAll(events []*registry.ServiceEvent, callback func()) {
   304  	defer callback()
   305  	if len(events) == 0 {
   306  		return
   307  	}
   308  	for _, e := range events {
   309  		nl.Notify(e)
   310  	}
   311  }
   312  
   313  func (nl *overrideSubscribeListener) doOverrideIfNecessary() {
   314  	providerUrl := getProviderUrl(nl.originInvoker)
   315  	key := getCacheKey(nl.originInvoker)
   316  	if exporter, ok := nl.protocol.bounds.Load(key); ok {
   317  		currentUrl := exporter.(protocol.Exporter).GetInvoker().GetURL()
   318  		// Compatible with the 2.6.x
   319  		if nl.configurator != nil {
   320  			nl.configurator.Configure(providerUrl)
   321  		}
   322  		// provider application level  management in 2.7.x
   323  		for _, v := range nl.protocol.providerConfigurationListener.Configurators() {
   324  			v.Configure(providerUrl)
   325  		}
   326  		// provider service level  management in 2.7.x
   327  		if serviceListener, ok := nl.protocol.serviceConfigurationListeners.Load(providerUrl.ServiceKey()); ok {
   328  			listener := serviceListener.(*serviceConfigurationListener)
   329  			for _, v := range listener.Configurators() {
   330  				v.Configure(providerUrl)
   331  			}
   332  		}
   333  
   334  		if currentUrl.String() != providerUrl.String() {
   335  			newRegUrl := nl.originInvoker.GetURL().Clone()
   336  			setProviderUrl(newRegUrl, providerUrl)
   337  			nl.protocol.reExport(nl.originInvoker, newRegUrl)
   338  		}
   339  	}
   340  }
   341  
   342  func isMatched(providerUrl *common.URL, consumerUrl *common.URL) bool {
   343  	// Compatible with the 2.6.x
   344  	if len(providerUrl.GetParam(constant.CategoryKey, "")) == 0 &&
   345  		providerUrl.Protocol == constant.OverrideProtocol {
   346  		providerUrl.AddParam(constant.CategoryKey, constant.ConfiguratorsCategory)
   347  	}
   348  	consumerInterface := consumerUrl.GetParam(constant.InterfaceKey, consumerUrl.Path)
   349  	providerInterface := providerUrl.GetParam(constant.InterfaceKey, providerUrl.Path)
   350  
   351  	if !(constant.AnyValue == consumerInterface ||
   352  		constant.AnyValue == providerInterface ||
   353  		providerInterface == consumerInterface) {
   354  		return false
   355  	}
   356  
   357  	if !isMatchCategory(providerUrl.GetParam(constant.CategoryKey, constant.DefaultCategory),
   358  		consumerUrl.GetParam(constant.CategoryKey, constant.DefaultCategory)) {
   359  		return false
   360  	}
   361  
   362  	if !providerUrl.GetParamBool(constant.EnabledKey, true) &&
   363  		consumerUrl.GetParam(constant.EnabledKey, "") != constant.AnyValue {
   364  		return false
   365  	}
   366  	consumerGroup := consumerUrl.GetParam(constant.GroupKey, "")
   367  	consumerVersion := consumerUrl.GetParam(constant.VersionKey, "")
   368  	consumerClassifier := consumerUrl.GetParam(constant.ClassifierKey, "")
   369  
   370  	providerGroup := providerUrl.GetParam(constant.GroupKey, "")
   371  	providerVersion := providerUrl.GetParam(constant.VersionKey, "")
   372  	providerClassifier := providerUrl.GetParam(constant.ClassifierKey, "")
   373  	// todo: public static boolean isContains(String values, String value) {
   374  	//        return isNotEmpty(values) && isContains(CommaSplitPattern.split(values), value);
   375  	//    }
   376  	return (consumerGroup == constant.AnyValue || consumerGroup == providerGroup ||
   377  		strings.Contains(consumerGroup, providerGroup)) && (consumerVersion == constant.AnyValue ||
   378  		consumerVersion == providerVersion) && (len(consumerClassifier) == 0 ||
   379  		consumerClassifier == constant.AnyValue || consumerClassifier == providerClassifier)
   380  }
   381  
   382  func isMatchCategory(category string, categories string) bool {
   383  	if len(categories) == 0 {
   384  		return category == constant.DefaultCategory
   385  	} else if strings.Contains(categories, constant.AnyValue) {
   386  		return true
   387  	} else if strings.Contains(categories, constant.RemoveValuePrefix) {
   388  		return !strings.Contains(categories, constant.RemoveValuePrefix+category)
   389  	} else {
   390  		return strings.Contains(categories, category)
   391  	}
   392  }
   393  
   394  func getSubscribedOverrideUrl(providerUrl *common.URL) *common.URL {
   395  	newUrl := providerUrl.Clone()
   396  	newUrl.Protocol = constant.ProviderProtocol
   397  	newUrl.SetParam(constant.CategoryKey, constant.ConfiguratorsCategory)
   398  	newUrl.SetParam(constant.CheckKey, "false")
   399  	return newUrl
   400  }
   401  
   402  // Destroy registry protocol
   403  func (proto *registryProtocol) Destroy() {
   404  	proto.bounds.Range(func(key, value interface{}) bool {
   405  		// protocol holds the exporters actually, instead, registry holds them in order to avoid export repeatedly, so
   406  		// the work for unexport should be finished in protocol.UnExport(), see also config.destroyProviderProtocols().
   407  		exporter := value.(*exporterChangeableWrapper)
   408  		reg := proto.getRegistry(getRegistryUrl(exporter.originInvoker))
   409  		if err := reg.UnRegister(exporter.registerUrl); err != nil {
   410  			panic(err)
   411  		}
   412  		// TODO unsubscribeUrl
   413  
   414  		// close all protocol server after consumerUpdateWait + stepTimeout(max time wait during
   415  		// waitAndAcceptNewRequests procedure)
   416  		go func() {
   417  			select {
   418  			case <-time.After(config.GetShutDown().GetStepTimeout() + config.GetShutDown().GetConsumerUpdateWaitTime()):
   419  				exporter.UnExport()
   420  				proto.bounds.Delete(key)
   421  			}
   422  		}()
   423  		return true
   424  	})
   425  
   426  	proto.registries.Range(func(key, value interface{}) bool {
   427  		proto.registries.Delete(key)
   428  		return true
   429  	})
   430  }
   431  
   432  func getRegistryUrl(invoker protocol.Invoker) *common.URL {
   433  	// here add * for return a new url
   434  	url := invoker.GetURL()
   435  	// if the protocol == registry, set protocol the registry value in url.params
   436  	if url.Protocol == constant.RegistryProtocol {
   437  		url.Protocol = url.GetParam(constant.RegistryKey, "")
   438  	}
   439  	return url
   440  }
   441  
   442  func getProviderUrl(invoker protocol.Invoker) *common.URL {
   443  	url := invoker.GetURL()
   444  	// be careful params maps in url is map type
   445  	return url.SubURL.Clone()
   446  }
   447  
   448  func setProviderUrl(regURL *common.URL, providerURL *common.URL) {
   449  	regURL.SubURL = providerURL
   450  }
   451  
   452  // GetProtocol return the singleton registryProtocol
   453  func GetProtocol() protocol.Protocol {
   454  	once.Do(func() {
   455  		regProtocol = newRegistryProtocol()
   456  	})
   457  	return regProtocol
   458  }
   459  
   460  type invokerDelegate struct {
   461  	invoker protocol.Invoker
   462  	protocol.BaseInvoker
   463  }
   464  
   465  func newInvokerDelegate(invoker protocol.Invoker, url *common.URL) *invokerDelegate {
   466  	return &invokerDelegate{
   467  		invoker:     invoker,
   468  		BaseInvoker: *protocol.NewBaseInvoker(url),
   469  	}
   470  }
   471  
   472  // Invoke remote service base on URL of wrappedInvoker
   473  func (ivk *invokerDelegate) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result {
   474  	return ivk.invoker.Invoke(ctx, invocation)
   475  }
   476  
   477  type exporterChangeableWrapper struct {
   478  	protocol.Exporter
   479  	originInvoker protocol.Invoker
   480  	exporter      protocol.Exporter
   481  	registerUrl   *common.URL
   482  	subscribeUrl  *common.URL
   483  }
   484  
   485  func (e *exporterChangeableWrapper) UnExport() {
   486  	e.exporter.UnExport()
   487  }
   488  
   489  func (e *exporterChangeableWrapper) SetRegisterUrl(registerUrl *common.URL) {
   490  	e.registerUrl = registerUrl
   491  }
   492  
   493  func (e *exporterChangeableWrapper) SetSubscribeUrl(subscribeUrl *common.URL) {
   494  	e.subscribeUrl = subscribeUrl
   495  }
   496  
   497  func (e *exporterChangeableWrapper) GetInvoker() protocol.Invoker {
   498  	return e.exporter.GetInvoker()
   499  }
   500  
   501  func newExporterChangeableWrapper(originInvoker protocol.Invoker, exporter protocol.Exporter) *exporterChangeableWrapper {
   502  	return &exporterChangeableWrapper{
   503  		originInvoker: originInvoker,
   504  		exporter:      exporter,
   505  	}
   506  }
   507  
   508  type providerConfigurationListener struct {
   509  	registry.BaseConfigurationListener
   510  	overrideListeners *sync.Map
   511  }
   512  
   513  func newProviderConfigurationListener(overrideListeners *sync.Map) *providerConfigurationListener {
   514  	listener := &providerConfigurationListener{}
   515  	listener.overrideListeners = overrideListeners
   516  	listener.InitWith(
   517  		config.GetRootConfig().Application.Name+constant.ConfiguratorSuffix,
   518  		listener,
   519  		extension.GetDefaultConfiguratorFunc(),
   520  	)
   521  	return listener
   522  }
   523  
   524  // Process notified once there's any change happens on the provider config
   525  func (listener *providerConfigurationListener) Process(event *config_center.ConfigChangeEvent) {
   526  	listener.BaseConfigurationListener.Process(event)
   527  	listener.overrideListeners.Range(func(key, value interface{}) bool {
   528  		value.(*overrideSubscribeListener).doOverrideIfNecessary()
   529  		return true
   530  	})
   531  }
   532  
   533  type serviceConfigurationListener struct {
   534  	registry.BaseConfigurationListener
   535  	overrideListener *overrideSubscribeListener
   536  	providerUrl      *common.URL
   537  }
   538  
   539  func newServiceConfigurationListener(overrideListener *overrideSubscribeListener, providerUrl *common.URL) *serviceConfigurationListener {
   540  	listener := &serviceConfigurationListener{overrideListener: overrideListener, providerUrl: providerUrl}
   541  	listener.InitWith(
   542  		providerUrl.ColonSeparatedKey()+constant.ConfiguratorSuffix,
   543  		listener,
   544  		extension.GetDefaultConfiguratorFunc(),
   545  	)
   546  	return listener
   547  }
   548  
   549  // Process notified once there's any change happens on the service config
   550  func (listener *serviceConfigurationListener) Process(event *config_center.ConfigChangeEvent) {
   551  	listener.BaseConfigurationListener.Process(event)
   552  	listener.overrideListener.doOverrideIfNecessary()
   553  }