dubbo.apache.org/dubbo-go/v3@v3.1.1/registry/zookeeper/registry.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 zookeeper
    19  
    20  import (
    21  	"fmt"
    22  	"net/url"
    23  	"path"
    24  	"sync"
    25  	"time"
    26  )
    27  
    28  import (
    29  	"github.com/dubbogo/go-zookeeper/zk"
    30  
    31  	gxzookeeper "github.com/dubbogo/gost/database/kv/zk"
    32  	"github.com/dubbogo/gost/log/logger"
    33  
    34  	perrors "github.com/pkg/errors"
    35  )
    36  
    37  import (
    38  	"dubbo.apache.org/dubbo-go/v3/common"
    39  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    40  	"dubbo.apache.org/dubbo-go/v3/common/extension"
    41  	"dubbo.apache.org/dubbo-go/v3/registry"
    42  	"dubbo.apache.org/dubbo-go/v3/remoting/zookeeper"
    43  )
    44  
    45  func init() {
    46  	extension.SetRegistry("zookeeper", newZkRegistry)
    47  }
    48  
    49  type zkRegistry struct {
    50  	registry.BaseRegistry
    51  	client       *gxzookeeper.ZookeeperClient
    52  	listenerLock sync.Mutex
    53  	listener     *zookeeper.ZkEventListener
    54  	dataListener *RegistryDataListener
    55  	cltLock      sync.Mutex
    56  	zkPath       map[string]int // key = protocol://ip:port/interface
    57  }
    58  
    59  func newZkRegistry(url *common.URL) (registry.Registry, error) {
    60  	var (
    61  		err error
    62  		r   *zkRegistry
    63  	)
    64  	r = &zkRegistry{
    65  		zkPath: make(map[string]int),
    66  	}
    67  	logger.Infof("[Zookeeper Registry] New zookeeper registry with url %+v", url.ToMap())
    68  	r.InitBaseRegistry(url, r)
    69  
    70  	err = zookeeper.ValidateZookeeperClient(r, url.Location)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	r.WaitGroup().Add(1)
    76  	go zookeeper.HandleClientRestart(r)
    77  
    78  	r.listener = zookeeper.NewZkEventListener(r.client)
    79  
    80  	r.dataListener = NewRegistryDataListener()
    81  
    82  	return r, nil
    83  }
    84  
    85  // nolint
    86  type Options struct {
    87  	client *gxzookeeper.ZookeeperClient
    88  }
    89  
    90  // nolint
    91  type Option func(*Options)
    92  
    93  func newMockZkRegistry(url *common.URL, opts ...gxzookeeper.Option) (*zk.TestCluster, *zkRegistry, error) {
    94  	var (
    95  		err error
    96  		r   *zkRegistry
    97  		c   *zk.TestCluster
    98  	)
    99  
   100  	r = &zkRegistry{
   101  		zkPath: make(map[string]int),
   102  	}
   103  	r.InitBaseRegistry(url, r)
   104  	c, r.client, _, err = gxzookeeper.NewMockZookeeperClient("test", 15*time.Second, opts...)
   105  	if err != nil {
   106  		return nil, nil, err
   107  	}
   108  	r.WaitGroup().Add(1)
   109  	go zookeeper.HandleClientRestart(r)
   110  	r.InitListeners()
   111  	return c, r, nil
   112  }
   113  
   114  // InitListeners initializes listeners of zookeeper registry center
   115  func (r *zkRegistry) InitListeners() {
   116  	r.listener = zookeeper.NewZkEventListener(r.client)
   117  	newDataListener := NewRegistryDataListener()
   118  	// should recover if dataListener isn't nil before
   119  	if r.dataListener != nil {
   120  		// close all old listener
   121  		oldDataListener := r.dataListener
   122  		oldDataListener.mutex.Lock()
   123  		defer oldDataListener.mutex.Unlock()
   124  		r.dataListener.closed = true
   125  		recovered := r.dataListener.subscribed
   126  		if len(recovered) > 0 {
   127  			// recover all subscribed url
   128  			for _, oldListener := range recovered {
   129  				var (
   130  					regConfigListener *RegistryConfigurationListener
   131  					ok                bool
   132  				)
   133  				if regConfigListener, ok = oldListener.(*RegistryConfigurationListener); ok {
   134  					regConfigListener.Close()
   135  				}
   136  				newDataListener.SubscribeURL(regConfigListener.subscribeURL, NewRegistryConfigurationListener(r.client, r, regConfigListener.subscribeURL))
   137  				go r.listener.ListenServiceEvent(regConfigListener.subscribeURL, fmt.Sprintf("/%s/%s/"+constant.DefaultCategory, r.URL.GetParam(constant.RegistryGroupKey, "dubbo"), url.QueryEscape(regConfigListener.subscribeURL.Service())), newDataListener)
   138  
   139  			}
   140  		}
   141  	}
   142  	r.dataListener = newDataListener
   143  }
   144  
   145  // CreatePath creates the path in the registry center of zookeeper
   146  func (r *zkRegistry) CreatePath(path string) error {
   147  	err := r.ZkClient().Create(path)
   148  	if err != nil && err != zk.ErrNodeExists {
   149  		return err
   150  	}
   151  	return nil
   152  }
   153  
   154  // DoRegister actually do the register job in the registry center of zookeeper
   155  func (r *zkRegistry) DoRegister(root string, node string) error {
   156  	return r.registerTempZookeeperNode(root, node)
   157  }
   158  
   159  func (r *zkRegistry) DoUnregister(root string, node string) error {
   160  	r.cltLock.Lock()
   161  	defer r.cltLock.Unlock()
   162  	if !r.ZkClient().ZkConnValid() {
   163  		return perrors.Errorf("zk client is not valid.")
   164  	}
   165  	return r.ZkClient().Delete(path.Join(root, node))
   166  }
   167  
   168  // DoSubscribe actually subscribes the provider URL
   169  func (r *zkRegistry) DoSubscribe(conf *common.URL) (registry.Listener, error) {
   170  	return r.getListener(conf)
   171  }
   172  
   173  func (r *zkRegistry) DoUnsubscribe(conf *common.URL) (registry.Listener, error) {
   174  	return r.getCloseListener(conf)
   175  }
   176  
   177  // LoadSubscribeInstances load subscribe instance
   178  func (r *zkRegistry) LoadSubscribeInstances(_ *common.URL, _ registry.NotifyListener) error {
   179  	return nil
   180  }
   181  
   182  // CloseAndNilClient closes listeners and clear client
   183  func (r *zkRegistry) CloseAndNilClient() {
   184  	r.listener.Close()
   185  	r.client.Close()
   186  	r.client = nil
   187  }
   188  
   189  // nolint
   190  func (r *zkRegistry) ZkClient() *gxzookeeper.ZookeeperClient {
   191  	return r.client
   192  }
   193  
   194  // nolint
   195  func (r *zkRegistry) SetZkClient(client *gxzookeeper.ZookeeperClient) {
   196  	r.client = client
   197  }
   198  
   199  // nolint
   200  func (r *zkRegistry) ZkClientLock() *sync.Mutex {
   201  	return &r.cltLock
   202  }
   203  
   204  // CloseListener closes listeners
   205  func (r *zkRegistry) CloseListener() {
   206  	if r.dataListener != nil {
   207  		r.dataListener.Close()
   208  	}
   209  }
   210  
   211  func (r *zkRegistry) registerTempZookeeperNode(root string, node string) error {
   212  	var (
   213  		err    error
   214  		zkPath string
   215  	)
   216  
   217  	r.cltLock.Lock()
   218  	defer r.cltLock.Unlock()
   219  	if r.client == nil {
   220  		return perrors.WithStack(perrors.New("zk client already been closed"))
   221  	}
   222  	logger.Infof("[Zookeeper Registry] Registry instance with root = %s, node = %s", root, node)
   223  	err = r.client.Create(root)
   224  	if err != nil && err != zk.ErrNodeExists {
   225  		logger.Errorf("zk.Create(root{%s}) = err{%v}", root, perrors.WithStack(err))
   226  		return perrors.WithStack(err)
   227  	}
   228  
   229  	// Try to register the node
   230  	zkPath, err = r.client.RegisterTemp(root, node)
   231  	if err == nil {
   232  		return nil
   233  	}
   234  
   235  	// Maybe the node did exist, then we need to delete it first and recreate it
   236  	if perrors.Cause(err) == zk.ErrNodeExists {
   237  		if err = r.client.Delete(zkPath); err == nil {
   238  			_, err = r.client.RegisterTemp(root, node)
   239  		}
   240  
   241  		if err == nil {
   242  			return nil
   243  		}
   244  	}
   245  
   246  	logger.Errorf("Register temp node(root{%s}, node{%s}) = error{%v}", root, node, perrors.WithStack(err))
   247  	return perrors.WithMessagef(err, "RegisterTempNode(root{%s}, node{%s})", root, node)
   248  }
   249  
   250  func (r *zkRegistry) getListener(conf *common.URL) (*RegistryConfigurationListener, error) {
   251  	var zkListener *RegistryConfigurationListener
   252  	dataListener := r.dataListener
   253  	ttl := r.GetParam(constant.RegistryTTLKey, constant.DefaultRegTTL)
   254  	conf.SetParam(constant.RegistryTTLKey, ttl)
   255  	dataListener.mutex.Lock()
   256  	defer dataListener.mutex.Unlock()
   257  	if r.dataListener.subscribed[conf.ServiceKey()] != nil {
   258  		zkListener, _ = r.dataListener.subscribed[conf.ServiceKey()].(*RegistryConfigurationListener)
   259  		if zkListener != nil {
   260  			r.listenerLock.Lock()
   261  			defer r.listenerLock.Unlock()
   262  			if zkListener.isClosed {
   263  				return nil, perrors.New("configListener already been closed")
   264  			} else {
   265  				return zkListener, nil
   266  			}
   267  		}
   268  	}
   269  
   270  	zkListener = NewRegistryConfigurationListener(r.client, r, conf)
   271  	if r.listener == nil {
   272  		r.cltLock.Lock()
   273  		client := r.client
   274  		r.cltLock.Unlock()
   275  		if client == nil {
   276  			return nil, perrors.New("zk connection broken")
   277  		}
   278  
   279  		// new client & listener
   280  		listener := zookeeper.NewZkEventListener(r.client)
   281  
   282  		r.listenerLock.Lock()
   283  		r.listener = listener
   284  		r.listenerLock.Unlock()
   285  	}
   286  
   287  	// Interested register to dataconfig.
   288  	r.dataListener.SubscribeURL(conf, zkListener)
   289  
   290  	go r.listener.ListenServiceEvent(conf, fmt.Sprintf("/%s/%s/"+constant.DefaultCategory, r.URL.GetParam(constant.RegistryGroupKey, "dubbo"), url.QueryEscape(conf.Service())), r.dataListener)
   291  
   292  	return zkListener, nil
   293  }
   294  
   295  func (r *zkRegistry) getCloseListener(conf *common.URL) (*RegistryConfigurationListener, error) {
   296  	var zkListener *RegistryConfigurationListener
   297  	r.dataListener.mutex.Lock()
   298  	configurationListener := r.dataListener.subscribed[conf.ServiceKey()]
   299  	if configurationListener != nil {
   300  		zkListener, _ = configurationListener.(*RegistryConfigurationListener)
   301  		if zkListener != nil && zkListener.isClosed {
   302  			r.dataListener.mutex.Unlock()
   303  			return nil, perrors.New(fmt.Sprintf("configListener for service %s has already been closed", conf.ServiceKey()))
   304  		}
   305  	}
   306  
   307  	if configurationListener := r.dataListener.UnSubscribeURL(conf); configurationListener != nil {
   308  		switch v := configurationListener.(type) {
   309  		case (*RegistryConfigurationListener):
   310  			if v != nil {
   311  				zkListener = v
   312  			}
   313  		}
   314  	}
   315  	r.dataListener.mutex.Unlock()
   316  
   317  	if r.listener == nil {
   318  		return nil, perrors.New("Zookeeper event listener is null, can not close.")
   319  	}
   320  
   321  	return zkListener, nil
   322  }
   323  
   324  func (r *zkRegistry) handleClientRestart() {
   325  	r.WaitGroup().Add(1)
   326  	go zookeeper.HandleClientRestart(r)
   327  }