Table of Contents
Introduction
2. Interviewer:
Have you ever encountered a scenario where you need to use distributed locks?
Event A:
Event B:
Redis distributed lock implementation method
1. Распределенная блокировка на основе Redis
3.Интервьюер: А как насчет операции разблокировки?
Используйте команду del для разблокировки
3.Интервьюер:
Принцип реализации распределенной блокировки на основе ZooKeeper
Дополнительное дополнение
方法一:
方法二:
Home Database Redis How to implement Redis distributed lock and what are its application scenarios

How to implement Redis distributed lock and what are its application scenarios

May 30, 2023 pm 05:55 PM
redis

    Introduction

    Lock is a very common tool in the development process. You must be familiar with it, pessimistic lock, optimistic lock, exclusive lock, fair lock, Unfair locks, etc., there are many concepts. If you don’t understand locks in Java, you can refer to this article: Java “locks” that must be mentioned. This article is very comprehensive, but for beginners, Knowing the concepts of these locks, due to lack of practical work experience, you may not understand the actual usage scenarios of unlocking. In Java, thread safety can be achieved through the three keywords Volatile, Synchronized, and ReentrantLock. This part of knowledge will be included in the first round of basic interviews. You will definitely ask (you must be proficient in it).

    In a distributed system, Java lock technologies cannot lock the code on two machines at the same time, so it must be implemented through distributed locks. Proficient use of distributed locks is also a skill that must be mastered by big factory developers.

    1. Interviewer:

    Have you ever encountered a scenario where you need to use distributed locks?

    Problem analysis: This question is mainly used as an introduction. You must first understand in what scenarios distributed locks need to be used and what problems distributed locks need to solve. Under this premise, it will help you better understand distributed locks. implementation principle.

    The scenarios for using distributed locks generally need to meet the following scenarios:

    • The system is a distributed system, and Java locks can no longer be locked.

    • Manipulate shared resources, such as the only user data in the library.

    • Synchronous access, that is, multiple processes operate shared resources at the same time.

    Answer: Let me tell you an example of a scenario where I use distributed locks in a project:

    Consumption points are available in many systems, including credit cards, e-commerce websites, etc. Points can be exchanged for gifts, etc. The operation of "consuming points" here is a typical scenario that requires the use of locks.

    Event A:

    Taking points redemption for gifts as an example, the complete point consumption process is simply divided into 3 steps:

    A1: The user selects the product, initiates the exchange and submits the order .

    A2: The system reads the user's remaining points: determines whether the user's current points are sufficient.

    A3: User points will be deducted.

    Event B:

    The system distributes points to users in three simple steps:

    B1: Calculate the points the user deserves for the day

    B2: Read The user’s original points

    B3: Add the points deserved this time to the original points

    Then the problem arises, if the user’s consumption points and the user’s accumulated points occur at the same time (user points are operated at the same time) What will happen?

    Assumption: While the user is consuming points, the offline task happens to be calculating points and issuing points to the user (for example, based on the user's consumption amount on the day). These two things are done at the same time. The following logic is a bit convoluted, so be patient and understand it.

    User U has 1,000 points (the data recording user points can be understood as shared resources), and this redemption will consume 999 points.

    Unlocked situation: When the event A program reaches the second step to read the points, the result read by the A:2 operation is 1000 points. It is judged that the remaining points are enough for this redemption, and then the step A is executed. Step 3 A: Points will be deducted for 3 operations (1000 - 999 = 1). The normal result should still be 1 point for the user. But event B is also executing at this time. This time, 100 points will be issued to user U. Two threads will do it at the same time (synchronous access). Without locking, there will be the following possibility: A:2 -> B :2 -> A:3 -> B:3, before A:3 is completed (points deducted, 1000 - 999), user U's total points are read by the thread of event B, and finally user U's total points It became 1100 points, and I redeemed a gift of 999 points in vain, which obviously did not meet the expected results.

    Some people say how it is possible to operate user points at the same time so coincidentally, and the CPU is so fast. As long as there are enough users and the concurrency is large enough, Murphy's Law will take effect sooner or later. It is only a matter of time before the above bug appears, and it may be hacked. The industry is stuck with this bug and is crazy about it. At this time, as a developer, if you want to solve this hidden danger, you must understand the use of unlocking.

    (Writing code is a rigorous matter!)

    Java itself provides two built-in lock implementations, one is synchronized implemented by the JVM and the Lock provided by the JDK. And many atomic operation classes are thread-safe. When your application is a stand-alone or single-process application, you can use these two locks to implement locks.

    However, most of the current systems of Internet companies are distributed. At this time, Java's own synchronized or Lock can no longer meet the locking requirements in a distributed environment, because the code will be deployed on multiple machines. In order to solve this problem, distributed locks came into being. The characteristics of distributed locks are multi-process, and memory cannot be shared on multiple physical machines. The common solution is based on the interference of the memory layer. The implementation solution is distributed locks based on Redis. or ZooKeeper distributed lock.

    (I can’t analyze it in more detail, the interviewer is not satisfied anymore?)

    2. Interviewer:

    Redis distributed lock implementation method

    There are currently two main implementation methods to solve the distributed lock problem: one is based on the Redis Cluster mode, and the other is... 2. Based on Zookeeper cluster mode.

    Give priority to mastering these two, and you will basically have no problem handling interviews.

    answer:

    1. Распределенная блокировка на основе Redis

    Метод 1: Используйте команду setnx для блокировки

    public static void wrongGetLock1(Jedis jedis, String lockKey, String requestId, int expireTime) {
    		// 第一步:加锁
        Long result = jedis.setnx(lockKey, requestId);
        if (result == 1) {
            // 第二步:设置过期时间
            jedis.expire(lockKey, expireTime);
        }
    }
    Copy after login

    Пояснение кода:

    setnx команда, Это означает, что установлен, если он не существует. Если lockKey не существует, сохраните ключ в Redis. Если результат возвращает 1 после успешного сохранения, это означает, что настройка прошла успешно. Если он не равен 1, это означает сбой. Другие потоки уже установить его.

    expire(), установите время истечения срока действия, чтобы предотвратить взаимоблокировку. Предположим, что если блокировка не удаляется после установки, то она эквивалентна всегда существующей, что приводит к взаимоблокировке.

    (Здесь хотелось бы подчеркнуть интервьюеру одно «но»)

    Подумайте, какие недостатки есть в моем вышеописанном методе? Продолжайте объяснять интервьюеру...

    Блокировка состоит из двух шагов. Первый шаг — jedis.setnx, второй — jedis.expire для установки срока действия. setnx и expire не являются атомарная операция. Если программа выполняется после того, как после первого шага произошло исключение. На втором шаге jedis.expire(lockKey, expireTime) не был выполнен, что означает, что у блокировки нет срока действия, и может возникнуть взаимоблокировка. . Как улучшить эту проблему?

    Улучшение:

    public class RedisLockDemo {
        private static final String SET_IF_NOT_EXIST = "NX";
        private static final String SET_WITH_EXPIRE_TIME = "PX";
        /**
         * 获取分布式锁
         * @param jedis Redis客户端
         * @param lockKey 锁
         * @param requestId 请求标识
         * @param expireTime 超期时间
         * @return 是否获取成功
         */
        public static boolean getLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
    				// 两步合二为一,一行代码加锁并设置 + 过期时间。
            if (1 == jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime)) {
                return true;//加锁成功
            }
            return false;//加锁失败
        }
    }
    Copy after login

    Объяснение кода:

    Объедините блокировку и установку срока действия в одну, одну строку кода, атомарную операцию.

    (Интервьюер был очень доволен, прежде чем задавать дальнейшие вопросы)

    3.Интервьюер: А как насчет операции разблокировки?

    Ответ:

    Снятие блокировки означает удаление ключа

    Используйте команду del для разблокировки

    public static void unLock(Jedis jedis, String lockKey, String requestId) {
        // 第一步: 使用 requestId 判断加锁与解锁是不是同一个客户端
        if (requestId.equals(jedis.get(lockKey))) {
            // 第二步: 若在此时,这把锁突然不是这个客户端的,则会误解锁
            jedis.del(lockKey);
        }
    }
    Copy after login

    Пояснение кода: используйте requestId, чтобы определить, Блокировка и разблокировка одинаковы Два шага client и jedis.del(lockKey) не являются атомарными операциями. Теоретически после выполнения первой операции проверки будет видно, что срок действия блокировки действительно истек и был получен другими потоками. Это время выполнения операции jedis.del(lockKey) эквивалентно снятию чужой блокировки, что неразумно. Конечно, это очень крайняя ситуация. Если на первом и втором шагах метода разблокировки нет других бизнес-операций, размещение приведенного выше кода в сети может не вызвать проблем. Первая причина – параллелизм бизнес-процессов. Если это так, невысокий, этот изъян вообще не будет выявляться, так что проблема не большая.

    Но написание кода — это кропотливая работа, и чтобы быть идеальным, вы должны быть совершенными. Предлагаются улучшения для решения проблем в приведенном выше коде.

    Улучшение кода:

    public class RedisTool {
        private static final Long RELEASE_SUCCESS = 1L;
        /**
         * 释放分布式锁
         * @param jedis Redis客户端
         * @param lockKey 锁
         * @param requestId 请求标识
         * @return 是否释放成功
         */
        public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
            if (RELEASE_SUCCESS.equals(result)) {
                return true;
            }
            return false;
        }
    }
    Copy after login

    Объяснение кода:

    Используйте метод eval клиента jedis и всего одну строку сценария, чтобы решить проблему атомарности, связанную с первым методом.

    3.Интервьюер:

    Принцип реализации распределенной блокировки на основе ZooKeeper

    Ответ: Это все еще пример потребления и накопления очков: событие A и событие B должны быть выполняться одновременно Операция изменения точек выполняется на двух машинах одновременно. Правильная бизнес-логика заключается в том, чтобы позволить одной машине выполнить ее сначала, а затем другой машине. Либо событие A выполняется первым, либо событие B выполняется одновременно. выполняется первым, чтобы гарантировать, что не произойдет A. :2 -> B:2 -> A:3 -> B:3 Чем больше очков вы тратите, тем больше очков вы тратите (думая, что как только этот вид если ошибка выйдет в сеть, босс рассердится, я могу заплакать).

    что делать? Используйте распределенные блокировки Zookeeper.

    После того, как машина получает запрос, она сначала получает распределенную блокировку на Zookeeper (zk создаст znode) и выполняет операцию; затем другая машина также пытается создать znode, но обнаруживает, что не может его создать ., поскольку он был создан кем-то другим, вам остается только подождать, пока первая машина завершит выполнение, прежде чем вы сможете получить блокировку.

    Используя функцию последовательных узлов ZooKeeper, если мы создадим 3 узла в каталоге /lock/, кластер ZK создаст узлы в том порядке, в котором они были созданы.Узлы разделены на /lock/ 0000000001, /lock/0000000002 , /lock/0000000003, последняя цифра последовательно увеличивается, а имя узла завершается знаком zk.

    ZK также имеет узел, называемый временным узлом. Временный узел создается клиентом. Когда клиент отключается от кластера ZK, узел автоматически удаляется. EPHEMERAL_SEQUENTIAL — это временный узел последовательности.

    Основная логика распределенных блокировок заключается в использовании наличия или отсутствия узлов в ZK в качестве статуса блокировки для реализации распределенных блокировок

    • Клиент вызывает функцию create() метод Создайте временный узел последовательности с именем «/dlm-locks/lockname/lock-».

    • Клиент вызывает метод getChildren("lockname") для получения всех созданных дочерних узлов.

    • После того, как клиент получит пути всех дочерних узлов, если он обнаружит, что узел, созданный им на шаге 1, имеет наименьший порядковый номер среди всех узлов, он проверит, является ли порядковый номер он создал ранги первым.Во-первых, если он первый, то считается, что этот клиент получил блокировку, и ни один другой клиент не получил блокировку до него.

    • Если созданный узел не является самым маленьким из всех узлов, то необходимо отслеживать самый большой узел с меньшим порядковым номером, чем созданный им узел, а затем перейти в состояние ожидания . После изменения отслеживаемого дочернего узла получите дочерний узел и определите, следует ли получать блокировку.

    Хотя процесс снятия блокировки относительно прост и фактически представляет собой удаление созданного дочернего узла, вам все равно необходимо учитывать нештатные ситуации, такие как невозможность удаления узла.

    Дополнительное дополнение

    Распределенные блокировки также могут решить проблему с базой данных

    方法一:

    利用 Mysql 的锁表,创建一张表,设置一个 UNIQUE KEY 这个 KEY 就是要锁的 KEY,所以同一个 KEY 在mysql表里只能插入一次了,这样对锁的竞争就交给了数据库,处理同一个 KEY 数据库保证了只有一个节点能插入成功,其他节点都会插入失败。

    这样 lock 和 unlock 的思路就很简单了,伪代码:

    def lock :
        exec sql: insert into locked—table (xxx) values (xxx)
        if result == true :
            return true
        else :
            return false
    def unlock :
        exec sql: delete from lockedOrder where order_id='order_id'
    Copy after login

    方法二:

    使用流水号+时间戳做幂等操作,可以看作是一个不会释放的锁。

    The above is the detailed content of How to implement Redis distributed lock and what are its application scenarios. For more information, please follow other related articles on the PHP Chinese website!

    Statement of this Website
    The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

    Hot AI Tools

    Undresser.AI Undress

    Undresser.AI Undress

    AI-powered app for creating realistic nude photos

    AI Clothes Remover

    AI Clothes Remover

    Online AI tool for removing clothes from photos.

    Undress AI Tool

    Undress AI Tool

    Undress images for free

    Clothoff.io

    Clothoff.io

    AI clothes remover

    Video Face Swap

    Video Face Swap

    Swap faces in any video effortlessly with our completely free AI face swap tool!

    Hot Tools

    Notepad++7.3.1

    Notepad++7.3.1

    Easy-to-use and free code editor

    SublimeText3 Chinese version

    SublimeText3 Chinese version

    Chinese version, very easy to use

    Zend Studio 13.0.1

    Zend Studio 13.0.1

    Powerful PHP integrated development environment

    Dreamweaver CS6

    Dreamweaver CS6

    Visual web development tools

    SublimeText3 Mac version

    SublimeText3 Mac version

    God-level code editing software (SublimeText3)

    How to build the redis cluster mode How to build the redis cluster mode Apr 10, 2025 pm 10:15 PM

    Redis cluster mode deploys Redis instances to multiple servers through sharding, improving scalability and availability. The construction steps are as follows: Create odd Redis instances with different ports; Create 3 sentinel instances, monitor Redis instances and failover; configure sentinel configuration files, add monitoring Redis instance information and failover settings; configure Redis instance configuration files, enable cluster mode and specify the cluster information file path; create nodes.conf file, containing information of each Redis instance; start the cluster, execute the create command to create a cluster and specify the number of replicas; log in to the cluster to execute the CLUSTER INFO command to verify the cluster status; make

    How to clear redis data How to clear redis data Apr 10, 2025 pm 10:06 PM

    How to clear Redis data: Use the FLUSHALL command to clear all key values. Use the FLUSHDB command to clear the key value of the currently selected database. Use SELECT to switch databases, and then use FLUSHDB to clear multiple databases. Use the DEL command to delete a specific key. Use the redis-cli tool to clear the data.

    How to read redis queue How to read redis queue Apr 10, 2025 pm 10:12 PM

    To read a queue from Redis, you need to get the queue name, read the elements using the LPOP command, and process the empty queue. The specific steps are as follows: Get the queue name: name it with the prefix of "queue:" such as "queue:my-queue". Use the LPOP command: Eject the element from the head of the queue and return its value, such as LPOP queue:my-queue. Processing empty queues: If the queue is empty, LPOP returns nil, and you can check whether the queue exists before reading the element.

    How to configure Lua script execution time in centos redis How to configure Lua script execution time in centos redis Apr 14, 2025 pm 02:12 PM

    On CentOS systems, you can limit the execution time of Lua scripts by modifying Redis configuration files or using Redis commands to prevent malicious scripts from consuming too much resources. Method 1: Modify the Redis configuration file and locate the Redis configuration file: The Redis configuration file is usually located in /etc/redis/redis.conf. Edit configuration file: Open the configuration file using a text editor (such as vi or nano): sudovi/etc/redis/redis.conf Set the Lua script execution time limit: Add or modify the following lines in the configuration file to set the maximum execution time of the Lua script (unit: milliseconds)

    How to use the redis command How to use the redis command Apr 10, 2025 pm 08:45 PM

    Using the Redis directive requires the following steps: Open the Redis client. Enter the command (verb key value). Provides the required parameters (varies from instruction to instruction). Press Enter to execute the command. Redis returns a response indicating the result of the operation (usually OK or -ERR).

    How to use redis lock How to use redis lock Apr 10, 2025 pm 08:39 PM

    Using Redis to lock operations requires obtaining the lock through the SETNX command, and then using the EXPIRE command to set the expiration time. The specific steps are: (1) Use the SETNX command to try to set a key-value pair; (2) Use the EXPIRE command to set the expiration time for the lock; (3) Use the DEL command to delete the lock when the lock is no longer needed.

    How to use the redis command line How to use the redis command line Apr 10, 2025 pm 10:18 PM

    Use the Redis command line tool (redis-cli) to manage and operate Redis through the following steps: Connect to the server, specify the address and port. Send commands to the server using the command name and parameters. Use the HELP command to view help information for a specific command. Use the QUIT command to exit the command line tool.

    How to set the redis expiration policy How to set the redis expiration policy Apr 10, 2025 pm 10:03 PM

    There are two types of Redis data expiration strategies: periodic deletion: periodic scan to delete the expired key, which can be set through expired-time-cap-remove-count and expired-time-cap-remove-delay parameters. Lazy Deletion: Check for deletion expired keys only when keys are read or written. They can be set through lazyfree-lazy-eviction, lazyfree-lazy-expire, lazyfree-lazy-user-del parameters.

    See all articles