복붙노트

[MONGODB] 어떻게하여 MongoDB에서 거래의 부족을 해결하려면?

MONGODB

어떻게하여 MongoDB에서 거래의 부족을 해결하려면?

나는 여기에 비슷한 질문이 알고 있지만 내가 거래를 필요로하거나 커밋 원자 작업 또는 두 개의 상을 사용하는 경우 그들 중 일반 RDBMS 시스템으로 전환하라고 말하고있다. 두 번째 솔루션은 최선의 선택을 보인다. 많은 일이 잘못 갈 수와 내가 모든 측면에서 테스트 할 수 있다는 것 때문에 세 번째 나는 수행하지 않으. 나는 원자 작업을 수행 할 수있는 내 프로젝트를 리팩토링 힘든 시간을 보내고 있습니다. 나는 (나는 단지 지금까지 SQL 데이터베이스와 함께 일한)이 내 한정된 관점에서 온다 여부를 모르거나 실제로 수행 할 수 없습니다 수 있는지 여부를 지정합니다.

우리는 우리 회사에서 파일럿 테스트 MongoDB를하고 싶습니다. 의 SMS 게이트웨이 - 우리는 상대적으로 간단한 프로젝트를 선택했습니다. 그것은 우리의 소프트웨어는 셀룰러 네트워크에 SMS 메시지를 보낼 수 있으며 게이트웨이는 더러운 일을 수행합니다 실제로 다른 통신 프로토콜을 통해 공급자와 통신. 게이트웨이는 또한 메시지의 청구를 관리합니다. 서비스에 적용 모든 고객은 일부 크레딧을 구매해야한다. 시스템은 자동으로 메시지가 송신되는 사용자의 잔액을 감소 시키며 균형이 불충분 한 경우, 액세스를 거부한다. 우리는 타사 SMS 제공 업체의 고객은 또한 있기 때문에, 우리는 또한 우리 자신의 균형을 그들과 함께있을 수 있습니다. 우리는뿐만 아니라 그 추적 할 수 있습니다.

나는 약간의 복잡성을 줄일 경우 내가 MongoDB를 사용하여 필요한 데이터를 저장할 수있는 방법에 대해 생각하기 시작 (외부 청구를 SMS가 전송 대기). 은 SQL 세계에서오고, 나는 사용자의 균형에 대한 트랜잭션을 저장하기위한 별도의 사용자를위한 테이블, SMS 메시지에 대한 또 하나, 하나를 만들 것입니다. 하자 내가 MongoDB에있는 모든 이들에 대해 별도의 컬렉션을 만들 말한다.

이 단순화 된 시스템에서 다음 단계로 작업을 보내는 SMS를 상상해 :

이제 문제는 무엇인가? MongoDB를 단지 하나 개의 문서에 원자 갱신 할 수 있습니다. 이전의 흐름에서는 오류의 어떤 종류에 섬뜩한과 메시지가 데이터베이스에 저장됩니다 있지만 사용자의 균형이 업데이트되지 및 / 또는 트랜잭션이 로그인하지 않은 일이 발생할 수 있습니다.

나는이 개 아이디어를 내놓았다 :

나는 약간의 비트가 선택하는 어떤 방법에 대해 혼란 스러워요. 거기에 다른 솔루션이 있습니까? 나는 이러한 종류의 문제를 해결하려면 방법에 대해 온라인 어떤 모범 사례를 찾을 수 없습니다. 나는 NoSQL의 세계에 익숙해하려고하는 많은 프로그래머가 처음에 비슷한 문제에 직면하고있다 같아요.

해결법

  1. ==============================

    1.4.0로, MongoDB를 다중 문서 ACID 트랜잭션을해야합니다. 계획은 분산됩니다 클러스터이어서 제 복제 세트 배치 사람들을 활성화한다. MongoDB의의 거래는 거래 개발자가 관계형 데이터베이스에서 잘 알고있는 것처럼 느낄 것이다 - 그들은 비슷한 의미하고 (start_transaction 및 commit_transaction 같은) 구문을 사용하여, 다중 문 수 있습니다. 중요한 트랜잭션을 사용하여 MongoDB에 대한 변경이 그들을 필요로하지 않는 워크로드 성능에 영향을주지 않습니다.

    4.0로, MongoDB를 다중 문서 ACID 트랜잭션을해야합니다. 계획은 분산됩니다 클러스터이어서 제 복제 세트 배치 사람들을 활성화한다. MongoDB의의 거래는 거래 개발자가 관계형 데이터베이스에서 잘 알고있는 것처럼 느낄 것이다 - 그들은 비슷한 의미하고 (start_transaction 및 commit_transaction 같은) 구문을 사용하여, 다중 문 수 있습니다. 중요한 트랜잭션을 사용하여 MongoDB에 대한 변경이 그들을 필요로하지 않는 워크로드 성능에 영향을주지 않습니다.

    자세한 내용은 자세한 내용은 여기를 참조하십시오.

    분산 트랜잭션을 갖는, 당신은 표 관계형 데이터베이스처럼 데이터를 모델링해야한다는 것을 의미하지 않는다. 문서 모델의 힘을 포용하고 좋은 데이터 모델링의 권장 사항을 따르십시오.

  2. ==============================

    2.트랜잭션은 ACID 속성을 지원하지만, MongoDB를 아무런 거래도 없다하더라도, 우리는 원자 작업을해야합니까. 음, 원자 연산 수단은 다른 사람이 문서를보기 전에 그 일이 완료됩니다 하나의 문서 작업 때. 그들은 모두 우리가 변경 또는 그들 중 누구도를 볼 수 있습니다. 그리고 원자 작업을 사용하여, 당신은 종종 우리가 관계형 데이터베이스에 트랜잭션을 사용하여 수행 한 것과 같은 일을 수행 할 수 있습니다. 그리고 그 이유는 관계형 데이터베이스에, 우리는 여러 테이블에서 변경해야한다는 것입니다. 일반적으로 필요한 테이블을 조인하고 우리는 한 번에 모든 것을 수행 할 수 있도록. 여러 테이블이 있기 때문에 그리고 그것을 할, 우리는 트랜잭션을 시작하고 모든 업데이트를 수행하고 트랜잭션을 종료해야합니다. 그러나 MongoDB를, 우리가 문서를 사전에 가입하는거야 때문에 우리는 포함 데이터에거야 그들은 계층 구조를 가지고 이러한 다양한 문서이야. 우리는 종종 같은 일을 수행 할 수 있습니다. 우리는 한 번에 전체 블로그 게시물을 업데이트 할 수 있기 때문에 우리가 확인하기를 원한다면 예를 들어, 블로그 예를 들어, 우리는 원자 블로그 포스트를 업데이트하는 것이, 우리는 할 수 있습니다. 이 관계형 테이블의 무리 인 것처럼 어디에서, 우리는 아마 우리가 포스트 수집 및 의견 수집을 업데이트 할 수 있도록 트랜잭션을 열어야 할 것입니다.

    트랜잭션은 ACID 속성을 지원하지만, MongoDB를 아무런 거래도 없다하더라도, 우리는 원자 작업을해야합니까. 음, 원자 연산 수단은 다른 사람이 문서를보기 전에 그 일이 완료됩니다 하나의 문서 작업 때. 그들은 모두 우리가 변경 또는 그들 중 누구도를 볼 수 있습니다. 그리고 원자 작업을 사용하여, 당신은 종종 우리가 관계형 데이터베이스에 트랜잭션을 사용하여 수행 한 것과 같은 일을 수행 할 수 있습니다. 그리고 그 이유는 관계형 데이터베이스에, 우리는 여러 테이블에서 변경해야한다는 것입니다. 일반적으로 필요한 테이블을 조인하고 우리는 한 번에 모든 것을 수행 할 수 있도록. 여러 테이블이 있기 때문에 그리고 그것을 할, 우리는 트랜잭션을 시작하고 모든 업데이트를 수행하고 트랜잭션을 종료해야합니다. 그러나 MongoDB를, 우리가 문서를 사전에 가입하는거야 때문에 우리는 포함 데이터에거야 그들은 계층 구조를 가지고 이러한 다양한 문서이야. 우리는 종종 같은 일을 수행 할 수 있습니다. 우리는 한 번에 전체 블로그 게시물을 업데이트 할 수 있기 때문에 우리가 확인하기를 원한다면 예를 들어, 블로그 예를 들어, 우리는 원자 블로그 포스트를 업데이트하는 것이, 우리는 할 수 있습니다. 이 관계형 테이블의 무리 인 것처럼 어디에서, 우리는 아마 우리가 포스트 수집 및 의견 수집을 업데이트 할 수 있도록 트랜잭션을 열어야 할 것입니다.

    그래서 우리는 거래의 부족을 극복하기 위해 MongoDB를 취할 수있는 우리의 접근 방식은 무엇입니까?

    업데이트, findAndModify, (갱신 이내) $ addToSet 및 (갱신 이내) $ 푸시 작업은 하나의 문서 내에서 원자 적으로 운영하고 있습니다.

  3. ==============================

    3.Tokutek에 의해, 이것 좀 봐. 그들은 약속은 거래뿐만 아니라 성능을 강화하지 않는 것이 몽고에 대한 플러그인을 개발한다.

    Tokutek에 의해, 이것 좀 봐. 그들은 약속은 거래뿐만 아니라 성능을 강화하지 않는 것이 몽고에 대한 플러그인을 개발한다.

  4. ==============================

    4.지점에 가져 : 트랜잭션 무결성이 필수 인 경우 다음 MongoDB를 사용하지 않지만 트랜잭션을 지원하는 시스템의 구성 요소 만 사용합니다. 그것은 비 ACID 준수 구성 요소에 대한 ACID-유사한 기능을 제공하기 위해 구성 요소의 상단에 빌드 뭔가 매우 어렵다. 각각의 쓰임새에 따라서는 어떤 방법으로 트랜잭션 및 비 트랜잭션 작업에 별도의 행동을 이해 할 수있다 ...

    지점에 가져 : 트랜잭션 무결성이 필수 인 경우 다음 MongoDB를 사용하지 않지만 트랜잭션을 지원하는 시스템의 구성 요소 만 사용합니다. 그것은 비 ACID 준수 구성 요소에 대한 ACID-유사한 기능을 제공하기 위해 구성 요소의 상단에 빌드 뭔가 매우 어렵다. 각각의 쓰임새에 따라서는 어떤 방법으로 트랜잭션 및 비 트랜잭션 작업에 별도의 행동을 이해 할 수있다 ...

  5. ==============================

    5.이건 정말 문제가되지 않습니다. 당신이 언급 한 오류 중 하나 논리적 (버그) 또는 IO 오류 (네트워크, 디스크 오류)입니다. 오류의 이러한 종류의 비 일관성있는 상태에서 모두 transactionless 및 트랜잭션 저장을 남길 수 있습니다. 예를 들어, 이미 SMS를 전송했지만 메시지 저장 중 오류가 발생하는 경우 - 이것은 가능하지 롤백 SMS 등 사용자의 균형이 감소되지 않을 것이며,이 기록되지 않을 것이다 수단 보내는

    이건 정말 문제가되지 않습니다. 당신이 언급 한 오류 중 하나 논리적 (버그) 또는 IO 오류 (네트워크, 디스크 오류)입니다. 오류의 이러한 종류의 비 일관성있는 상태에서 모두 transactionless 및 트랜잭션 저장을 남길 수 있습니다. 예를 들어, 이미 SMS를 전송했지만 메시지 저장 중 오류가 발생하는 경우 - 이것은 가능하지 롤백 SMS 등 사용자의 균형이 감소되지 않을 것이며,이 기록되지 않을 것이다 수단 보내는

    여기 진짜 문제는 사용자가 경쟁 조건을 활용하고 자신의 균형을 허용하는 것보다 더 많은 메시지를 보낼 수 있습니다. 당신이 (큰 병목 것) 밸런스 필드 잠금과 내부 거래를 보내는 SMS를하지 않는 한 이것은 또한, RDBMS에 적용됩니다. MongoDB에 대한 가능한 해결책은 균형을 줄이고이를 확인 그것의 음수 해제하면 보내는 경우 양 (원자 증분) 환불 제 findAndModify를 사용하는 것이있다. 긍정적 인 경우, 보내는 경우이 금액을 환불 실패 계속. 균형 기록 수집은 또한 도움 수정에 유지 될 수 / 밸런스 필드를 확인합니다.

  6. ==============================

    6.이 프로젝트는 간단하지만, 당신은 모든 일을 어렵게 지불에 대한 트랜잭션을 지원해야합니다. 당신이 포럼 또는 채팅 항목, 아무도 정말 걱정을 잃으면 있기 때문에 그래서, 예를 들어, 컬렉션의 수백 복잡한 포털 시스템 (등 포럼, 채팅, 광고, ...) 일부에 대해 간단입니다. 당신이 경우, otherhand에 심각한 문제의 지불 거래를 잃게됩니다.

    이 프로젝트는 간단하지만, 당신은 모든 일을 어렵게 지불에 대한 트랜잭션을 지원해야합니다. 당신이 포럼 또는 채팅 항목, 아무도 정말 걱정을 잃으면 있기 때문에 그래서, 예를 들어, 컬렉션의 수백 복잡한 포털 시스템 (등 포럼, 채팅, 광고, ...) 일부에 대해 간단입니다. 당신이 경우, otherhand에 심각한 문제의 지불 거래를 잃게됩니다.

    당신이 정말로 MongoDB를위한 시범 사업을 원하는 경우에 따라서, 그 점에서 간단 하나를 선택합니다.

  7. ==============================

    7.거래는 유효한 이유 MongoDB를 결석입니다. 이 빠른 MongoDB를 만들 것들 중 하나입니다.

    거래는 유효한 이유 MongoDB를 결석입니다. 이 빠른 MongoDB를 만들 것들 중 하나입니다.

    트랜잭션이 필수 인 경우 귀하의 경우에는, 몽고 좋은 적합하지 보인다.

    RDMBS + MongoDB가 될 수 있지만, 그 복잡성을 추가하고 어렵게 관리 및 지원 응용 프로그램을 만들 것입니다.

  8. ==============================

    8.이것은 아마 내가 MongoDB를위한 기능과 같은 트랜잭션을 구현에 관한 볼 수있는 가장 좋은 블로그입니다.!

    이것은 아마 내가 MongoDB를위한 기능과 같은 트랜잭션을 구현에 관한 볼 수있는 가장 좋은 블로그입니다.!

    동기화 신고 : 단지 마스터 문서에서 통해 데이터를 복사하는 가장

    작업 대기열 : 매우 일반적인 목적은, 케이스의 95 %를 해결합니다. 대부분의 시스템은 주위 어쨌든 적어도 하나의 작업 대기열이 필요합니다!

    두 단계 커밋 :이 기술은 각 엔티티는 항상 모든 정보가 일관성있는 상태에 도달하기 위해 필요한 것을 확인

    로그인 화해 : 가장 강력한 기술, 금융 시스템에 이상적

    버전은 : 절연을 제공하고 복잡한 구조를 지원

    추가 정보를 원하시면이 읽기 : https://dzone.com/articles/how-implement-robust-and

  9. ==============================

    9.이 늦게하지만 앞으로이 의지의 도움을 생각합니다. 나는이 문제를 해결하기 위해 메이크업을위한 큐 레디 스를 사용합니다.

    이 늦게하지만 앞으로이 의지의 도움을 생각합니다. 나는이 문제를 해결하기 위해 메이크업을위한 큐 레디 스를 사용합니다.

    하지만 isRunning는 () setStateToRelease () setStateToRunning () 분리 그것의 자신이나 다른 사람이 다시 경쟁 조건에 직면 필요는 없다. 이를 위해 나는 ACID 목적과 확장 성을 위해 레디 스를 선택합니다. 그것에 대해 레디 스 문서 이야기 트랜잭션입니다 :

    추신: 내 서비스가 이미 그것을 사용하기 때문에, 당신은 그렇게 다른 방법으로 지원 격리를 사용할 수 있습니다 레디 스를 사용합니다. 내 코드의 action_domain은 다른 사용자를 차단하지 않는 사용자 A의 사용자 A 블록 동작이들만 조치 1 호를 필요로 할 때에 이상입니다. 아이디어는 각 사용자의 잠금에 대한 고유 키가됩니다.

  10. ==============================

    10.거래는 MongoDB를 4.0에서 사용할 수 있습니다. 여기 샘플

    거래는 MongoDB를 4.0에서 사용할 수 있습니다. 여기 샘플

    // Runs the txnFunc and retries if TransientTransactionError encountered
    
    function runTransactionWithRetry(txnFunc, session) {
        while (true) {
            try {
                txnFunc(session);  // performs transaction
                break;
            } catch (error) {
                // If transient error, retry the whole transaction
                if ( error.hasOwnProperty("errorLabels") && error.errorLabels.includes("TransientTransactionError")  ) {
                    print("TransientTransactionError, retrying transaction ...");
                    continue;
                } else {
                    throw error;
                }
            }
        }
    }
    
    // Retries commit if UnknownTransactionCommitResult encountered
    
    function commitWithRetry(session) {
        while (true) {
            try {
                session.commitTransaction(); // Uses write concern set at transaction start.
                print("Transaction committed.");
                break;
            } catch (error) {
                // Can retry commit
                if (error.hasOwnProperty("errorLabels") && error.errorLabels.includes("UnknownTransactionCommitResult") ) {
                    print("UnknownTransactionCommitResult, retrying commit operation ...");
                    continue;
                } else {
                    print("Error during commit ...");
                    throw error;
                }
           }
        }
    }
    
    // Updates two collections in a transactions
    
    function updateEmployeeInfo(session) {
        employeesCollection = session.getDatabase("hr").employees;
        eventsCollection = session.getDatabase("reporting").events;
    
        session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } );
    
        try{
            employeesCollection.updateOne( { employee: 3 }, { $set: { status: "Inactive" } } );
            eventsCollection.insertOne( { employee: 3, status: { new: "Inactive", old: "Active" } } );
        } catch (error) {
            print("Caught exception during transaction, aborting.");
            session.abortTransaction();
            throw error;
        }
    
        commitWithRetry(session);
    }
    
    // Start a session.
    session = db.getMongo().startSession( { mode: "primary" } );
    
    try{
       runTransactionWithRetry(updateEmployeeInfo, session);
    } catch (error) {
       // Do something with error
    } finally {
       session.endSession();
    }
    
  11. from https://stackoverflow.com/questions/6635718/how-to-work-around-the-lack-of-transactions-in-mongodb by cc-by-sa and MIT license