Heim > Datenbank > Redis > Hauptteil

Wie Redis optimistisches Sperren verwendet, um die Datenkonsistenz sicherzustellen

WBOY
Freigeben: 2023-06-02 16:52:42
nach vorne
723 Leute haben es durchsucht

Szenario

In Redis gibt es oft eine Situation, in der der Wert eines bestimmten Schlüssels gelesen wird, eine gewisse Geschäftslogikverarbeitung durchgeführt wird und dann ein neuer Wert basierend auf dem gelesenen Wert berechnet und erneut festgelegt wird.

Wenn Client A gerade den Schlüsselwert gelesen hat und Client B dann den Schlüsselwert ändert, liegt ein Problem mit der Parallelitätssicherheit vor.

Problemsimulation

Angenommen, der Redis-Server verfügt über einen Schlüssel namens test, der ein JSON-Array [1, 2, 3] speichert.

Wie Redis optimistisches Sperren verwendet, um die Datenkonsistenz sicherzustellen

Simulieren wir die Situation, in der Client A und Client B gleichzeitig auf Änderungen zugreifen. Der Code lautet wie folgt:

Client A:

class RedisClientA(username: String, password: String, host: String, port: Int) {
    val jedis: Jedis

    init {
        val pool = JedisPool(JedisPoolConfig(), host, port)
        jedis = pool.resource
        jedis.auth(username, password)
    }

    fun update(key: String) {
        val idStr = jedis.get(key)
        val idList = Json.decodeFromString<MutableList<Int>>(idStr)

        // 等待2秒,模拟业务
        TimeUnit.SECONDS.sleep(2L)

        idList.add(4)
        println("new id list: $idList")

        jedis.set(key, Json.encodeToString(idList))
    }

    fun getVal(key: String): String? {
        return jedis.get(key)
    }
}

fun main() {
    val key = "test"
    val redisClientA = RedisClientA("default", "123456", "127.0.0.1", 6379)
    redisClientA.update(key)
    val res = redisClientA.getVal(key)
    println("res: $res")
}
Nach dem Login kopieren

Client B:

class RedisClientB(username: String, password: String, host: String, port: Int) {
    val jedis: Jedis

    init {
        val pool = JedisPool(JedisPoolConfig(), host, port)
        jedis = pool.resource
        jedis.auth(username, password)
    }

    fun update(key: String) {
        val idStr = jedis.get(key)
        val idList = Json.decodeFromString<MutableList<Int>>(idStr)

        idList.add(5)
        println("new id list: $idList")

        jedis.set(key, Json.encodeToString(idList))
    }

    fun getVal(key: String): String? {
        return jedis.get(key)
    }
}

fun main() {
    val key = "test"
    val redisClientB = RedisClientB("default", "123456", "127.0.0.1", 6379)
    redisClientB.update(key)
    val res = redisClientB.getVal(key)
    println("res: $res")
}
Nach dem Login kopieren

Client A ist für 2 Sekunden blockiert , wird verwendet, um zeitaufwändige Geschäftslogikverarbeitung zu simulieren. Client B hat während der Verarbeitung auf „test“ zugegriffen und die ID:5 hinzugefügt.

Wenn Client A die Verarbeitung der zeitaufwändigen Geschäftslogik abgeschlossen hat, wird ID:4 hinzugefügt und ID:5 überschrieben.

Der endgültige Inhalt in „Test“ lautet wie folgt:

Wie Redis optimistisches Sperren verwendet, um die Datenkonsistenz sicherzustellen

CAS zur Gewährleistung der Datenkonsistenz

Der WATCH-Befehl von Redis stellt das Check-and-Set-Verhalten (CAS) für Redis-Transaktionen bereit. Überwachte Schlüssel werden überwacht und es wird festgestellt, ob sie geändert wurden. Wenn mindestens ein überwachtes Objekt geändert wird, bevor EXEC ausgeführt wird, wird die gesamte Transaktion abgebrochen und EXEC gibt eine Null-Wiedergabe zurück, um einen Transaktionsausführungsfehler anzuzeigen. Wir müssen den Vorgang lediglich wiederholen und hoffen, dass es in diesem Zeitraum keine neue Konkurrenz gibt. Diese Form der Verriegelung wird als optimistische Verriegelung bezeichnet und ist ein sehr leistungsfähiger Verriegelungsmechanismus.

Wie implementiert man CAS? Wir müssen nur den Code in der update()-Methode von RedisClientA wie folgt ändern:

fun update(key: String) {
    var flag = true

    while (flag) {
        jedis.watch(key)

        val idStr = jedis.get(key)
        val idList = Json.decodeFromString<MutableList<Int>>(idStr)

        // 等待2秒,模拟业务
        TimeUnit.SECONDS.sleep(2L)

        val transaction = jedis.multi()
        idList.add(4)
        println("new id list: $idList")

        transaction.set(key, Json.encodeToString(idList))

        transaction.exec()?.let {
            flag = false
        }
    }

}
Nach dem Login kopieren

Der endgültige „Test“-Inhalt lautet wie folgt:

Wie Redis optimistisches Sperren verwendet, um die Datenkonsistenz sicherzustellen

Es ist ersichtlich, dass wir zur Implementierung die Befehle WATCH und TRANACTION verwenden Daten mit optimistischer CAS-Sperrkonsistenz.

Das obige ist der detaillierte Inhalt vonWie Redis optimistisches Sperren verwendet, um die Datenkonsistenz sicherzustellen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:yisu.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