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 }