ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • MongoDB CRUD - 어떻게 완화된 ACID (BASE) 인가?
    mongoDB 2022. 3. 28. 22:32

     mongoDB는 완화된 ACID 즉, BASE의 컨셉을 갖고 있다. 그렇다면 mongoDB는 어떻게 완화된 ACID (BASE)로 사용될까?


     

    Atomicity and Transactions

     mongoDB는 single document level write의 atomic을 보장한다. 이는 embedded document에서도 적용이 된다. 말이 좀 어려울 수 있는데 결론은 atomic을 보장하고 싶으면 여러 document에 data를 분산하지 말고 embedded documents로 single document를 관리해야 한다.

     

     여기서 embedded documents를 모를 수 있으니 이에 대해 간단히 설명하겠다.

    RDBMS에서는 보통 아래와 같이 나누어서 data를 저장한다. 이는 single document가 아니기 때문에 만약 아래의 document들을 동시에 수정하게 되면 관계가 있을 지라도 atomic이 보장되지 않고 interleave하게 동작한다.

    // user document
    {
       _id: "1",
       name: "zzihyeon"
    }
    
    // follow documents
    {
       user_id: "1",
       follwor_id: "2",
       name: "IU"
    }
    
    {
       user_id: "1",
       follower_id: "3",
       name: "j park"
    }

     하지만 mongoDB는 나눌 필요 없이 아래와 같이 embedded document로 작성할 수 있다. 이는 atomic이 보장된다.

    {
       _id: "1",
       name: "zzihyeon"
       followers: [
        {
           user_id: "1", 
           follwor_id: "2",
           name: "IU"
        }
    
        {
           user_id: "1",
           follower_id: "3",
           name: "j park"
        }
       ]
    }

     하지만 single Document가 write가 아닌 multi document write 시에도 atomicity가 보장되어야 하는 경우가 있을 것이다. 이를 위해 mongoDB는 multi-document transactions을 지원한다.(https://www.mongodb.com/docs/manual/core/transactions/)


    Concurrency Control

     만약 2개의 application에서 update를 동시에 날렸다고 생각해보자. 동일한 condition인데 update 결과로 인해 condition에 해당하는 필드가 변한다면 어떻게 동작할까? Mongodb는 concurrency control을 통해 이를 문제 없이 해결할 수 있다.

     이해를 돕기 위해 예제를 추가하면 

    #data insert
    db.myCollection.insertMany( [
       { _id: 0, a: 1, b: 1 },
       { _id: 1, a: 1, b: 1 }
    ] )
    #update
    db.myCollection.findAndModify( {
       query: { a: 1 },
       update: { $inc: { b: 1 }, $set: { a: 2 } }
    } )

     

     만약 동시에 2개의 update가 다른 application에서 날아오면 _id:0이 두번 update되어 a=2, b=3이 되는 것이 아니라 _id:0, _id:1 모두 a,b = 2가 된다.

     만약 여기에서 애초에 data가 _id:0 밖에 없었다면 2개의 findAndModify 하나는 정상적으로 찾아서 modify하고 다른 하나는 condition에 맞는 document를 찾지 못해 update를 하지 못하거나 upsert옵션을 true로 했을 때는 _id는 자동으로 생성되고 a =2, b는 int라고 생각하고 default 0에서 1을 더한 값인 1로 document가 생성된다.


     대체 mongoDB가 기존 RDB랑 무슨 차이가 있길래 완화된 ACID(BASE)라고 말할까에 대한 의문이 들 수 있다. 그럼 이제 이 의문을 해결하기 위해 Read Concern과 Write Concern에 대해 살펴보자.

     Read Concern과 Write Concern은 강력한 일관성을 보장해야하는 작업이 필요할 땐 일관성 레벨을 조정하여 높이고 반대로 가용성이 더 필요할 땐 일관성을 좀 느슨하게 조정하여 가용성을 높일 수 있다. 드디어 완화된 ACID (BASE)에 관련된 내용을 확인할 수 있다. 그렇다면 어떻게 사용할 수 있는지 알아보자.

    Read Concern

     사실 read concern level과 관계없이 node의 가장 최신 data는 시스템의 data상의 가장 최신 버전을 반영하지 않을 수 있다. 즉, 현재 노드의 값과 실제 시스템 상의 값이 다를 수 있다. 글만으로는 이해가 어렵기 때문에 이해를 돕기위해 간단한 설명을 하고 지나가도록 하겠다. 

     아래의 그림은 mongoDB replica set이다. mongoDB replica set에서 write는 primary에서만 가능하지만 read는 secondary도 가능하다.

     primary에서 write operation이 발생하면 primary가 secondary로 replication 작업을 진행하는데 이 때, primary에는 반영된 정보가 secondary에 반영이 되기 전에 secondary에서 read를 하면 primary와 secondary의 값이 서로 다를 수 있다. 즉, 내가 보고 있는 node와 시스템 상의 값이 차이가 있을 수 있다.

    mongodb replica set에 대한 그림

     readConcern 옵션은 replica sets이거나 replica set shards에서 데이터의 일관성, 고립성을 제어할 수 있게 해준다. 이 옵션은 "local", "available", "majority", "linearizable", "snapshot" 이 5가지 단계가 있다. 이에 대해 알아보도록 하자.

     

     우선은 간단히 어떤 기능이다 정도만 살펴보고 다음 포스팅에 이해를 돕기 위해 예제와 함께 자세히 설명하도록 하겠다. (작성하다 보니 이해가 너무 어려울 듯 한데 다음 포스팅에 최대한 풀어서 설명해보도록 하겠다.)

    •  "local"
      • primary, secondaries의 기본 read operation으로 majority replica set members에 실제로 그 data가 쓰였는지 보장하지 않는다. "local" read concern은 consistent sessions 과 transactions에서도 사용할 수 있다.
      • mongoDB 4.4 부터 transaction내에서 collections과 indexs를 생성할 수 있는데, 암묵적인 collection 생성시(존재하지 않는 collection에 insert를 하면 collection이 생성된다.)에는 상관이 없지만 명시적으로 collection이나 index를 생성할 경우(db.createCollection(), db.createIndex()) transaction은 반드시 read concern을 "local"로 사용해야 한다. 
    • "available"
      • primary, secondaries의 기본 read operation으로 majority replica set members에 실제로 그 data가 쓰였는지 보장하지 않는다.
      • "available"은 "local"과 다르게 consistent sessions과 transaction에서 사용할 수 없다. 또한 sharded cluster일 때 동작이 다른데, 모든 read concerns중 가장 낮은 latency를 제공한다. 하지만 비정상적인 종료로 migration이 실패하거나 migration 정리가 불완전해서 다른 shard의 chunk로 존재하는 shard document인 orphaned document를 반환할 가능성이 있다. 이는 문제의 여지가 있기 때문에 이를 피하기 위해서는 "local"을 사용하는 편이 좋다.
      • 만약 sharded collection이 아니라면 local과 available은 동일하게 동작한다.
    • "majority"
      • majority replica set member가 인정한 데이터를 리턴한다. 이 데이터는 문제가 발생해도 보장되는 data이다.
      • consistent sessions과 transactions에서 사용 가능하다.
      • WiredTiger storage engine 사용시에만 가능하다.
      • multi-document trasactions에서 "majority" read concern은 "majority" wirte concern 에서만 가능하다. 만약 아니라면 transactions에서 read 시 data를 보장하지 못한다.
    •  "linearizable"
      • read operation 이전에 완료된 모든 성공한 majority-acknoledged write를 반영한 data를 리턴한다.
      • query는 결과를 리턴하기 전에 majority replica set member들에게 전파하기 위해 동시에 실행되는 write를 기다린다.
      • 만약 writeConcernMajorityJournalDefault가 true인 경우(dafault로 true임) read operation 후에 majority replica set member들이 문제가있고 재시작한다 하더라도 document는 read operation은 durable(majority node에서 journal file에 쓰여졌다. 즉, 안정적) 하다.
    • "snapshot"
      • multi-document transactions에서 사용 가능하다. multi-document transactions 밖에서 특정 read operation을 할 수 있다.
      • transcation이 caually consistent session의 부분이 아니라면 write concern "majority" transaction commit 에 transaction operations은 majority-commited data의 snapshot으로 부터 read하는 게 보장된다.
      • transcation이 caually consistent session의 부분이라면 write concern "majority" transaction commit 에 transaction operations은 transaction 시작 직전의 causal consistency를 포함하는 majority-commited data의 snapshot으로 부터 read하는 게 보장된다.

     

     "local", "available" option을 보면 가용성을 중요시 한 것을 볼 수 있다.

     

    causally consistent session:  연관된 일련의 "majority" concern인 read operations 과 write operations이 그들의 순서로부터 반영된 인과 관계(causal relationship)을 갖는다.

     

    2022.04.04 - [mongoDB] - MongoDB - Read Concern

    Write Concern

     read concern을 설명한 김에 write concern도 간단하게 소개하도록 하겠다.

     write concern은 standalone mongod, replicaset, sharded cluster에 대한 write operation에 대해 mongoDB에서 요청된 level of acknowledgment을 나타낸다.

     wrie concern은 아래의 3가지 field를 포함한다.

    { w: <value>, j: <boolean>, wtimeout: <number> }

     

    • w: write operation을 전파 할 mongo instance의 수 또는 특정 tags에 대한 요청 옵션이다.
    • j: write operation이 on-disk journal에 쓰였음을 확인하는 옵션이다.
    • wtimout: write 시간 제한 옵션이다.

    이 또한 다음 포스트에 자세하게 설명하도록 하겠다.

     

    추후 MongoDB 문서를 보면서 BASE와 관련 된 내용이 있으면 이 page를 수정하여 내용을 추가하도록 하겠다.

    'mongoDB' 카테고리의 다른 글

    MongoDB - Data modeling (1)  (0) 2022.04.14
    MongoDB - Read Concern  (0) 2022.04.04
    Mongodb - database and collection  (0) 2022.03.27
    MongoDB Time Series Collection - 3  (0) 2022.03.25
    MongoDB Time Series Collection - 2  (0) 2022.03.25

    댓글

Designed by Tistory.