更新时间:2024-10-23 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时这几种场景由于读写可能不在同一侧,导致分布式锁锁不住。要实现分布式锁必须保证读写在同一侧。
- 通过setnx等命令实现的情况,需在方法上加注解路由指定读数据源@ReadRoute(from = RedisSource.ACTIVE)。
- 如使用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使用手册