在微服务架构中,分布式锁是解决资源竞争的核心组件。传统单体应用的synchronized或ReentrantLock在分布式场景下完全失效,我们需要面对三大核心挑战:
SETNX方案演进:
java
复制
// 基础实现
Boolean result = redisTemplate.opsForValue()
.setIfAbsent(lockKey, requestId, 30, TimeUnit.SECONDS);
// 隐患:锁续期问题
// 解决方案:守护线程续期
private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
if (redisTemplate.getExpire(lockKey) < 20) {
redisTemplate.expire(lockKey, 30, TimeUnit.SECONDS);
}
}, 0, 10, TimeUnit.SECONDS);
RedLock算法争议:
基于多Redis实例的投票机制实现,但存在时钟漂移风险。Martin Kleppmann与Redis作者Antirez的著名论战揭示了其潜在问题:
java
复制
@Configuration
@ConditionalOnClass(RedisTemplate.class)
public class DistributedLockAutoConfiguration {
@Bean
public RedisDistributedLock redisDistributedLock(RedisTemplate<String, String> redisTemplate) {
return new RedisDistributedLock(redisTemplate);
}
}
java
复制
@Around("@annotation(distributedLock)")
public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {
String lockKey = generateLockKey(joinPoint, distributedLock);
try {
if (lockManager.lock(lockKey)) {
return joinPoint.proceed();
}
throw new ConcurrentAccessException();
} finally {
lockManager.unlock(lockKey);
}
}
核心组件交互流程:
复制
客户端 -> Config Server -> Git仓库
↓
Redis缓存
↓
Spring Cloud Bus
↓
/monitor端点刷新
Redis缓存层设计:
java
复制
@Configuration
public class RedisCacheConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(SerializationPair.fromSerializer(new Jackson2JsonRedisSerializer<>(Object.class)))
.entryTtl(Duration.ofMinutes(10));
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.transactionAware()
.build();
}
}
java
复制
@EnableEncryptableProperties
public class SecurityConfig {
@Bean
public TextEncryptor textEncryptor() {
return new AES256TextEncryptor(environment.getProperty("encrypt.key"));
}
}
yaml
复制
spring:
cloud:
config:
server:
git:
uri: https://config-repo
username: {cipher}FKSAJDFGYOS8...
password: {cipher}HJKLASDF98U...
java
复制
@Cacheable(value = "configCache", cacheManager = "caffeineCacheManager")
@Cacheable(value = "configRedis", cacheManager = "redisCacheManager")
public Properties getConfig(String application, String profile) {
// 从Git原始仓库加载
}
java
复制
@RefreshScope
@Scheduled(fixedRate = 5000)
public void checkUpdate() {
Long latestVersion = redisTemplate.opsForValue().increment("config.version");
if (latestVersion > localVersion.get()) {
refreshEnvironment();
}
}
方案 | 恢复时间 | 数据一致性 | 实现复杂度 |
---|---|---|---|
Redis哨兵 | <30s | 最终一致 | 中 |
集群模式 | <10s | 强一致 | 高 |
本地缓存回退 | 即时 | 弱一致 | 低 |
多中心同步 | <1min | 最终一致 | 极高 |
建议组合方案:
Redis Cluster + 本地文件缓存 + 配置版本控制