>Java >java지도 시간 >Redis를 사용하여 분산 잠금을 구현하는 방법에 대한 자세한 설명(코드 예)

Redis를 사용하여 분산 잠금을 구현하는 방법에 대한 자세한 설명(코드 예)

不言
不言앞으로
2018-10-20 17:00:283491검색

이 글은 Redis를 사용하여 분산 잠금을 구현하는 방법에 대한 자세한 설명(코드 예제)을 제공합니다. 필요한 친구들이 참고할 수 있기를 바랍니다.

분산 잠금 구현을 위해 Redis를 선택한 이유

Redis는 성능이 뛰어납니다

Redis 명령이 이를 더 잘 지원하고 구현하기가 더 편리합니다# 🎜 🎜#

명령 사용 소개

SETNXSETNX 키 값

if 그리고 다음과 같은 경우에만 키가 없으면 키 값을 사용하여 문자열을 설정하고 1을 반환합니다. 키가 있으면 아무 작업도 수행하지 않고 0을 반환합니다.

expireexpire key timeout

키 시간 제한을 초 단위로 설정하세요. 교착 상태를 방지하기 위해 이 시간이 지나면 잠금이 자동으로 해제됩니다.

deletedelete key

delete key
Redis를 사용하여 분산 잠금을 구현할 때 이 세 가지 명령이 주로 사용됩니다.

구현

은 jedis를 사용하여 Redis에 연결합니다.

구현 아이디어

잠금을 획득할 때 setnx를 사용하여 잠그고 만료 명령을 사용하여 잠금에 제한 시간을 추가합니다. 이 시간을 초과하면 잠금이 자동으로 해제되며, 잠금 값은 잠금 해제 시기를 결정하는 데 사용되는 무작위로 생성된 UUID입니다.

락 획득 시, 획득 제한 시간도 설정되어 있으며, 이 시간을 초과할 경우 락 획득이 포기됩니다.

잠금을 해제할 때 UUID를 사용하여 잠금인지 확인합니다. 잠금인 경우 삭제를 실행하여 잠금을 해제합니다.

분산 잠금의 핵심 코드는 다음과 같습니다.

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.exceptions.JedisException;
 
import java.util.List;
import java.util.UUID;
 
public class DistributedLock {
    private final JedisPool jedisPool;
 
    public DistributedLock(JedisPool jedisPool) {
        this.jedisPool = jedisPool;
    }
 
    /**
     * 加锁
     * @param locaName  锁的key
     * @param acquireTimeout  获取超时时间
     * @param timeout   锁的超时时间
     * @return 锁标识
     */
    public String lockWithTimeout(String locaName,
                                  long acquireTimeout, long timeout) {
        Jedis conn = null;
        String retIdentifier = null;
        try {
            // 获取连接
            conn = jedisPool.getResource();
            // 随机生成一个value
            String identifier = UUID.randomUUID().toString();
            // 锁名,即key值
            String lockKey = "lock:" + locaName;
            // 超时时间,上锁后超过此时间则自动释放锁
            int lockExpire = (int)(timeout / 1000);
 
            // 获取锁的超时时间,超过这个时间则放弃获取锁
            long end = System.currentTimeMillis() + acquireTimeout;
            while (System.currentTimeMillis()  results = transaction.exec();
                    if (results == null) {
                        continue;
                    }
                    retFlag = true;
                }
                conn.unwatch();
                break;
            }
        } catch (JedisException e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.close();
            }
        }
        return retFlag;
    }
}
Test

방금 구현한 분산 잠금을 간단한 예제를 통해 테스트해 보겠습니다.

예시에서는 상품의 반짝 세일을 시뮬레이션하기 위해 50개의 스레드가 사용되었으며, 상품을 줄이기 위해 -- 연산자를 사용하여 결과의 ​​순서를 보면 잠겨 있는지를 알 수 있습니다. 상태.

플래시 세일 서비스를 시뮬레이션하고 그 안에 jedis 스레드 풀을 구성한 후 초기화 중에 분산 잠금에 전달하여 사용합니다.

import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class Service {
    private static JedisPool pool = null;
 
    static {
        JedisPoolConfig config = new JedisPoolConfig();
        // 设置最大连接数
        config.setMaxTotal(200);
        // 设置最大空闲数
        config.setMaxIdle(8);
        // 设置最大等待时间
        config.setMaxWaitMillis(1000 * 100);
        // 在borrow一个jedis实例时,是否需要验证,若为true,则所有jedis实例均是可用的
        config.setTestOnBorrow(true);
        pool = new JedisPool(config, "127.0.0.1", 6379, 3000);
    }
 
    DistributedLock lock = new DistributedLock(pool);
 
    int n = 500;
 
    public void seckill() {
        // 返回锁的value值,供释放锁时候进行判断
        String indentifier = lock.lockWithTimeout("resource", 5000, 1000);
        System.out.println(Thread.currentThread().getName() + "获得了锁");
        System.out.println(--n);
        lock.releaseLock("resource", indentifier);
    }
}
플래시 세일 서비스 스레드 시뮬레이션

public class ThreadA extends Thread {
    private Service service;
 
    public ThreadA(Service service) {
        this.service = service;
    }
 
    @Override
    public void run() {
        service.seckill();
    }
}
 
public class Test {
    public static void main(String[] args) {
        Service service = new Service();
        for (int i = 0; i 결과는 다음과 같으며, 결과는 순서대로입니다. <p></p><p style="text-align: center;"><span class="img-wrap"><img src="https://img.php.cn//upload/image/211/984/157/1540025904941327.png" title="1540025904941327.png" alt="Redis를 사용하여 분산 잠금을 구현하는 방법에 대한 자세한 설명(코드 예)"></span></p>자물쇠를 사용하는 부분을 댓글로 달아주시면<p></p><pre class="brush:php;toolbar:false">public void seckill() {
    // 返回锁的value值,供释放锁时候进行判断
    //String indentifier = lock.lockWithTimeout("resource", 5000, 1000);
    System.out.println(Thread.currentThread().getName() + "获得了锁");
    System.out.println(--n);
    //lock.releaseLock("resource", indentifier);
}
가능한대로 결과를 보면 일부는 비동기적으로 수행됩니다.

Redis를 사용하여 분산 잠금을 구현하는 방법에 대한 자세한 설명(코드 예)

분산 환경에서는 특정 리소스를 스냅하는 등 리소스를 잠그는 것이 때로는 중요합니다. 이번에는 분산 잠금을 사용하여 리소스를 효과적으로 제어할 수 있습니다.

물론 특정 용도에서는 타임아웃 시간 선택, 잠금 획득 시간 선택 등 동시성 양에 큰 영향을 미치는 많은 요소를 고려해야 합니다. 위에 구현된 잠금은 단순한 구현일 뿐이며 대부분은 아이디어입니다.

[사실 redis를 사용하여 구현한 분산 잠금보다 Zookeeper를 사용하는 신뢰성이 더 높지만, 그에 비해 성능은 Redis가 더 좋습니다. ]

위 내용은 Redis를 사용하여 분산 잠금을 구현하는 방법에 대한 자세한 설명(코드 예)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제