ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • transactions
    개발하면서/코드보면서 2012. 9. 8. 14:42
    반응형

    Redis에는 transaction기능도 있습니다. :) 

    MULTI, EXEC, DISCARD, WATCH, UNWATCH 명령어가 있는데, 

    transaction이 redisClient별 이루어 지는 관계로 우선 redisClient에 대해 먼저 알아보겠습니다.

    redisClient 구조체는 아래와 같이 생겼습니다. transaction 설명하는데 필요한 변수만 적었습니다.



    우선 MULTI, EXEC명령어에 대한 source를 보겠습니다.

    redisClient 에는 flag라는 변수가 있는데, OR연산을 통해 아래와 같은 정보를 표시합니다.


    MULTI라는 명령어를 실행하면 별거 없습니다. 해당 client의 flag에 REDIS_MULTI를 표시합니다. (multi.c:multiCommand)

    MULTI이후에 명령어들은 EXEC가 실행되기 전까지 수행되지 않습니다.

    어떻게 그렇게 되는지 보게되면 (redis.c :processCommand)


    if문 안에 있는 문장들 반갑지 않나요? ㅎㅎㅎ REDIS_MULTI이고 그외 명령어들이 나오기 전까지는 queueMultiCommand를 실행합니다.


    queueMultiCommand의 기능도 간단합니다. 입력된 명령어들을 실행하라고 서버로 보내지않고,
    zrealloc하면서 명령어(c->cmd), 명령어의 인자값(c->argv)들을 c->mstate에 저장합니다.

    MULTI를 실행하고 명령어 1000개 2000개 입력하면 그만큼 메모리를 할당하게 됩니다. 서버에 데이타가 

    하나도 없어도 max_memory효과를 볼수 있겠네요?   ; ) ㅎㅎㅎ;;   


    명령어를 다 입력했으면 이젠 실행 시켜야겠죠??  EXEC를 실행합니다.  (multi.c : execCommand)

    딱~ 보이는게 REDIS_MULTI냐 아니냐를 판단하고,   c->flags & REDIS_DIRTY_CAS인지 아닌 지를 봅니다.

    CAS에 대해서는 WATCH 명령어에 대해 알아볼때 자세히 하도록 하겠습니다. 

    지금은 그냥 REDIS_DIRTY_CAS인 경우 mstate에 있는 명령어들이 실행이 안되는구나....라는 정도만 이해해도 좋을 것 같습니다.


    정상적이라면 아래 처럼 그동안 모아두었던 명령어들을 수행합니다.


    마지막으로 server.dirty++를 하게 되는데 replication, AOF할 건덕지를 남겨주는거라고 합니다. dirty = 0인게 좋은거죠.ㅋㅋㅋ


    WATCH명령어에 대해 알아보겠습니다.

    http://redis.io/topics/transactions 에 보면 Redis는 Optimistic Lock을 사용한다고 합니다.

    제가 영어가 짧아 소스로 배웠습니다.  

    optimistic concurrency control Wiki에 보면 아래와 같이 설명했습니다.

    • Begin : transaction을 시작한다고 timestamp를 기록 (Redis에서는 WATCH명령어)
    • Modify : 값을가져오고 가공을한다   (Redis에서는 MULTI명령어 이후 일반 명령어까지~)
    • Validate : 가공된 값을 저장하려고 할때 이값이 유효한(valid)지 검사
                 (Redis에서는 EXEC명령어를 수행하면 REDIS_DIRTY_CAS를 검사)
    • Commit/ Rollback : 아무런 문제가 없으면 Commit, 문제가 있다면 지금까지 입력했던 명령어들 무효


    watched_keys가 그 역할을 해줍니다.

    흐름이 어떻게 되는지 알아보겠습니다.

    우선 서버가 가동되면 redisDB를 생성합니다(redis.c:initServer)



    빨강색 안쪽이 생성되는거죠.



    서버가 가동됐습니다. 
    다음엔 client가 생성될 때 (network.c:createClient) c->watched_keys = listCreate();를 수행합니다.



    client에서 WATCH 명령어를 날릴때는 아래와 같은 동작을 합니다.





    동일한 redisDb에서 동일한 key를 다른 client가 수정을 하게되면 다음과 같은 연산을 합니다.(multi.c:touchWatchedKey)

    EXEC 명령어를 실행하면 validate를 검사합니다. 상상가시죠? 

    해당 client의 flag가 REDIS_DIRTY_CAS인지 검사하는것입니다.

    check결과에 따라 commit을 할건지, rollback을 할건지 정합니다.


    반응형

    댓글

Designed by Tistory.