sql >> Databasteknik >  >> NoSQL >> Redis

Transaktioner och bevakningsutdrag i Redis

Det finns flera frågor här.

1) Varför kan vi inte utföra inkrement i transaktion som inte kan avbrytas av andra kommandon?

Observera först att Redis "transaktioner" är helt annorlunda än vad de flesta tror att transaktioner är i klassisk DBMS.

# Does not work
redis.multi() 
current = redis.get('powerlevel') 
redis.set('powerlevel', current + 1) 
redis.exec()

Du måste förstå vad som körs på serversidan (i Redis) och vad som körs på klientsidan (i ditt skript). I ovanstående kod kommer GET- och SET-kommandona att exekveras på Redis-sidan, men tilldelning till ström och beräkning av ström + 1 är tänkt att exekveras på klientsidan.

För att garantera atomicitet fördröjer ett MULTI/EXEC-block exekveringen av Redis-kommandon tills exec. Så klienten kommer bara att stapla upp GET- och SET-kommandona i minnet och exekvera dem i ett skott och atomiskt till slut. Naturligtvis kommer försöket att tilldela ström till resultatet av GET och inkrementering ske långt innan. I själva verket kommer metoden redis.get bara att returnera strängen "QUEUED" för att signalera att kommandot är försenat, och ökningen kommer inte att fungera.

I MULTI/EXEC-block kan du bara använda kommandon vars parametrar kan vara helt kända innan blockets början. Du kanske vill läsa dokumentationen för mer information.

2) Varför måste vi istället upprepa och vänta tills ingen ändrar värde innan transaktionen startar?

Detta är ett exempel på ett samtidigt optimistiskt mönster.

Om vi ​​inte använde någon WATCH/MULTI/EXEC skulle vi ha ett potentiellt tävlingstillstånd:

# Initial arbitrary value
powerlevel = 10
session A: GET powerlevel -> 10
session B: GET powerlevel -> 10
session A: current = 10 + 1
session B: current = 10 + 1
session A: SET powerlevel 11
session B: SET powerlevel 11
# In the end we have 11 instead of 12 -> wrong

Låt oss nu lägga till ett WATCH/MULTI/EXEC-block. Med en WATCH-sats körs kommandona mellan MULTI och EXEC endast om värdet inte har ändrats.

# Initial arbitrary value
powerlevel = 10
session A: WATCH powerlevel
session B: WATCH powerlevel
session A: GET powerlevel -> 10
session B: GET powerlevel -> 10
session A: current = 10 + 1
session B: current = 10 + 1
session A: MULTI
session B: MULTI
session A: SET powerlevel 11 -> QUEUED
session B: SET powerlevel 11 -> QUEUED
session A: EXEC -> success! powerlevel is now 11
session B: EXEC -> failure, because powerlevel has changed and was watched
# In the end, we have 11, and session B knows it has to attempt the transaction again
# Hopefully, it will work fine this time.

Så du behöver inte iterera för att vänta tills ingen ändrar värdet, utan snarare att försöka operationen igen och igen tills Redis är säker på att värdena är konsekventa och signalerar att den är framgångsrik.

I de flesta fall, om "transaktionerna" är tillräckligt snabba och sannolikheten för att strida är låg, är uppdateringarna mycket effektiva. Nu, om det finns tvist, kommer några extra operationer att behöva göras för vissa "transaktioner" (på grund av iterationen och omförsöken). Men uppgifterna kommer alltid att vara konsekventa och ingen låsning krävs.




  1. Konvertera HBase ACL:er till Ranger-policyer

  2. Implementering av goMongoDB-liknande frågeuttrycksobjektutvärdering

  3. ClusterControl körtidskonfigurationsalternativ

  4. Node.js - Session kvarstår inte genom res.redirect()