更新时间:2023-12-27 GMT+08:00
分布式锁场景最佳实践
分布式锁场景需根据所选取的路由模式来选择合适的策略。
- 路由模式为single-read-write, single-read-async-double-write时
- 路由模式为local-read-single-write,local-read-single-write-support-readable, local-read-async-double-write时
这几种场景由于读写可能不在同一侧,导致分布式锁锁不住。要实现分布式锁必须保证读写在同一侧。
1、通过setnx等命令实现的情况,需在方法上加注解路由指定读数据源@ReadRoute(from = RedisSource.ACTIVE)
2、如使用redisson分布式锁时需根据激活的数据源创建RedissonClient
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 |
import com.huawei.devspore.mas.redis.config.Constants;
import com.huawei.devspore.mas.redis.config.MasRedisConfiguration;
import com.huawei.devspore.mas.redis.config.RedisServerConfiguration;
import com.huawei.devspore.mas.redis.config.RedisType;
import com.huawei.devspore.mas.redis.core.MultiZoneClient;
import com.huawei.devspore.mas.redis.exception.DcsException;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@Service
public class RedissonClientStorage {
// dcs的客户端
private final MultiZoneClient client;
// dc1和dc2的RedissonClient
private final Map<String, RedissonClient> redissonDcsMap = new HashMap<>();
/**
* @param client MultiZoneClient用于获取active.
* @param masRedisConfiguration 获取redis配置
* @return
*/
public RedissonClientStorage(MultiZoneClient client, MasRedisConfiguration masRedisConfiguration) {
this.client = client;
if (masRedisConfiguration.getRedis().getServers().containsKey(Constants.DC_1)) {
redissonDcsMap.put(Constants.DC_1,
create(masRedisConfiguration.getRedis().getServers().get(Constants.DC_1)));
}
if (masRedisConfiguration.getRedis().getServers().containsKey(Constants.DC_2)) {
redissonDcsMap.put(Constants.DC_2,
create(masRedisConfiguration.getRedis().getServers().get(Constants.DC_2)));
}
}
public static RedissonClient create(RedisServerConfiguration configuration) {
if (RedisType.NORMAL.equals(configuration.getType())
|| RedisType.MASTER_SLAVE.equals(configuration.getType())) {
Config config = new Config();
config.useSingleServer()
.setAddress(Constants.REDISSON_URI_PREFIX.concat(configuration.getHosts()))
.setPassword(configuration.getPassword())
.setDatabase(configuration.getDb());
config.setCodec(new JsonJacksonCodec());
return Redisson.create(config);
} else if (RedisType.CLUSTER.equals(configuration.getType())) {
Config config = new Config();
config.useClusterServers()
.setPassword(configuration.getPassword())
.setNodeAddresses(Arrays.stream(configuration.getHosts().split(","))
.map(Constants.REDISSON_URI_PREFIX::concat)
.collect(Collectors.toList()));
config.setCodec(new JsonJacksonCodec());
return Redisson.create(config);
} else {
throw new DcsException(String.format("unknown redis type %s", configuration.getType()));
}
}
/**
* @return active的RedissonClient
*/
public RedissonClient getActiveRedisson() {
return redissonDcsMap.get(client.getStrategyMode().getState().getActive());
}
// redisson lock使用的demo
public void lock() throws InterruptedException {
RedissonClient activeRedisson = this.getActiveRedisson();
RLock lock = activeRedisson.getLock("lock");
try {
if (lock.tryLock()) {
log.info("lock success-{}", Thread.currentThread());
Thread.sleep(30000);
} else {
log.info("lock fail-{}", Thread.currentThread());
}
} finally {
lock.unlock();
log.info("unlock success-{}", Thread.currentThread());
}
}
}
|
父主题: Mas-Redis-SDK使用手册