分散トランザクションソリューションのRedis実装

6528 ワード

前言:
マイクロサービスの発展に伴い、分散型事務はほとんど避けられないと言え、関連概念は余計なことではありません.分からないことがあれば、まず理解してから読むこともできますし、伝言もできます.このブログがあなたに役立つことを望んでいます.
本文:
まず、アーキテクチャ図を添付し、私が実現したソリューションが頼りにしているプロジェクトアーキテクチャを簡単に理解します.
 
 
 
以下は分散ロックの取得と解放、メンバー変数:StringRedisTemplate(springboot統合redis取得redis、注入jedisによる実現も可能であり、実現構想は一致しており、文末にredis取得の実現を添付します).
いくつかのredisの基本命令を見てみましょう:SETNX key value(stringRedisTemplate.opsForValue().setIfAbsent()キーが存在しない場合は、キー対応文字列valueを設定します.この場合、このコマンドはSETと同じです.keyがすでに存在する場合、何もしません.SETNXは「SET if Not eXists」です.expire KEY seconds(stringRedisTemplate.expire()キーの有効期限を設定します.keyが期限切れになった場合、自動的に削除されます.del KEY(stringRedisTemplate.delete()削除key
/**
 * @auther fanxuebo
 * @desc     
 * @Company 
 * @create 2019/1/10 17:48
 */
public class DistributedLock {

    private static final Logger LOGGER = LoggerFactory.getLogger(DistributedLock.class);

    private StringRedisTemplate stringRedisTemplate;
    public DistributedLock(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    /**
     * @Author fanxuebo
     * @Date 2019/1/11 10:10
     * @Description    
     **/
    public String lockWithTimeout(String lockName, long timeout) {
        String retIdentifier = null;
        try {
            //       value
            String identifier = UUID.randomUUID().toString();
            //   , key 
            String lockKey = "lock:" + lockName;
            //     ,              
            int lockExpire = (int)(timeout / 1000);
            while (true) {
                if (stringRedisTemplate.opsForValue().setIfAbsent(lockKey, identifier)) {
                    LOGGER.info("{}:    lockKey:{}", Thread.currentThread().getName(), lockKey);
                    stringRedisTemplate.expire(lockKey, lockExpire, TimeUnit.SECONDS);
                    //   value ,         
                    retIdentifier = identifier;
                    break;
                }
                //   -1  key        , key        
                if (stringRedisTemplate.getExpire(lockKey) == -1L) {
                    stringRedisTemplate.expire(lockKey, lockExpire, TimeUnit.SECONDS);
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        } catch (JedisException e) {
            e.printStackTrace();
        }
        return retIdentifier;
    }

    /**
     * @Author fanxuebo
     * @Date 2019/1/11 10:09
     * @Description    
     **/
    public boolean releaseLock(String lockName, String identifier) {
        String lockKey = "lock:" + lockName;
        boolean retFlag = false;
        try {
            while (true) {
                //   lock,      
                stringRedisTemplate.watch(lockKey);
                //        value        ,    ,   ,   
                if (identifier.equals(stringRedisTemplate.opsForValue().get(lockKey))) {
                    LOGGER.info("{}:   lockKey:{}", Thread.currentThread().getName(), lockKey);
                    stringRedisTemplate.delete(lockKey);
                    retFlag = true;
                }
                stringRedisTemplate.unwatch();
                break;
            }
        } catch (JedisException e) {
            e.printStackTrace();
        }
        return retFlag;
    }
}

ロックが必要なコードブロックでは、次の操作を行います.
DistributedLock distributedLock = new DistributedLock(stringRedisTemplate);
String lockName = XXX;
String identifier = null;
try {
    identifier = distributedLock.lockWithTimeout(lockName, 3000);
    //         
    distributedLock.releaseLock(lockName, identifier);
} catch (Exception e) {
    distributedLock.releaseLock(lockName, identifier);
}

ロックを取得する方法では、ロックを取得する時間が入力され、一定時間以内に取得され、返された識別がNULLでない場合、改善することができる.
long end = System.currentTimeMillis() + acquireTimeout;
while (System.currentTimeMillis() < end) {}
DistributedLock distributedLock = new DistributedLock(stringRedisTemplate);
String lockName = XXX;
String identifier = null;
try {
    identifier = distributedLock.lockWithTimeout(lockName, 3000);
    if (StringUtils.isBlank(identifier)) {
        //          
    }
    //         
    distributedLock.releaseLock(lockName, identifier);
} catch (Exception e) {
    distributedLock.releaseLock(lockName, identifier);
}

 
Springboot統合reids:
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

/**
 * @auther fanxuebo
 * @desc REDIS     
 * @Company sinosig
 * @create 2018/8/6 09:56
 */
@Configuration
@EnableCaching
public class RedisConfig {

    @Bean
    public CacheManager cacheManager(RedisTemplate,?> redisTemplate) {
        CacheManager cacheManager = new RedisCacheManager (redisTemplate);
        return cacheManager;
    }
    /**
     * @Auther: fanxuebo
     * @Description: jdk    ,      
     * @Date: 09:58 2018/8/6
     */
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        return redisTemplate;
    }
    /**
     * @Auther: fanxuebo
     * @Description: string      ,    string  
     * @Date: 09:59 2018/8/6
     */
    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(factory);
        return stringRedisTemplate;
    }
}

プロファイル:
spring:
    redis:
        database: 
        host: 
        port: 
        password: 
        pool:
            max-active: 50
            max-wait: 5000
#            max-idle: 8
#            min-idle: 0
        timeout: 5000

読んでからあなたたちに収穫があることを望んで、本文は完備しなければなりません.の