0
# Distributed Locking
1
2
Distributed locking capabilities for coordination and synchronization across microservices. Supports lock expiration, try-lock operations, and remote lock management with automatic cleanup.
3
4
## Capabilities
5
6
### Basic Lock Operations
7
8
Core distributed locking operations for synchronization across microservices.
9
10
```java { .api }
11
public interface LockService {
12
// Acquire distributed lock (blocking)
13
Boolean lock(LockInstance instance) throws NacosException;
14
15
// Release distributed lock
16
Boolean unLock(LockInstance instance) throws NacosException;
17
18
// Try to acquire lock without blocking (non-blocking)
19
Boolean remoteTryLock(LockInstance instance) throws NacosException;
20
21
// Release lock remotely
22
Boolean remoteReleaseLock(LockInstance instance) throws NacosException;
23
24
// Shutdown the lock service
25
void shutdown() throws NacosException;
26
}
27
```
28
29
#### Usage Examples
30
31
```java
32
import com.alibaba.nacos.api.lock.LockService;
33
import com.alibaba.nacos.api.lock.NacosLockFactory;
34
import com.alibaba.nacos.api.lock.model.LockInstance;
35
import com.alibaba.nacos.api.exception.NacosException;
36
37
// Create lock service
38
Properties props = new Properties();
39
props.setProperty("serverAddr", "localhost:8848");
40
LockService lockService = NacosLockFactory.createLockService(props);
41
42
// Create lock instance
43
LockInstance lockInstance = new LockInstance();
44
lockInstance.setKey("order-processing-lock");
45
lockInstance.setExpiredTime(30000L); // 30 seconds in milliseconds
46
47
try {
48
// Acquire lock
49
Boolean acquired = lockService.lock(lockInstance);
50
51
if (acquired) {
52
System.out.println("Lock acquired successfully");
53
54
// Perform critical section operations
55
processOrder();
56
57
} else {
58
System.out.println("Failed to acquire lock");
59
}
60
61
} finally {
62
// Always release lock in finally block
63
lockService.unLock(lockInstance);
64
}
65
```
66
67
### Non-blocking Lock Operations
68
69
Try-lock operations that don't block if the lock is unavailable.
70
71
```java
72
// Non-blocking lock attempt
73
LockInstance lockInstance = new LockInstance();
74
lockInstance.setKey("cache-update-lock");
75
lockInstance.setExpiredTime(60000L); // 60 seconds in milliseconds
76
77
// Try to acquire lock without blocking
78
Boolean acquired = lockService.remoteTryLock(lockInstance);
79
80
if (acquired) {
81
try {
82
// Perform cache update
83
updateCache();
84
85
} finally {
86
// Release lock
87
lockService.remoteReleaseLock(lockInstance);
88
}
89
} else {
90
System.out.println("Another process is updating cache, skipping...");
91
}
92
```
93
94
### Lock with Automatic Expiration
95
96
Locks with built-in expiration to prevent deadlocks from process failures.
97
98
```java
99
// Lock with automatic expiration (prevents deadlocks)
100
String lockKey = "database-migration-lock";
101
String lockValue = "migration-" + UUID.randomUUID().toString();
102
103
// Lock expires after 300 seconds (5 minutes)
104
boolean acquired = lockService.lock(lockKey, lockValue, 300);
105
106
if (acquired) {
107
try {
108
// Perform long-running database migration
109
runDatabaseMigration();
110
111
} catch (Exception e) {
112
System.err.println("Migration failed: " + e.getMessage());
113
// Lock will automatically expire if process crashes
114
115
} finally {
116
// Explicitly release lock when done
117
lockService.unLock(lockKey, lockValue);
118
}
119
}
120
```
121
122
### Distributed Coordination Patterns
123
124
Common patterns for distributed coordination using locks.
125
126
#### Mutual Exclusion Pattern
127
128
```java
129
public class OrderProcessor {
130
private final LockService lockService;
131
private final String instanceId;
132
133
public OrderProcessor(LockService lockService) {
134
this.lockService = lockService;
135
this.instanceId = "processor-" + InetAddress.getLocalHost().getHostName();
136
}
137
138
public void processOrderBatch(List<Order> orders) throws NacosException {
139
String lockKey = "order-batch-processing";
140
141
// Ensure only one instance processes orders at a time
142
boolean acquired = lockService.lock(lockKey, instanceId, 120); // 2 minutes
143
144
if (acquired) {
145
try {
146
System.out.println("Processing " + orders.size() + " orders...");
147
148
for (Order order : orders) {
149
processOrder(order);
150
}
151
152
System.out.println("Batch processing completed");
153
154
} finally {
155
lockService.unLock(lockKey, instanceId);
156
}
157
} else {
158
System.out.println("Another instance is processing orders");
159
}
160
}
161
}
162
```
163
164
#### Leader Election Pattern
165
166
```java
167
public class LeaderElection {
168
private final LockService lockService;
169
private final String nodeId;
170
private volatile boolean isLeader = false;
171
172
public LeaderElection(LockService lockService, String nodeId) {
173
this.lockService = lockService;
174
this.nodeId = nodeId;
175
}
176
177
public void tryBecomeLeader() {
178
String leaderLock = "cluster-leader-election";
179
180
try {
181
// Try to become leader (non-blocking)
182
boolean becameLeader = lockService.remoteTryLock(leaderLock, nodeId, 60);
183
184
if (becameLeader && !isLeader) {
185
isLeader = true;
186
System.out.println("Node " + nodeId + " became leader");
187
startLeaderTasks();
188
189
} else if (!becameLeader && isLeader) {
190
isLeader = false;
191
System.out.println("Node " + nodeId + " lost leadership");
192
stopLeaderTasks();
193
}
194
195
} catch (NacosException e) {
196
System.err.println("Leader election failed: " + e.getMessage());
197
}
198
}
199
200
public void resignLeadership() {
201
if (isLeader) {
202
try {
203
lockService.remoteReleaseLock("cluster-leader-election", nodeId);
204
isLeader = false;
205
stopLeaderTasks();
206
207
} catch (NacosException e) {
208
System.err.println("Failed to resign leadership: " + e.getMessage());
209
}
210
}
211
}
212
}
213
```
214
215
#### Resource Pool Management
216
217
```java
218
public class ResourcePoolManager {
219
private final LockService lockService;
220
private final String poolName;
221
222
public ResourcePoolManager(LockService lockService, String poolName) {
223
this.lockService = lockService;
224
this.poolName = poolName;
225
}
226
227
public Resource acquireResource(String resourceId) throws NacosException {
228
String lockKey = poolName + "-resource-" + resourceId;
229
String lockValue = "consumer-" + Thread.currentThread().getId();
230
231
// Try to acquire resource for 30 seconds
232
boolean acquired = lockService.remoteTryLock(lockKey, lockValue, 30);
233
234
if (acquired) {
235
return new Resource(resourceId, () -> {
236
try {
237
lockService.remoteReleaseLock(lockKey, lockValue);
238
} catch (NacosException e) {
239
System.err.println("Failed to release resource: " + e.getMessage());
240
}
241
});
242
} else {
243
throw new ResourceUnavailableException("Resource " + resourceId + " is in use");
244
}
245
}
246
}
247
```
248
249
## Types
250
251
### Lock Instance Model
252
253
```java { .api }
254
public class LockInstance implements Serializable {
255
private String key;
256
private Long expiredTime;
257
private Map<String, ? extends Serializable> params;
258
private String lockType;
259
260
// Constructors
261
public LockInstance();
262
public LockInstance(String key, Long expiredTime, String lockType);
263
264
// Lock identification
265
public String getKey();
266
public void setKey(String key);
267
268
public String getLockType();
269
public void setLockType(String lockType);
270
271
// Expiration management
272
public Long getExpiredTime();
273
public void setExpiredTime(Long expiredTime);
274
275
// Additional parameters
276
public Map<String, ? extends Serializable> getParams();
277
public void setParams(Map<String, ? extends Serializable> params);
278
279
// Utility methods
280
public Boolean lock(LockService lockService) throws NacosException;
281
public Boolean unLock(LockService lockService) throws NacosException;
282
}
283
```
284
285
### Lock Operation Types
286
287
```java { .api }
288
public enum LockOperationEnum {
289
LOCK("lock"),
290
UNLOCK("unlock"),
291
TRY_LOCK("tryLock"),
292
RELEASE_LOCK("releaseLock");
293
294
private final String operation;
295
296
LockOperationEnum(String operation) {
297
this.operation = operation;
298
}
299
300
public String getOperation();
301
}
302
```
303
304
### Lock Configuration
305
306
```java { .api }
307
// Lock-specific property keys
308
public class LockPropertyKeyConst {
309
// Connection settings
310
public static final String LOCK_SERVER_ADDR = "lockServerAddr";
311
public static final String LOCK_NAMESPACE = "lockNamespace";
312
313
// Timeout settings
314
public static final String LOCK_TIMEOUT = "lockTimeout";
315
public static final String LOCK_RETRY_INTERVAL = "lockRetryInterval";
316
public static final String LOCK_MAX_RETRY = "lockMaxRetry";
317
318
// Default expiration
319
public static final String DEFAULT_LOCK_EXPIRATION = "defaultLockExpiration";
320
321
// Performance tuning
322
public static final String LOCK_THREAD_POOL_SIZE = "lockThreadPoolSize";
323
public static final String LOCK_HEARTBEAT_INTERVAL = "lockHeartbeatInterval";
324
}
325
```
326
327
### Lock Exceptions
328
329
```java { .api }
330
// Lock-specific exceptions
331
public class LockException extends NacosException {
332
public static final int LOCK_ALREADY_HELD = 10001;
333
public static final int LOCK_NOT_FOUND = 10002;
334
public static final int LOCK_EXPIRED = 10003;
335
public static final int LOCK_INVALID_OWNER = 10004;
336
337
public LockException(int errCode, String errMsg);
338
public LockException(int errCode, String errMsg, Throwable cause);
339
}
340
```
341
342
## Best Practices
343
344
### Lock Key Naming
345
346
Use descriptive, hierarchical lock keys to avoid conflicts:
347
348
```java
349
// Good: descriptive hierarchy
350
"order-processing-batch-daily"
351
"cache-update-user-profiles"
352
"database-migration-v2.1"
353
"leader-election-notification-service"
354
355
// Bad: generic names
356
"lock1"
357
"process"
358
"update"
359
```
360
361
### Lock Value Generation
362
363
Use unique, identifiable lock values:
364
365
```java
366
// Include instance/thread identification
367
String lockValue = instanceId + "-" + Thread.currentThread().getId() + "-" + System.currentTimeMillis();
368
369
// Or use UUID for uniqueness
370
String lockValue = UUID.randomUUID().toString();
371
```
372
373
### Expiration Time Guidelines
374
375
Set appropriate expiration times based on operation duration:
376
377
```java
378
// Short operations (few seconds)
379
lockService.lock(lockKey, lockValue, 30);
380
381
// Medium operations (minutes)
382
lockService.lock(lockKey, lockValue, 300);
383
384
// Long operations (hours) - consider breaking into smaller chunks
385
lockService.lock(lockKey, lockValue, 3600);
386
```
387
388
### Error Handling
389
390
Always handle lock failures gracefully:
391
392
```java
393
try {
394
boolean acquired = lockService.lock(lockKey, lockValue, 60);
395
396
if (!acquired) {
397
// Handle inability to acquire lock
398
scheduleRetry();
399
return;
400
}
401
402
// Perform critical section
403
performCriticalOperation();
404
405
} catch (NacosException e) {
406
// Handle network or server errors
407
handleLockError(e);
408
409
} finally {
410
// Always attempt to release lock
411
try {
412
lockService.unLock(lockKey, lockValue);
413
} catch (NacosException e) {
414
// Log but don't fail - lock will expire
415
logger.warn("Failed to release lock: " + e.getMessage());
416
}
417
}
418
```