0
# Service Discovery and Registry
1
2
Apache Dubbo's registry system provides service discovery and registration capabilities with support for multiple backends including ZooKeeper, Nacos, Consul, and etcd. It handles dynamic service management, health monitoring, and provider/consumer coordination.
3
4
## Capabilities
5
6
### Registry Interface
7
8
Core registry interface for service registration and discovery operations.
9
10
```java { .api }
11
/**
12
* Registry interface for service discovery operations
13
*/
14
@SPI("dubbo")
15
public interface Registry extends Node, RegistryService {
16
// Inherits methods from RegistryService and Node interfaces
17
}
18
19
/**
20
* Registry service operations interface
21
*/
22
public interface RegistryService {
23
/**
24
* Register service provider
25
* @param url Service provider URL
26
*/
27
void register(URL url);
28
29
/**
30
* Unregister service provider
31
* @param url Service provider URL
32
*/
33
void unregister(URL url);
34
35
/**
36
* Subscribe to service changes
37
* @param url Consumer URL with subscription parameters
38
* @param listener Notification listener for service changes
39
*/
40
void subscribe(URL url, NotifyListener listener);
41
42
/**
43
* Unsubscribe from service changes
44
* @param url Consumer URL
45
* @param listener Notification listener to remove
46
*/
47
void unsubscribe(URL url, NotifyListener listener);
48
49
/**
50
* Lookup available providers
51
* @param url Service URL to lookup
52
* @return List of available provider URLs
53
*/
54
List<URL> lookup(URL url);
55
}
56
57
/**
58
* Node interface for lifecycle management
59
*/
60
public interface Node {
61
/** Get node URL */
62
URL getUrl();
63
64
/** Check if node is available */
65
boolean isAvailable();
66
67
/** Destroy node and release resources */
68
void destroy();
69
}
70
```
71
72
### Registry Factory
73
74
Factory interface for creating registry instances.
75
76
```java { .api }
77
/**
78
* Registry factory for creating registry instances
79
*/
80
@SPI("dubbo")
81
public interface RegistryFactory {
82
/**
83
* Create registry instance
84
* @param url Registry URL with connection parameters
85
* @return Registry instance
86
*/
87
Registry getRegistry(URL url);
88
}
89
90
/**
91
* Abstract registry factory with common functionality
92
*/
93
public abstract class AbstractRegistryFactory implements RegistryFactory {
94
/** Registry cache by URL */
95
private static final Map<String, Registry> REGISTRIES = new ConcurrentHashMap<>();
96
97
@Override
98
public Registry getRegistry(URL url) {
99
// Normalize URL and get from cache or create new
100
url = URLBuilder.from(url)
101
.setPath(RegistryService.class.getName())
102
.addParameter(INTERFACE_KEY, RegistryService.class.getName())
103
.removeParameters(EXPORT_KEY, REFER_KEY)
104
.build();
105
106
String key = url.toServiceStringWithoutResolving();
107
Registry registry = REGISTRIES.get(key);
108
if (registry != null) {
109
return registry;
110
}
111
112
synchronized (this) {
113
registry = REGISTRIES.get(key);
114
if (registry == null) {
115
registry = createRegistry(url);
116
REGISTRIES.put(key, registry);
117
}
118
}
119
return registry;
120
}
121
122
/** Template method for creating specific registry implementation */
123
protected abstract Registry createRegistry(URL url);
124
}
125
```
126
127
### Notification System
128
129
Event system for handling service provider changes.
130
131
```java { .api }
132
/**
133
* Notification listener for registry changes
134
*/
135
public interface NotifyListener {
136
/**
137
* Handle provider list changes
138
* @param urls Updated list of provider URLs
139
*/
140
void notify(List<URL> urls);
141
}
142
143
/**
144
* Registry event for service changes
145
*/
146
public class RegistryNotification {
147
public enum EventType {
148
REGISTER,
149
UNREGISTER,
150
UPDATE
151
}
152
153
private final EventType eventType;
154
private final URL url;
155
private final long timestamp;
156
157
public RegistryNotification(EventType eventType, URL url) {
158
this.eventType = eventType;
159
this.url = url;
160
this.timestamp = System.currentTimeMillis();
161
}
162
163
public EventType getEventType() { return eventType; }
164
public URL getUrl() { return url; }
165
public long getTimestamp() { return timestamp; }
166
}
167
```
168
169
### ZooKeeper Registry
170
171
ZooKeeper-based service registry implementation.
172
173
```java { .api }
174
/**
175
* ZooKeeper registry implementation
176
*/
177
public class ZookeeperRegistry extends FailbackRegistry {
178
public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter);
179
180
/** Get ZooKeeper client */
181
public ZookeeperClient getZookeeperClient();
182
183
/** Create ZooKeeper path */
184
protected void createPersistent(String path);
185
186
/** Create ephemeral ZooKeeper path */
187
protected void createEphemeral(String path);
188
189
/** Add child listener */
190
protected void addChildListener(String path, ChildListener listener);
191
192
/** Remove child listener */
193
protected void removeChildListener(String path, ChildListener listener);
194
195
@Override
196
protected void doRegister(URL url) {
197
// Create ephemeral sequential node for provider
198
String path = toUrlPath(url);
199
createEphemeral(path);
200
}
201
202
@Override
203
protected void doUnregister(URL url) {
204
// Delete ZooKeeper node
205
String path = toUrlPath(url);
206
zkClient.delete(path);
207
}
208
209
@Override
210
protected void doSubscribe(URL url, NotifyListener listener) {
211
// Subscribe to ZooKeeper path changes
212
String path = toCategoryPath(url);
213
addChildListener(path, new ZookeeperChildListener(listener));
214
}
215
}
216
217
/**
218
* ZooKeeper registry factory
219
*/
220
public class ZookeeperRegistryFactory extends AbstractRegistryFactory {
221
private ZookeeperTransporter zookeeperTransporter;
222
223
@Override
224
protected Registry createRegistry(URL url) {
225
return new ZookeeperRegistry(url, zookeeperTransporter);
226
}
227
}
228
```
229
230
**Usage Examples:**
231
232
```java
233
// ZooKeeper registry configuration
234
RegistryConfig registry = new RegistryConfig();
235
registry.setAddress("zookeeper://127.0.0.1:2181");
236
registry.setUsername("admin");
237
registry.setPassword("password");
238
registry.setTimeout(5000);
239
registry.setSession(60000);
240
241
// Cluster ZooKeeper setup
242
registry.setAddress("zookeeper://127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183");
243
244
// With namespace
245
registry.setAddress("zookeeper://127.0.0.1:2181/dubbo");
246
```
247
248
### Nacos Registry
249
250
Nacos-based service registry implementation for Alibaba's service discovery.
251
252
```java { .api }
253
/**
254
* Nacos registry implementation
255
*/
256
public class NacosRegistry extends FailbackRegistry {
257
public NacosRegistry(URL url, NacosNamingService nacosNamingService);
258
259
/** Get Nacos naming service */
260
public NacosNamingService getNacosNamingService();
261
262
@Override
263
protected void doRegister(URL url) {
264
// Register service instance to Nacos
265
Instance instance = createNacosInstance(url);
266
nacosNamingService.registerInstance(getServiceName(url), instance);
267
}
268
269
@Override
270
protected void doUnregister(URL url) {
271
// Deregister service instance from Nacos
272
Instance instance = createNacosInstance(url);
273
nacosNamingService.deregisterInstance(getServiceName(url), instance);
274
}
275
276
@Override
277
protected void doSubscribe(URL url, NotifyListener listener) {
278
// Subscribe to Nacos service changes
279
String serviceName = getServiceName(url);
280
nacosNamingService.subscribe(serviceName, new NacosEventListener(listener));
281
}
282
283
/** Convert Dubbo URL to Nacos instance */
284
private Instance createNacosInstance(URL url) {
285
Instance instance = new Instance();
286
instance.setIp(url.getHost());
287
instance.setPort(url.getPort());
288
instance.setWeight(url.getParameter(WEIGHT_KEY, DEFAULT_WEIGHT));
289
instance.setHealthy(true);
290
instance.setEnabled(true);
291
instance.setMetadata(new HashMap<>(url.getParameters()));
292
return instance;
293
}
294
}
295
296
/**
297
* Nacos registry factory
298
*/
299
public class NacosRegistryFactory extends AbstractRegistryFactory {
300
@Override
301
protected Registry createRegistry(URL url) {
302
return new NacosRegistry(url, buildNacosNamingService(url));
303
}
304
}
305
```
306
307
**Usage Examples:**
308
309
```java
310
// Nacos registry configuration
311
RegistryConfig registry = new RegistryConfig();
312
registry.setAddress("nacos://127.0.0.1:8848");
313
registry.setGroup("DEFAULT_GROUP");
314
registry.setNamespace("public");
315
316
// With configuration parameters
317
registry.setAddress("nacos://127.0.0.1:8848?namespace=dev&group=dubbo");
318
319
// Authentication
320
registry.setUsername("nacos");
321
registry.setPassword("nacos");
322
```
323
324
### Consul Registry
325
326
HashiCorp Consul integration for service discovery.
327
328
```java { .api }
329
/**
330
* Consul registry implementation
331
*/
332
public class ConsulRegistry extends FailbackRegistry {
333
public ConsulRegistry(URL url, ConsulClient consulClient);
334
335
/** Get Consul client */
336
public ConsulClient getConsulClient();
337
338
@Override
339
protected void doRegister(URL url) {
340
// Register service to Consul
341
NewService service = createConsulService(url);
342
consulClient.agentServiceRegister(service);
343
}
344
345
@Override
346
protected void doUnregister(URL url) {
347
// Deregister service from Consul
348
String serviceId = buildServiceId(url);
349
consulClient.agentServiceDeregister(serviceId);
350
}
351
352
@Override
353
protected void doSubscribe(URL url, NotifyListener listener) {
354
// Watch Consul service changes
355
String serviceName = getServiceName(url);
356
consulClient.healthServicesPass(serviceName, new ConsulQueryCallback(listener));
357
}
358
359
/** Convert Dubbo URL to Consul service */
360
private NewService createConsulService(URL url) {
361
NewService service = new NewService();
362
service.setId(buildServiceId(url));
363
service.setName(getServiceName(url));
364
service.setAddress(url.getHost());
365
service.setPort(url.getPort());
366
service.setTags(buildTags(url));
367
service.setCheck(createHealthCheck(url));
368
return service;
369
}
370
}
371
```
372
373
### Etcd Registry
374
375
etcd-based distributed registry for service discovery.
376
377
```java { .api }
378
/**
379
* Etcd registry implementation
380
*/
381
public class EtcdRegistry extends FailbackRegistry {
382
public EtcdRegistry(URL url, EtcdClient etcdClient);
383
384
@Override
385
protected void doRegister(URL url) {
386
// Register service to etcd with TTL
387
String key = buildEtcdKey(url);
388
String value = url.toFullString();
389
etcdClient.putEphemeral(key, value);
390
}
391
392
@Override
393
protected void doUnregister(URL url) {
394
// Remove service from etcd
395
String key = buildEtcdKey(url);
396
etcdClient.delete(key);
397
}
398
399
@Override
400
protected void doSubscribe(URL url, NotifyListener listener) {
401
// Watch etcd key prefix changes
402
String keyPrefix = buildEtcdKeyPrefix(url);
403
etcdClient.watchPrefix(keyPrefix, new EtcdWatchListener(listener));
404
}
405
}
406
```
407
408
### Multicast Registry
409
410
IP multicast-based registry for local network service discovery.
411
412
```java { .api }
413
/**
414
* Multicast registry for local network discovery
415
*/
416
public class MulticastRegistry extends FailbackRegistry {
417
public MulticastRegistry(URL url);
418
419
/** Get multicast socket */
420
public MulticastSocket getMulticastSocket();
421
422
@Override
423
protected void doRegister(URL url) {
424
// Broadcast registration message
425
String message = REGISTER + url.toFullString();
426
broadcast(message);
427
}
428
429
@Override
430
protected void doUnregister(URL url) {
431
// Broadcast unregistration message
432
String message = UNREGISTER + url.toFullString();
433
broadcast(message);
434
}
435
436
@Override
437
protected void doSubscribe(URL url, NotifyListener listener) {
438
// Add subscription listener
439
subscriptions.put(url, listener);
440
441
// Request current providers
442
String message = SUBSCRIBE + url.toFullString();
443
broadcast(message);
444
}
445
446
/** Broadcast message to multicast group */
447
private void broadcast(String message) {
448
byte[] data = message.getBytes();
449
DatagramPacket packet = new DatagramPacket(data, data.length, multicastAddress, multicastPort);
450
multicastSocket.send(packet);
451
}
452
}
453
```
454
455
**Usage Examples:**
456
457
```java
458
// Multicast registry (development/testing)
459
RegistryConfig registry = new RegistryConfig();
460
registry.setAddress("multicast://224.5.6.7:1234");
461
462
// Custom multicast parameters
463
registry.setAddress("multicast://239.255.255.255:1234?timeout=3000&cleanup=60000");
464
```
465
466
### Registry Configuration
467
468
Advanced registry configuration options and behavior customization.
469
470
```java { .api }
471
/**
472
* Registry configuration constants
473
*/
474
public class RegistryConstants {
475
/** Registry protocol */
476
public static final String REGISTRY_KEY = "registry";
477
public static final String REGISTRY_PROTOCOL = "registry";
478
479
/** Dynamic registration */
480
public static final String DYNAMIC_KEY = "dynamic";
481
public static final boolean DEFAULT_DYNAMIC = true;
482
483
/** Service categories */
484
public static final String CATEGORY_KEY = "category";
485
public static final String PROVIDERS_CATEGORY = "providers";
486
public static final String CONSUMERS_CATEGORY = "consumers";
487
public static final String ROUTERS_CATEGORY = "routers";
488
public static final String CONFIGURATORS_CATEGORY = "configurators";
489
490
/** Registry check */
491
public static final String REGISTRY_CHECK_KEY = "check";
492
493
/** Registry retry period */
494
public static final String REGISTRY_RETRY_PERIOD_KEY = "retry.period";
495
public static final int DEFAULT_REGISTRY_RETRY_PERIOD = 5000;
496
497
/** Registry session timeout */
498
public static final String SESSION_TIMEOUT_KEY = "session";
499
public static final int DEFAULT_SESSION_TIMEOUT = 60000;
500
}
501
```
502
503
### Failback Registry
504
505
Abstract registry with automatic retry capabilities for failed operations.
506
507
```java { .api }
508
/**
509
* Failback registry providing automatic retry for failed operations
510
*/
511
public abstract class FailbackRegistry extends AbstractRegistry {
512
/** Failed registration URLs */
513
private final Set<URL> failedRegistered = new ConcurrentHashSet<>();
514
515
/** Failed unregistration URLs */
516
private final Set<URL> failedUnregistered = new ConcurrentHashSet<>();
517
518
/** Failed subscriptions */
519
private final Map<URL, Set<NotifyListener>> failedSubscribed = new ConcurrentHashMap<>();
520
521
/** Failed unsubscriptions */
522
private final Map<URL, Set<NotifyListener>> failedUnsubscribed = new ConcurrentHashMap<>();
523
524
public FailbackRegistry(URL url) {
525
super(url);
526
// Start retry timer
527
this.retryTimer = new HashedWheelTimer(new NamedThreadFactory("DubboRegistryFailedRetryTimer", true),
528
retryPeriod, TimeUnit.MILLISECONDS, 128);
529
this.retryTimer.newTimeout(this::retry, retryPeriod, TimeUnit.MILLISECONDS);
530
}
531
532
@Override
533
public void register(URL url) {
534
super.register(url);
535
failedRegistered.remove(url);
536
failedUnregistered.remove(url);
537
try {
538
doRegister(url);
539
} catch (Exception e) {
540
failedRegistered.add(url);
541
throw new RpcException("Failed to register " + url, e);
542
}
543
}
544
545
@Override
546
public void unregister(URL url) {
547
super.unregister(url);
548
failedRegistered.remove(url);
549
failedUnregistered.remove(url);
550
try {
551
doUnregister(url);
552
} catch (Exception e) {
553
failedUnregistered.add(url);
554
throw new RpcException("Failed to unregister " + url, e);
555
}
556
}
557
558
/** Retry failed operations */
559
private void retry(Timeout timeout) {
560
// Retry failed registrations
561
if (!failedRegistered.isEmpty()) {
562
Set<URL> failed = new HashSet<>(failedRegistered);
563
for (URL url : failed) {
564
try {
565
doRegister(url);
566
failedRegistered.remove(url);
567
} catch (Exception e) {
568
// Keep in failed set for next retry
569
}
570
}
571
}
572
573
// Schedule next retry
574
retryTimer.newTimeout(this::retry, retryPeriod, TimeUnit.MILLISECONDS);
575
}
576
577
/** Template method for actual registration */
578
protected abstract void doRegister(URL url);
579
580
/** Template method for actual unregistration */
581
protected abstract void doUnregister(URL url);
582
583
/** Template method for actual subscription */
584
protected abstract void doSubscribe(URL url, NotifyListener listener);
585
586
/** Template method for actual unsubscription */
587
protected abstract void doUnsubscribe(URL url, NotifyListener listener);
588
}
589
```
590
591
### Service Instance Management
592
593
Modern service instance-based discovery for cloud-native environments.
594
595
```java { .api }
596
/**
597
* Service instance representation
598
*/
599
public interface ServiceInstance extends Serializable {
600
/** Get service name */
601
String getServiceName();
602
603
/** Get instance host */
604
String getHost();
605
606
/** Get instance port */
607
int getPort();
608
609
/** Check if instance is enabled */
610
boolean isEnabled();
611
612
/** Check if instance is healthy */
613
boolean isHealthy();
614
615
/** Get instance metadata */
616
Map<String, String> getMetadata();
617
618
/** Get instance ID */
619
String getId();
620
}
621
622
/**
623
* Service discovery interface for cloud-native service mesh
624
*/
625
@SPI("zookeeper")
626
public interface ServiceDiscovery extends Closeable {
627
/**
628
* Initialize service discovery
629
* @throws Exception if initialization fails
630
*/
631
void initialize(URL registryURL) throws Exception;
632
633
/**
634
* Register service instance
635
* @param serviceInstance Service instance to register
636
* @throws RuntimeException if registration fails
637
*/
638
void register(ServiceInstance serviceInstance) throws RuntimeException;
639
640
/**
641
* Update service instance
642
* @param serviceInstance Service instance to update
643
* @throws RuntimeException if update fails
644
*/
645
void update(ServiceInstance serviceInstance) throws RuntimeException;
646
647
/**
648
* Unregister service instance
649
* @param serviceInstance Service instance to unregister
650
* @throws RuntimeException if unregistration fails
651
*/
652
void unregister(ServiceInstance serviceInstance) throws RuntimeException;
653
654
/**
655
* Get service instances by service name
656
* @param serviceName Service name
657
* @return Set of service instances
658
* @throws RuntimeException if lookup fails
659
*/
660
Set<ServiceInstance> getInstances(String serviceName) throws RuntimeException;
661
662
/**
663
* Get all service names
664
* @return Set of service names
665
* @throws RuntimeException if lookup fails
666
*/
667
Set<String> getServices() throws RuntimeException;
668
669
/**
670
* Add service instance change listener
671
* @param serviceName Service name to watch
672
* @param listener Change listener
673
* @throws RuntimeException if listener addition fails
674
*/
675
void addServiceInstancesChangedListener(String serviceName,
676
ServiceInstancesChangedListener listener)
677
throws RuntimeException;
678
}
679
```
680
681
**Usage Examples:**
682
683
```java
684
// Complete registry setup with multiple backends
685
DubboBootstrap bootstrap = DubboBootstrap.getInstance();
686
687
// Primary registry (ZooKeeper)
688
RegistryConfig primaryRegistry = new RegistryConfig();
689
primaryRegistry.setAddress("zookeeper://127.0.0.1:2181");
690
primaryRegistry.setGroup("production");
691
692
// Backup registry (Nacos)
693
RegistryConfig backupRegistry = new RegistryConfig();
694
backupRegistry.setAddress("nacos://127.0.0.1:8848");
695
backupRegistry.setGroup("production");
696
backupRegistry.setBackup(true);
697
698
bootstrap.registries(Arrays.asList(primaryRegistry, backupRegistry));
699
700
// Service with multiple registry support
701
ServiceConfig<GreeterService> service = new ServiceConfig<>();
702
service.setInterface(GreeterService.class);
703
service.setRef(new GreeterServiceImpl());
704
service.setRegistry(primaryRegistry);
705
service.export();
706
```