Home > Database > Redis > How Redis uses optimistic locking to ensure data consistency

How Redis uses optimistic locking to ensure data consistency

WBOY
Release: 2023-06-02 16:52:42
forward
741 people have browsed it

Scenario

In Redis, there is often a situation where the value of a certain key is read, some business logic processing is performed, and then a new value is calculated based on the read value. Set it in again.

If client A has just read the key value, and then client B modifies the key value, then there will be a concurrency security issue.

Problem simulation

Assume that Redis Server has a key named test, which stores a json array [1, 2, 3].

How Redis uses optimistic locking to ensure data consistency

Let us simulate the situation where client A and client B access modifications at the same time. The code is as follows:

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")
}
Copy after login

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")
}
Copy after login

Client A blocked for 2 seconds to simulate the processing of time-consuming business logic. Client B accessed "test" during processing and added id:5.

When client A finishes processing the time-consuming business logic, id:4 is added and id:5 will be overwritten.

The final content in "test" is as follows:

How Redis uses optimistic locking to ensure data consistency

CAS to ensure data consistency

Redis' WATCH command Check and Set (CAS) behavior is provided for use with Redis transactions. WATCHed keys will be monitored and it will be discovered whether they have been modified. If at least one monitored object is modified before EXEC is executed, the entire transaction will be canceled and EXEC will return Null replay to indicate transaction execution failure. We just need to repeat the operation and hope that there will be no new competition during this time period. This form of locking is called optimistic locking, and it is a very powerful locking mechanism.

So how to implement CAS? We only need to modify the code in the update() method of RedisClientA as follows:

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

}
Copy after login

The final content of "test" is as follows:

How Redis uses optimistic locking to ensure data consistency

It can be seen that we use The WATCH and TRANACTION commands use CAS optimistic locking to achieve data consistency.

The above is the detailed content of How Redis uses optimistic locking to ensure data consistency. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:yisu.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template