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üsselwertAblauf
Ablaufschlüssel-TimeoutLöschen
Schlüssel löschenBei 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; } }
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); } }
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); }
Wie aus den Ergebnissen ersichtlich ist, werden einige davon asynchron ausgeführt.
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!