⬆️ ⬇️

How do transactions work in Redis

I have been working with Redis relatively recently and now it has become necessary to change one key with several threads simultaneously. To work with Redis in php I use the Rediska client. Even when I read the Rediska manual I saw a section on transactions , and today it’s time to read more carefully.







I don’t know that I’m guilty of that, whether my poor knowledge of English, or my stupidity, or incomprehensibility of documentation, but nevertheless, having familiarized myself with the transaction documentation on the Rediska website and then on the Redis website, I didn’t understand whether changeable inside the transaction, the key to write to execute () or not.

Yes, in both documents there are descriptions and examples of “Optimistic locking using check-and-set” when watch is used, but at the same time at the beginning of the official documentation on the Redis website it is written:

')

Transacted sequentially. The redis transaction. This is a single isolated operation.



After reading this, it seemed to me (I will cross, just in case) that it’s about the fact that no one can change the values ​​of the affected keys in the middle of a transaction. However, I was wrong and to understand this I had to write a script by analogy with the one that is listed in the dock on the Rediska client site.



$ options = array (

'namespace' => 'Application_' ,

'servers' => array (

array ( 'host' => '127.0.0.1' , 'port' => 6379 , 'db' => 5 )

)

) ;



require_once 'Rediska.php' ;



// Get rediska entity

$ rediska = new Rediska ( $ options ) ;



for ( $ i = 1 ; $ i <= 10000 ; $ i ++ ) {

// Start transaction

$ transaction = $ rediska -> transaction ( ) ;



// Get current value

$ value = $ rediska -> get ( 'test_value' ) ;



// Increment value

$ value ++;



// Store new value

$ transaction -> set ( 'test_value' , $ value ) ;



// Execute transaction

$ transaction -> execute ( ) ;

}



echo $ rediska -> get ( 'test_value' ) ;




This script runs in two threads from the command line, i.e. in theory, the result was to get the value from the key “test_value” equal to 20 thousand, but in reality, there were on average about 12 thousand. Those. There is no lock.



Now I modify the loop a little by adding watch to it:



for ( $ i = 1 ; $ i <= 10000 ; $ i ++ ) {

for ( $ j = 1 ; $ j <= 5 ; $ j ++ ) {

// Start transaction

$ transaction = $ rediska -> transaction ( ) ;



// Watch

$ transaction -> watch ( 'test_value' ) ;



// Get current value

$ value = $ rediska -> get ( 'test_value' ) ;



// Increment value

$ value ++;



// Store new value

$ transaction -> set ( 'test_value' , $ value ) ;



// Execute transaction

try {

$ transaction -> execute ( ) ;

} catch ( Rediska_Transaction_AbortedException $ e ) {

continue ;

}



break ;

}

}




Those. in fact, when an exception occurs, we try to repeat the transaction 5 times. As a result, with 5 repetitions, an average of 17 thousand came out, if we raise, say up to 10, then an average of 19 thousand will come out.

These are particular cases, in practice there will hardly be such a number of simultaneous changes and 5 repetitions should be enough in principle, but this is not the point. The fact is that in fact Redis does not yet have a mechanism (documented) for locking keys affected by the changes.

It’s not for me to decide whether it’s good or bad to decide; I think it all depends on the task, I just wanted to show how it is.

Source: https://habr.com/ru/post/165223/



All Articles