Heim > Java > javaLernprogramm > Hauptteil

Detaillierte Erläuterung der Verwendung von Redis zur Implementierung verteilter Sperren (Codebeispiel)

不言
Freigeben: 2018-10-20 17:00:28
nach vorne
3461 Leute haben es durchsucht

Dieser Artikel enthält eine detaillierte Erklärung (Codebeispiel) zur Implementierung verteilter Sperren. Ich hoffe, dass er für Freunde hilfreich ist.

Gründe für die Wahl von Redis zur Implementierung verteilter Sperren

Redis bietet eine hohe Leistung

Der Redis-Befehl unterstützt dies besser und ist bequemer zu implementieren

Einführung in die Verwendung von Befehlen

SETNX

SETNX-Schlüsselwert
Wenn und nur wenn der Schlüssel nicht existiert, legen Sie eine Zeichenfolge mit Schlüsselwert fest und geben Sie 1 zurück; Wenn der Schlüssel vorhanden ist, tun Sie nichts und geben Sie 0 zurück.

Ablauf

Ablaufschlüssel-Timeout
Legen Sie einen Timeout für den Schlüssel in Sekunden fest. Die Sperre wird nach dieser Zeit automatisch aufgehoben, um einen Deadlock zu vermeiden.

Löschen

Schlüssel löschen
Schlüssel löschen

Bei der Verwendung von Redis zur Implementierung verteilter Sperren werden hauptsächlich diese drei Befehle verwendet.

implementiert

mithilfe von Jedis, um eine Verbindung zu Redis herzustellen.

Implementierungsidee

Verwenden Sie beim Erwerb der Sperre setnx, um sie zu sperren, und verwenden Sie den Befehl „expire“, um der Sperre eine Zeitüberschreitungszeit hinzuzufügen , die Sperre wird automatisch aufgehoben. Der Wert ist eine zufällig generierte UUID, die zur Beurteilung beim Aufheben der Sperre verwendet wird.

Beim Erwerb der Sperre wird auch eine Zeitüberschreitung für den Erwerb festgelegt. Bei Überschreitung dieser Zeit wird der Erwerb der Sperre aufgegeben.

Wenn Sie eine Sperre aufheben, verwenden Sie die UUID, um festzustellen, ob es sich um die Sperre handelt. Wenn es sich um die Sperre handelt, führen Sie „Delete“ aus, um die Sperre aufzuheben.

Der Kerncode der verteilten Sperre lautet wie folgt:

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;
    }
}
Nach dem Login kopieren

Testen

Lassen Sie uns ein einfaches Beispiel verwenden, um die gerade implementierte verteilte Sperre zu testen.
Im Beispiel werden 50 Threads verwendet, um einen Flash-Sale eines Produkts zu simulieren, und der ---Operator wird verwendet, um das Produkt zu reduzieren. Aus der Reihenfolge der Ergebnisse lässt sich erkennen, ob es sich in einem gesperrten Zustand befindet .

Simulieren Sie den Flash-Sale-Dienst, konfigurieren Sie den darin enthaltenen Jedis-Thread-Pool und übergeben Sie ihn während der Initialisierung zur Verwendung an die verteilte Sperre.

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);
    }
}
Nach dem Login kopieren

Threads für Flash-Sale-Service simulieren

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>Die Ergebnisse sind wie folgt und die Ergebnisse sind in Ordnung. </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="Detaillierte Erläuterung der Verwendung von Redis zur Implementierung verteilter Sperren (Codebeispiel)"></span></p><p>Wenn Sie den Teil, der Sperren verwendet, auskommentieren </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);
}
Nach dem Login kopieren

Wie aus den Ergebnissen ersichtlich ist, werden einige davon asynchron ausgeführt.

Detaillierte Erläuterung der Verwendung von Redis zur Implementierung verteilter Sperren (Codebeispiel)

In einer verteilten Umgebung ist es manchmal wichtig, Ressourcen zu sperren, z. B. um eine bestimmte Ressource zu nutzen. In diesem Fall können verteilte Sperren verwendet werden sorgen für eine gute Kontrolle über die Ressourcen.

Natürlich müssen bei der spezifischen Verwendung viele Faktoren berücksichtigt werden, wie z. B. die Auswahl der Zeitüberschreitungszeit und die Auswahl der Sperrenerfassungszeit, die einen großen Einfluss auf den Umfang der implementierten Parallelität haben Oben ist nur eine einfache Implementierung, hauptsächlich eine Idee.

[Tatsächlich ist die Zuverlässigkeit der Verwendung von Zookeeper höher als die der von Redis implementierten verteilten Sperre, aber im Vergleich dazu ist die Leistung von Redis besser. ]

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der Verwendung von Redis zur Implementierung verteilter Sperren (Codebeispiel). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:segmentfault.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage