Sunday, May 3, 2015

REDIS : Single Threaded Model, Race Condition.

Lets assume we have multithreaded DB server, which can accept multiple connections and can execute multiple queries from different clients.
    Now let say Client 1 Issues a command : Incr X;
    Client 2 also Issues a Command : Incr X;
    Now If two Clients perform it at a same time then two possibilities can happen :
         If your DataBase server is on MultiCore CPU then then both threads can run parallel y.
     --If your DB server is with single Core then both can run concurrently.
     --In both cases : If queries are not performed atomically it can lead to Race Condition.

Since both threads trying to update the X, at almost same time(and due to this can cause inconsistent value of X).

        One more point to note : is INCR query requires to steps : a)Read the Value X b)Increment value X.
    For a small moment of time lets assume our Underlying Storage Engine of the DataBase provides exclusive Locks on Row/Table
        for update operation. Therefore it is safe to say that any of the two clients who got the Lock first, perform its operation, and release the lock
Hence there will be no race condition, as such.
In case you have multiple queries needs to executes as one Single atom, then we go by transaction and make it happen successfully.

NOTE : Lets say Client wants to execute the following command :
INCR X;
Now Increment X deals with two more granular operations : get X, update X = X+1;
Considering following scenario's(in case of multithreaded DB Server) :
May be my underlying Storage Engine behaves on occurrence of Update Query :
 -->It provides Exclusive DB Level Lock
 -->It provides  Exclusive Table Level Lock.
 -->It provides Exclusive Row Level Lock.
 -->It provides granular locks (on the basis of queries) {In that case we need to to execute INCR X in a Transaction}.
In any of the case Client needs to content for the Lock, grab the Lock, execute its query, release the Lock.

Therefore whatever be the case in Multithreaded DB Servers we need to make sure that only one Update Query executes at a time(If multiple clients wants to
update on same resource).{and this can be achieved by Locks, which is quite Obvious}.


NOTE : In case of Single Threaded Environment {DB Server is Single Threaded}, which means only one Thread will be using the Database at a time.
  So lets say we have two Clients scenario again : they both want to perform "get X" operation.
  Then the following will happen :
  Client #1 got the access of DB, send the command to REDIS, get the result ...Happy.
  Client #2 got the access of DB, send the command to REDIS, get the result ...Happy.
  It seems like get X operation is executed atomically, no interference.  Job Done.
 
  Now Lets say : Clients wants to Execute INCR X command :
  again, as per Single Threaded model , it will be executed atomically.
  Client #1 got the access of DB, send the command to REDIS, update X.
  Client #2 got the access of DB, send the command to REDIS, update X.
  Again no Interference, since it is Single Server Model.
 
  What happens, If Clients perform the following :
get X;
//DO SOME TASK
Incr X.

Now here as per our previous scenario's : get X {executed without interference}, But it might happen that other Client update the X value,
and when our old Client get the chance, it will Increment X with old value and not the newest value.
Hence Race Conditions occurs, and I think it is obvious, because If you want to execute multiple commands at once, why not go for Transactions.
Therefore WATCH/MULTI/EXEC comes into picture.
Now If we have used transaction{Then all our commands i.e get X and update X will run as Single Unit}.
EXEC : Will execute them one after other and WATCH : will keep track if any updates happened before executing the commands, If so retry the whole process again.

It seems like it is Responsive approach: Since no User/Client will get blocked{due to Locking} , which happened in case of Traditional RDBMS.
The only thing is that retries will happen on case of updations by other Clients.

But again above process have one severe drawback :
In case of Heavy Load : Number of retries will increase, because at the moment when you are going to execute your Commands Chain, some other Client update the
value, then your Exec will fail and you try the whole process again.
Now to avoid such scenario's under Heavy Load, Locks comes into Picture. It is same like Traditional Locks(you can fine grain your locks based on the application
requirements) and you lock certain Data-structure, perform the queries and release the Lock.

Summary :
In short Redis commands are atomic on its own, and given that Redis is Single Threaded it is quite safe to execute single command without worrying about Race Conditions.
But when you are dealing with multiple commands to be executed atomically then you need to consider Transactions/Locking etc.
In contrast : Some Storage Engines{which supports multiple requests} might give atomicity only on {finest granularity} commands for Example INCR X {comprise of GET X, UPDATE X = X+1}, in that
case RACE Conditions can occur, in such scenario's you need to put even INCR X in a transaction or LOCK the resource.