Redis看门狗架构实战:分布式锁续期机制、Redisson实现与企业级高可用解决方案

一、看门狗机制概述

1.1 分布式锁的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
分布式锁常见问题:
锁过期:
- 设置过期时间防止死锁
- 但任务执行时间可能超过过期时间
- 导致锁被错误释放

任务执行时间不确定:
- 网络延迟
- 业务处理时间
- 数据库操作耗时

解决方案:
- 看门狗自动续期
- 后台线程定期续期
- 保持任务执行期间的锁有效性

1.2 看门狗机制原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
看门狗工作机制:
获取锁成功:
- 设置锁过期时间
- 启动看门狗定时器
- 开始后台续期

续期逻辑:
- 定时检查锁是否仍被持有
- 如果持有,自动延长过期时间
- 保持锁的有效性

任务完成:
- 释放锁
- 停止看门狗定时器
- 清理资源

异常处理:
- 客户端宕机
- 任务执行失败
- 自动过期释放

二、Redis分布式锁基础

2.1 原生实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
-- 加锁
-- redis-cli
-- 使用SET命令的NX和EX参数
SET lock:user:123 "unique_value" NX EX 10

-- Lua脚本实现锁的原子操作
-- lock.lua
local key = KEYS[1]
local value = ARGV[1]
local expire = tonumber(ARGV[2])
local result = redis.call('set', key, value, 'NX', 'EX', expire)
if result then
return 1
else
return 0
end

-- 解锁脚本
-- unlock.lua
local key = KEYS[1]
local value = ARGV[1]
local currentValue = redis.call('get', key)
if currentValue == value then
redis.call('del', key)
return 1
else
return 0
end

-- 续期脚本
-- renew.lua
local key = KEYS[1]
local value = ARGV[1]
local expire = tonumber(ARGV[2])
local currentValue = redis.call('get', key)
if currentValue == value then
redis.call('expire', key, expire)
return 1
else
return 0
end

2.2 Java原生实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// RedisDistributedLock.java
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class RedisDistributedLock {
private JedisPool jedisPool;
private String lockKey;
private String lockValue;
private int expireTime;
private Thread renewalThread;
private volatile boolean isRunning = true;

// Lua脚本
private static final String LOCK_SCRIPT =
"if redis.call('set', KEYS[1], ARGV[1], 'NX', 'EX', ARGV[2]) then " +
" return 1 " +
"else " +
" return 0 " +
"end";

private static final String UNLOCK_SCRIPT =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
" return redis.call('del', KEYS[1]) " +
"else " +
" return 0 " +
"end";

private static final String RENEWAL_SCRIPT =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
" return redis.call('expire', KEYS[1], ARGV[2]) " +
"else " +
" return 0 " +
"end";

public RedisDistributedLock(JedisPool jedisPool, String lockKey, int expireTime) {
this.jedisPool = jedisPool;
this.lockKey = lockKey;
this.expireTime = expireTime;
}

/**
* 尝试获取锁
*/
public boolean tryLock(long timeout) throws InterruptedException {
lockValue = UUID.randomUUID().toString();
long start = System.currentTimeMillis();

while (System.currentTimeMillis() - start < timeout) {
try (Jedis jedis = jedisPool.getResource()) {
// 使用Lua脚本原子性加锁
Long result = (Long) jedis.eval(LOCK_SCRIPT,
Collections.singletonList(lockKey),
Arrays.asList(lockValue, String.valueOf(expireTime))
);

if (result == 1) {
// 获取锁成功,启动看门狗
startWatchdog();
return true;
}
}

Thread.sleep(10);
}

return false;
}

/**
* 启动看门狗线程
*/
private void startWatchdog() {
renewalThread = new Thread(() -> {
while (isRunning) {
try {
Thread.sleep(expireTime * 1000 / 3); // 每过期时间的1/3续期一次

try (Jedis jedis = jedisPool.getResource()) {
Long result = (Long) jedis.eval(RENEWAL_SCRIPT,
Collections.singletonList(lockKey),
Arrays.asList(lockValue, String.valueOf(expireTime))
);

if (result == 0) {
// 续期失败,锁可能已被释放
System.out.println("续期失败,停止看门狗");
break;
}
}
} catch (Exception e) {
e.printStackTrace();
break;
}
}
});

renewalThread.setDaemon(true);
renewalThread.start();
}

/**
* 释放锁
*/
public void unlock() {
isRunning = false;

if (renewalThread != null) {
renewalThread.interrupt();
}

try (Jedis jedis = jedisPool.getResource()) {
jedis.eval(UNLOCK_SCRIPT,
Collections.singletonList(lockKey),
Collections.singletonList(lockValue)
);
}
}
}

三、Redisson看门狗实现

3.1 Redisson介绍

1
2
3
4
5
6
7
8
<!-- pom.xml -->
<dependencies>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.20.1</version>
</dependency>
</dependencies>

3.2 Redisson分布式锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// RedissonLockExample.java
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class RedissonLockExample {

private RedissonClient redisson;

public void initRedisson() {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379")
.setPassword("your_password")
.setDatabase(0);

redisson = Redisson.create(config);
}

/**
* 基本分布式锁
*/
public void basicLock() {
RLock lock = redisson.getLock("myLock");

try {
// 尝试加锁,最多等待100秒,锁过期30秒后自动释放
boolean isLock = lock.tryLock(100, 30, TimeUnit.SECONDS);

if (isLock) {
try {
// 业务逻辑
doSomething();
} finally {
// 释放锁
lock.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}

/**
* 使用看门狗的锁(不设置leaseTime参数)
*/
public void lockWithWatchdog() {
RLock lock = redisson.getLock("myLock");

try {
// 不指定leaseTime,使用默认值-1,启用看门狗
// 看门狗会每10秒续期一次,leaseTime默认30秒
boolean isLock = lock.tryLock(100, TimeUnit.SECONDS);

if (isLock) {
try {
// 业务逻辑
doSomething();
} finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}

/**
* 公平锁
*/
public void fairLock() {
RLock fairLock = redisson.getFairLock("myFairLock");

try {
fairLock.lock();
try {
doSomething();
} finally {
fairLock.unlock();
}
}
}

/**
* 读写锁
*/
public void readWriteLock() {
RReadWriteLock rwLock = redisson.getReadWriteLock("myRWLock");
RLock readLock = rwLock.readLock();
RLock writeLock = rwLock.writeLock();

// 读锁
readLock.lock();
try {
// 读取操作
readData();
} finally {
readLock.unlock();
}

// 写锁
writeLock.lock();
try {
// 写入操作
writeData();
} finally {
writeLock.unlock();
}
}

/**
* 联锁(MultiLock)
*/
public void multiLock() {
RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
RLock lock3 = redisson.getLock("lock3");

RLock multiLock = redisson.getMultiLock(lock1, lock2, lock3);

try {
multiLock.lock();
try {
doSomething();
} finally {
multiLock.unlock();
}
}
}

private void doSomething() {
// 业务逻辑
System.out.println("执行业务逻辑...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}

private void readData() {
System.out.println("读取数据...");
}

private void writeData() {
System.out.println("写入数据...");
}

public void shutdown() {
if (redisson != null) {
redisson.shutdown();
}
}
}

3.3 Redisson配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// RedissonConfig.java
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RedissonConfig {

@Bean
public RedissonClient redissonClient() {
Config config = new Config();

// 单机模式
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379")
.setPassword("your_password")
.setConnectionMinimumIdleSize(10)
.setConnectionPoolSize(64)
.setConnectTimeout(3000)
.setTimeout(3000)
.setRetryAttempts(3)
.setRetryInterval(1500)
.setDatabase(0);

// 集群模式
// config.useClusterServers()
// .addNodeAddress("redis://127.0.0.1:7001")
// .addNodeAddress("redis://127.0.0.1:7002");

// 哨兵模式
// config.useSentinelServers()
// .setMasterName("mymaster")
// .addSentinelAddress("redis://127.0.0.1:26379");

return Redisson.create(config);
}

@Bean
public RedissonClient redissonClientCustom() {
Config config = new Config();

// 自定义看门狗时间
config.setLockWatchdogTimeout(10000); // 10秒

// 线程池配置
config.setThreads(16);
config.setNettyThreads(32);

config.useSingleServer()
.setAddress("redis://127.0.0.1:6379");

return Redisson.create(config);
}
}

四、看门狗机制深度解析

4.1 看门狗核心逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// Redisson看门狗实现原理(简化版)
public class WatchdogScheduler {

// 看门狗默认超时时间:30秒
public static final long DEFAULT_LOCK_WATCHDOG_TIMEOUT = 30000L;

// 续期间隔:超时时间的1/3
private long renewalInterval = DEFAULT_LOCK_WATCHDOG_TIMEOUT / 3;

private ScheduledExecutorService scheduler;
private String lockKey;
private String lockValue;
private RedissonClient redisson;

public WatchdogScheduler(RedissonClient redisson, String lockKey, String lockValue) {
this.redisson = redisson;
this.lockKey = lockKey;
this.lockValue = lockValue;
this.scheduler = Executors.newScheduledThreadPool(1);
}

/**
* 启动看门狗
*/
public void schedule() {
scheduler.scheduleAtFixedRate(() -> {
try {
// 获取锁的所有者信息
Long ttl = getTTL();

if (ttl != null && ttl > 0) {
// 锁仍然存在,执行续期
expireAsync(lockValue, DEFAULT_LOCK_WATCHDOG_TIMEOUT);
} else {
// 锁已过期,停止看门狗
cancel();
}
} catch (Exception e) {
e.printStackTrace();
cancel();
}
}, renewalInterval, renewalInterval, TimeUnit.MILLISECONDS);
}

/**
* 异步续期
*/
private void expireAsync(String value, long timeout) {
// Lua脚本续期
String script =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
" return redis.call('pexpire', KEYS[1], ARGV[2]) " +
"else " +
" return 0 " +
"end";

redisson.getScript().eval(
Mode.READ,
script,
Collections.singletonList(lockKey),
Lists.newArrayList(value, String.valueOf(timeout))
);
}

private Long getTTL() {
// 实现TTL获取逻辑
return null;
}

public void cancel() {
scheduler.shutdown();
}
}

4.2 续期流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
续期流程详解:
1. 获取锁成功:
- 返回锁对象
- 创建看门狗任务
- 加入调度队列

2. 定期检查:
- 每10秒检查一次
- 判断锁是否仍被持有
- 判断任务是否完成

3. 续期操作:
- 使用Lua脚本原子性续期
- 延长锁的过期时间
- 返回续期结果

4. 任务完成:
- 手动调用unlock
- 停止看门狗任务
- 释放资源

5. 异常处理:
- 续期失败(锁已被释放)
- 客户端断连
- 服务器故障

五、高级特性

5.1 锁的超时时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 指定leaseTime,不使用看门狗
public void lockWithoutWatchdog() {
RLock lock = redisson.getLock("myLock");

try {
// leaseTime指定为30秒,锁会在30秒后自动释放
// 不使用看门狗机制
boolean isLock = lock.tryLock(100, 30, TimeUnit.SECONDS);

if (isLock) {
try {
// 业务逻辑
doSomething();
} finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}

// 使用看门狗(默认)
public void lockWithWatchdogDefault() {
RLock lock = redisson.getLock("myLock");

try {
// 不指定leaseTime或指定为-1,启用看门狗
// 看门狗每10秒续期一次
boolean isLock = lock.tryLock(100, TimeUnit.SECONDS);

if (isLock) {
try {
doSomething();
} finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}

5.2 自定义看门狗时间

1
2
3
4
5
6
7
8
9
10
11
12
13
// RedissonConfig.java - 自定义看门狗超时时间
@Bean
public RedissonClient redissonClient() {
Config config = new Config();

// 自定义看门狗超时时间为60秒
config.setLockWatchdogTimeout(60000);

config.useSingleServer()
.setAddress("redis://127.0.0.1:6379");

return Redisson.create(config);
}

5.3 信号量(Semaphore)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void semaphore() {
RSemaphore semaphore = redisson.getSemaphore("mySemaphore");

// 设置许可数量
semaphore.trySetPermits(5);

try {
// 获取许可
semaphore.acquire();

// 业务逻辑
doSomething();

// 释放许可
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

5.4 计数器(CountDownLatch)

1
2
3
4
5
6
7
8
9
10
11
12
public void countDownLatch() {
RCountDownLatch latch = redisson.getCountDownLatch("myCountDownLatch");

// 设置计数
latch.trySetCount(10);

// 等待所有任务完成
latch.await();

// 或者在其他地方计数减1
latch.countDown();
}

六、实际应用场景

6.1 分布式任务调度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// DistributedTaskScheduler.java
@Service
public class DistributedTaskScheduler {

@Autowired
private RedissonClient redissonClient;

/**
* 分布式定时任务
*/
@Scheduled(cron = "0 0 2 * * ?")
public void executeDistributedTask() {
RLock lock = redissonClient.getLock("task:schedule:data-sync");

try {
// 获取锁,最多等待10秒
if (lock.tryLock(10, TimeUnit.SECONDS)) {
try {
// 执行定时任务
syncData();
} finally {
lock.unlock();
}
} else {
System.out.println("其他节点正在执行任务");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}

private void syncData() {
System.out.println("开始同步数据...");
// 执行数据同步逻辑
}
}

6.2 防止重复提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// IdempotentController.java
@RestController
public class IdempotentController {

@Autowired
private RedissonClient redissonClient;

/**
* 幂等性控制
*/
@PostMapping("/submit")
public ResponseEntity submit(@RequestParam String requestId) {
RLock lock = redissonClient.getLock("submit:lock:" + requestId);

try {
// 尝试获取锁,最多等待1秒
if (lock.tryLock(1, 10, TimeUnit.SECONDS)) {
try {
// 检查是否已处理
if (isProcessed(requestId)) {
return ResponseEntity.ok("请求已处理");
}

// 执行业务逻辑
processRequest(requestId);

// 标记已处理
markAsProcessed(requestId);

return ResponseEntity.ok("处理成功");
} finally {
lock.unlock();
}
} else {
return ResponseEntity.status(409).body("请求正在处理中");
}
} catch (InterruptedException e) {
return ResponseEntity.status(500).body("处理失败");
}
}

private boolean isProcessed(String requestId) {
// 检查请求是否已处理
return false;
}

private void processRequest(String requestId) {
// 处理请求
}

private void markAsProcessed(String requestId) {
// 标记为已处理
}
}

七、高可用配置

7.1 Redis Sentinel配置

1
2
3
4
5
6
7
8
9
10
11
12
13
// Redis Sentinel模式
Config config = new Config();

config.useSentinelServers()
.setMasterName("mymaster")
.addSentinelAddress("redis://127.0.0.1:26379")
.addSentinelAddress("redis://127.0.0.1:26380")
.addSentinelAddress("redis://127.0.0.1:26381")
.setCheckSentinelsList(true)
.setDatabase(0)
.setPassword("your_password");

RedissonClient redisson = Redisson.create(config);

7.2 Redis Cluster配置

1
2
3
4
5
6
7
8
9
10
11
// Redis Cluster模式
Config config = new Config();

config.useClusterServers()
.setScanInterval(2000)
.addNodeAddress("redis://127.0.0.1:7001")
.addNodeAddress("redis://127.0.0.1:7002")
.addNodeAddress("redis://127.0.0.1:7003")
.setPassword("your_password");

RedissonClient redisson = Redisson.create(config);

7.3 多主模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// MultiLock - 多个Redis实例
RLock lock1 = redisson1.getLock("myLock");
RLock lock2 = redisson2.getLock("myLock");
RLock lock3 = redisson3.getLock("myLock");

RLock multiLock = redisson1.getMultiLock(lock1, lock2, lock3);

try {
multiLock.lock();
try {
// 业务逻辑
doSomething();
} finally {
multiLock.unlock();
}
}

八、监控和诊断

8.1 锁监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// LockMonitor.java
@Component
public class LockMonitor {

@Autowired
private RedissonClient redissonClient;

/**
* 监控锁状态
*/
public void monitorLocks() {
RPatternTopic patternTopic = (RPatternTopic) redissonClient.getPatternTopic("lock:*");
patternTopic.addListener(String.class, new PatternMessageListener<String>() {
@Override
public void onMessage(CharSequence pattern, CharSequence channel, String message) {
System.out.println("Lock event: " + message);
}
});
}

/**
* 查看锁信息
*/
public void inspectLock(String lockName) {
RLock lock = redissonClient.getLock(lockName);

System.out.println("Lock name: " + lockName);
System.out.println("Is locked: " + lock.isLocked());
System.out.println("Is held by current thread: " + lock.isHeldByCurrentThread());
System.out.println("Remaining lease time: " + lock.remainTimeToLive());
}
}

8.2 指标收集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// RedissonMetrics.java
@Component
public class RedissonMetrics {

@Autowired
private RedissonClient redissonClient;

/**
* 收集Redis指标
*/
public Map<String, Object> collectMetrics() {
Map<String, Object> metrics = new HashMap<>();

Collection<MasterSlaveEntry> entries = ((Redisson) redissonClient)
.getConnectionManager()
.getSlaveEntries();

for (MasterSlaveEntry entry : entries) {
RedisClient client = entry.getClient();
// 收集客户端信息
metrics.put("client", client.toString());
}

return metrics;
}
}

九、最佳实践

9.1 锁的最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// 1. 总是使用try-finally确保释放锁
public void bestPractice1() {
RLock lock = redissonClient.getLock("myLock");
try {
if (lock.tryLock(100, TimeUnit.SECONDS)) {
try {
doSomething();
} finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}

// 2. 避免业务代码执行过长
public void bestPractice2() {
RLock lock = redissonClient.getLock("myLock");
try {
if (lock.tryLock(100, 10, TimeUnit.SECONDS)) {
// 快速执行业务逻辑,避免长时间占用锁
quickOperation();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}

// 3. 使用合理的锁超时时间
public void bestPractice3() {
RLock lock = redissonClient.getLock("myLock");

// 合理设置等待时间和锁超时时间
try {
boolean isLock = lock.tryLock(10, 30, TimeUnit.SECONDS);
if (isLock) {
try {
doSomething();
} finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}

// 4. 异常处理
public void bestPractice4() {
RLock lock = redissonClient.getLock("myLock");
boolean locked = false;

try {
locked = lock.tryLock(100, TimeUnit.SECONDS);
if (locked) {
// 业务逻辑
doSomething();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (locked) {
try {
lock.unlock();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

9.2 注意事项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
使用看门狗注意事项:
1. 看门狗消耗资源:
- 后台线程定期续期
- 增加Redis服务器负担
- 合理设置续期时间

2. 网络延迟:
- 续期操作可能失败
- 锁可能在续期间隙过期
- 需要处理续期失败情况

3. 锁竞争:
- 高并发场景下锁竞争激烈
- 使用公平锁减少饥饿
- 合理设置等待时间

4. 死锁避免:
- 设置合理的超时时间
- 使用tryLock避免阻塞
- 及时释放锁

十、总结

本文介绍Redis看门狗机制及应用:

核心要点

  1. 看门狗机制:分布式锁自动续期
  2. Redisson实现:开箱即用
  3. 续期策略:每超时时间1/3续期
  4. 适用场景:任务执行时间不确定
  5. 高可用方案:Sentinel/Cluster/MultiLock
  6. 最佳实践:避免过长持有、合理超时

技术要点

  • 自动续期:后台续期、任务结束后释放
  • 原子操作:Lua脚本保证原子性
  • 异常处理:超时自动释放
  • 高可用:多实例可用性保障

实践建议

  1. 优先使用 Redisson 等成熟库
  2. 业务逻辑耗时不确定时使用看门狗
  3. 合理设置续期时间与等待时间
  4. 监控锁使用情况并优化
  5. 生产使用 Sentinel 或 Cluster

通过看门狗机制可稳定实现分布式锁。