Rumah > pangkalan data > Redis > Cara Redis menggunakan penguncian optimistik untuk memastikan konsistensi data

Cara Redis menggunakan penguncian optimistik untuk memastikan konsistensi data

WBOY
Lepaskan: 2023-06-02 16:52:42
ke hadapan
741 orang telah melayarinya

Senario

Dalam Redis, selalunya terdapat situasi di mana nilai kunci tertentu dibaca, beberapa pemprosesan logik perniagaan dilakukan, dan kemudian nilai baharu dikira berdasarkan nilai baca masuk semula.

Jika pelanggan A baru sahaja membaca nilai kunci, dan kemudian pelanggan B mengubah suai nilai kunci, maka akan berlaku isu keselamatan serentak.

Simulasi Masalah

Andaikan Pelayan Redis mempunyai kunci bernama ujian, yang menyimpan tatasusunan json [1, 2, 3].

Cara Redis menggunakan penguncian optimistik untuk memastikan konsistensi data

Mari kita mensimulasikan situasi di mana klien A dan klien B mengakses pengubahsuaian pada masa yang sama Kodnya adalah seperti berikut:

Klien 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")
}
Salin selepas log masuk

Klien 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")
}
Salin selepas log masuk

Klien A disekat selama 2 saat untuk mensimulasikan pemprosesan logik perniagaan yang memakan masa. Klien B mengakses "ujian" semasa pemprosesan dan menambah id:5.

Apabila pelanggan A selesai memproses logik perniagaan yang memakan masa, id:4 ditambah dan id:5 akan ditimpa.

Kandungan akhir dalam "ujian" adalah seperti berikut:

Cara Redis menggunakan penguncian optimistik untuk memastikan konsistensi data

CAS untuk memastikan ketekalan data

Arahan WATCH Redis Tingkah laku Semak dan Tetapkan (CAS) disediakan untuk digunakan dengan transaksi Redis. Kunci yang ditonton akan dipantau dan ia akan ditemui sama ada ia telah diubah suai. Jika sekurang-kurangnya satu objek yang dipantau diubah suai sebelum EXEC dilaksanakan, keseluruhan transaksi akan dibatalkan dan EXEC akan mengembalikan main semula Null untuk menunjukkan kegagalan pelaksanaan transaksi. Kami hanya perlu mengulangi operasi dan berharap tidak akan ada pertandingan baru dalam tempoh masa ini. Bentuk penguncian ini dipanggil penguncian optimistik, dan ia merupakan mekanisme penguncian yang sangat berkuasa.

Jadi bagaimana untuk melaksanakan CAS? Kami hanya perlu mengubah suai kod dalam kaedah kemas kini() RedisClientA seperti berikut:

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
        }
    }

}
Salin selepas log masuk

Kandungan akhir "ujian" adalah seperti berikut:

Cara Redis menggunakan penguncian optimistik untuk memastikan konsistensi data

Ia boleh dilihat bahawa kami menggunakan arahan WATCH dan TRANACTION menggunakan penguncian optimistik CAS untuk mencapai konsistensi data.

Atas ialah kandungan terperinci Cara Redis menggunakan penguncian optimistik untuk memastikan konsistensi data. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:yisu.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan