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.
Andaikan Pelayan Redis mempunyai kunci bernama ujian, yang menyimpan tatasusunan json [1, 2, 3].
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") }
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") }
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:
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 } } }
Kandungan akhir "ujian" adalah seperti berikut:
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!