Redis 분산 잠금 원리를 구현하는 방법

(*-*)浩
풀어 주다: 2019-11-28 10:14:53
원래의
17298명이 탐색했습니다.

Redis 분산 잠금 원리를 구현하는 방법

분산 잠금은 분산 시스템 간의 공유 리소스에 대한 동기 액세스를 제어하는 ​​방법입니다.

분산 시스템에서는 작업을 조정해야 하는 경우가 많습니다. 서로 다른 시스템 또는 동일한 시스템의 서로 다른 호스트가 하나 또는 그룹의 리소스를 공유하는 경우 이러한 리소스에 액세스할 때 상호 간섭을 방지하고 일관성을 보장하기 위해 상호 배제가 필요한 경우가 많습니다. 이 경우 분산 잠금을 사용해야 합니다.

4개의 Redis 명령 setnx, getset,expiration 및 del을 사용하여 구현합니다.(권장 학습: Redis 비디오 튜토리얼)

setnx는 "SET if Not eXists"의 약어입니다(존재하지 않는 경우 세트). 명령 형식: SETNX 키 값, 사용법: 키 키가 존재하지 않는 경우에만 키 값을 value로 설정합니다. 키 키가 이미 존재하는 경우 SETNX 명령은 아무 작업도 수행하지 않습니다. 반환 값: 이 명령은 설정에 성공하면 1을 반환하고 설정에 실패하면 0을 반환합니다.

getset 명령 형식: GETSET 키 값, 키 키 값을 value로 설정하고 설정되기 전 키 키의 이전 값을 반환합니다. 반환 값: 키 키에 이전 값이 없는 경우, 즉 키가 설정되기 전에 키 키가 존재하지 않는 경우 명령은 nil을 반환합니다. 키가 존재하지만 문자열 유형이 아닌 경우 명령은 오류를 반환합니다.

expire 명령 형식: EXPIRE 키 초, 사용법: 해당 키의 생존 시간을 설정합니다. 키가 만료되면(생존 시간이 0) 자동으로 삭제됩니다. 반환 값: 설정에 성공하면 1이 반환됩니다. 키가 존재하지 않거나 키의 수명을 설정할 수 없는 경우(예: Redis 2.1.3 이전 버전에서 키 수명을 업데이트하려고 하는 경우) 0이 반환됩니다.

del 명령 형식: DEL 키 [key...], 사용법: 하나 이상의 지정된 키를 삭제하고, 존재하지 않는 키는 무시됩니다. 반환 값: 삭제된 키의 수.

Redis의 분산 잠금 구현 원리:

1. setnx(lock_timeout)을 통해 구현됩니다. 잠금이 설정된 경우 1을 반환하고, 성공적으로 설정되지 않은 값이 있으면 0을 반환합니다. 2. 교착상태 문제: 실습을 통해 판단 만료된 경우 만료 시간 get(lockKey)을 얻은 후 getset(lock_timeout)과 동일한지 확인합니다. 여러 스레드가 동시에 getset(lock_timeout) 메서드를 실행하게 할 수 있으므로 잠금이 성공적으로 잠겼음을 증명합니다. 결과적으로 다중 스레드는 잠금을 결정하는 스레드에 대해 getset만 필요합니다. 성공하면 여러 스레드가 동시에 시간을 겹쳐서 잠금 에이징 시간이 두 배로 늘어나는 것을 방지하기 위해 만료(lockKey, LOCK_TIMEOUT, TimeUnit.MILLISECONDS) 만료 시간을 추가합니다.

코드: Redis 분산 잠금 원리를 구현하는 방법

/**
 * @author yaoxin
 * @date 2018/8/13下午5:04
 */
public class RedisLockTest {
 
    public static final String url = "jdbc:mysql://127.0.0.1:3306/ly?characterEncoding=UTF-8";
    public static final String name = "com.mysql.jdbc.Driver";
    public static final String user = "root";
    public static final String password = "";
 
    public static void main(String[] args) {
 
        Integer count = 50;
        while (count > 0) {
            count--;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Jedis jedis = new Jedis("127.0.0.1", 6379);
                    jedis.auth("1234");
                    String lock = lock(jedis);
                    if (lock != null) {
                        Statement statement = null;
                        Connection conn = null;
                        ResultSet resultSet = null;
                        try {
                            Class.forName(name);// 指定连接类型
                            conn = DriverManager.getConnection(url, user, password);// 获取连接
                            statement = conn.createStatement();// 准备执行语句
                            String querySql = "SELECT id,name,count FROM production WHERE id=2";
                            resultSet = statement.executeQuery(querySql);
                            int count = 0;
                            while (resultSet.next()) {
                                System.out.println(Thread.currentThread().getName() + "抢到了锁 id: " + resultSet.getString("id")
                                        + " name: " + resultSet.getString("name")
                                        + " count: " + resultSet.getString("count"));
                                count = Integer.valueOf(resultSet.getString("count"));
                            }
                            String updateSql = "UPDATE production SET count=" + (count - 1)
                                    + " WHERE id=2";
                            int rows = statement.executeUpdate(updateSql);
                            if (rows > 0) {
                                System.out.println("更新成功" + Thread.currentThread().getName() + "  库存剩余:" + (count - 1));
                                System.out.println(Thread.currentThread().getName() + " === > >开始解锁");
                                boolean unlock = unlock(jedis, lock);
                                if (unlock)
                                    System.out.println(Thread.currentThread().getName() + " === > >解锁成功");
                            } else {
                                System.out.println("更新失败" + Thread.currentThread().getName());
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                if (conn != null)
                                    conn.close();
                                if (statement != null)
                                    statement.close();
                                if (resultSet != null)
                                    resultSet.close();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }, "线程" + count).start();
        }
    }
 
    public static String lock(Jedis jedis) {
        try {
            while (true) {
                String lockTime = Long.valueOf(jedis.time().get(0)) + 5 + "";
                if (jedis.setnx("lock", lockTime) == 1) {
                    jedis.expire("lock", 5);
                    return lockTime;
                }
                String lock = jedis.get("lock");
                if (!StringUtils.isEmpty(lock) && Long.valueOf(lock) < Long.valueOf(jedis.time().get(0))) {
                    String oldLockTime = jedis.getSet("lock", lockTime);
                    if (!StringUtils.isEmpty(oldLockTime) && oldLockTime.equals(lock)) {
                        return lockTime;
                    }
                }
                Thread.sleep(100);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
 
    public static boolean unlock(Jedis jedis, String lockTag) {
        if (lockTag.equals(jedis.get("lock"))) {
            jedis.del("lock");
            return true;
        }
        return false;
    }
 
}
로그인 후 복사

실행 결과는 다음과 같습니다.

Redis 분산 잠금 원리를 구현하는 방법더 많은 Redis 관련 기술 기사를 보려면

Redis 시작 튜토리얼

칼럼을 방문하여 알아보세요!

위 내용은 Redis 분산 잠금 원리를 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!