나는 여기에 비슷한 질문이 있다는 것을 알고 있지만 트랜잭션이 필요하거나 원자 연산 또는 2 단계 커밋을 사용하는 경우 일반 RDBMS 시스템으로 다시 전환 하라고 지시합니다 . 두 번째 솔루션이 최선의 선택 인 것 같습니다. 세 번째는 많은 일이 잘못 될 수 있고 모든 측면에서 테스트 할 수 없기 때문에 따르고 싶지 않습니다. 원자 작업을 수행하기 위해 프로젝트를 리팩토링하는 데 어려움을 겪고 있습니다. 나는 이것이 제한된 관점에서 왔는지 (지금까지는 SQL 데이터베이스로만 작업 했음) 또는 실제로 수행 할 수 있는지 여부를 알 수 없습니다.
우리 회사에서 MongoDB를 시범 테스트하고 싶습니다. 우리는 SMS 게이트웨이라는 비교적 간단한 프로젝트를 선택했습니다. 그것은 우리의 소프트웨어가 셀룰러 네트워크에 SMS 메시지를 보낼 수있게하며 게이트웨이는 더러운 작업을 수행합니다. 실제로 다른 통신 프로토콜을 통해 공급자와 통신합니다. 게이트웨이는 또한 메시지 청구를 관리합니다. 서비스를 신청하는 모든 고객은 약간의 크레딧을 구매해야합니다. 메시지가 전송 될 때 시스템은 자동으로 사용자의 잔액을 줄이고 잔액이 부족하면 액세스를 거부합니다. 또한 우리는 타사 SMS 제공 업체의 고객이므로 그들과 자체 균형이있을 수도 있습니다. 우리도 그것들을 추적해야합니다.
복잡성 (외부 청구, 대기중인 SMS 전송)을 줄이면 MongoDB에 필요한 데이터를 저장하는 방법에 대해 생각하기 시작했습니다. SQL 세계에서 온 사용자를 위해 별도의 테이블을 만들고, 다른 하나는 SMS 메시지를 위해, 다른 하나는 사용자 균형에 관한 트랜잭션을 저장하기위한 테이블을 만듭니다. MongoDB의 모든 콜렉션에 대해 별도의 콜렉션을 작성한다고 가정 해 봅시다.
이 단순화 된 시스템에서 다음 단계로 SMS 전송 작업을 상상해보십시오.
-
사용자에게 잔액이 충분한 지 확인하십시오. 크레딧이 충분하지 않으면 액세스 거부
-
세부 정보 및 비용과 함께 SMS 컬렉션에 메시지를 보내고 저장합니다 (라이브 시스템에서는 메시지에
status
특성이 있고 작업이 배달을 위해 메시지를 받아 현재 상태에 따라 SMS 가격을 설정 함). -
보낸 메시지 비용으로 사용자 잔액을 줄입니다.
-
트랜잭션 콜렉션에 트랜잭션을 기록하십시오.
이제 문제가 무엇입니까? MongoDB는 하나의 문서에서만 원자 업데이트를 수행 할 수 있습니다. 이전 흐름에서는 일종의 오류가 발생하여 메시지가 데이터베이스에 저장되지만 사용자 잔액이 업데이트되지 않거나 트랜잭션이 기록되지 않을 수 있습니다.
나는 두 가지 아이디어를 생각해 냈습니다.
-
사용자에 대한 단일 콜렉션을 작성하고 잔액을 필드, 사용자 관련 트랜잭션 및 메시지를 사용자 문서의 하위 문서로 저장하십시오. 문서를 원자 적으로 업데이트 할 수 있기 때문에 실제로 트랜잭션 문제가 해결됩니다. 단점 : 사용자가 많은 SMS 메시지를 보내면 문서 크기가 커지고 4MB 문서 제한에 도달 할 수 있습니다. 그런 시나리오에서 기록 문서를 만들 수는 있지만 이것이 좋은 생각은 아닙니다. 또한 더 큰 데이터를 동일한 큰 문서로 푸시하면 시스템이 얼마나 빠른지 알 수 없습니다.
-
사용자를위한 하나의 컬렉션과 트랜잭션을위한 하나의 컬렉션을 만듭니다. 거래 는 긍정적 인 잔액 변경으로 신용 구매 와 부정적인 잔액 변경으로 전송 된 메시지 의 두 가지 종류가 있습니다. 트랜잭션에는 하위 문서가있을 수 있습니다. 예를 들어, 전송 된 메시지 에서 SMS의 세부 사항은 트랜잭션에 임베드 될 수 있습니다. 단점 : 현재 사용자 잔액을 저장하지 않으므로 사용자가 메시지를 보낼 때마다 메시지를 보낼 때마다 계산해야합니다. 저장된 트랜잭션 수가 증가함에 따라이 계산이 느려질 수 있습니다.
어떤 방법을 선택 해야할지 조금 혼란 스럽습니다. 다른 해결책이 있습니까? 이러한 종류의 문제를 해결하는 방법에 대한 온라인 모범 사례를 찾을 수 없었습니다. NoSQL 세계에 익숙해 지려는 많은 프로그래머들이 처음에 비슷한 문제에 직면하고 있다고 생각합니다.
답변
4.0부터 MongoDB는 다중 문서 ACID 트랜잭션을 갖습니다. 계획은 복제본 세트 배포를 먼저 활성화 한 다음 샤드 클러스터를 활성화하는 것입니다. MongoDB의 트랜잭션은 개발자가 관계형 데이터베이스에서 익숙한 트랜잭션처럼 느껴질 것입니다. 비슷한 의미 및 구문 (와 같은 start_transaction
및 유사한)을 가진 다중 명령문이 commit_transaction
됩니다. 중요하게, 트랜잭션을 가능하게하는 MongoDB의 변경 사항은이를 필요로하지 않는 워크로드의 성능에 영향을 미치지 않습니다.
분산 트랜잭션이 있다고해서 테이블 관계형 데이터베이스 에서처럼 데이터를 모델링해야한다는 의미는 아닙니다. 문서 모델의 힘을 받아들이고 데이터 모델링 의 우수하고 권장되는 사례 를 따르십시오 .
답변
거래없는 생활
트랜잭션은 ACID 속성을 지원 하지만에 트랜잭션이 없지만 MongoDB
원자 적 연산이 있습니다. 원자 작업은 단일 문서에서 작업 할 때 다른 사람이 문서를보기 전에 해당 작업이 완료된다는 것을 의미합니다. 그들은 우리가 변경 한 모든 것을 보거나 전혀 보지 못할 것입니다. 원자 연산을 사용하면 관계형 데이터베이스에서 트랜잭션을 사용하여 달성 한 것과 동일한 결과를 얻을 수 있습니다. 그 이유는 관계형 데이터베이스에서 여러 테이블을 변경해야하기 때문입니다. 일반적으로 결합해야하는 테이블이므로 한 번에 모두 수행하려고합니다. 이를 위해서는 여러 테이블이 있으므로 트랜잭션을 시작하고 모든 업데이트를 수행 한 다음 트랜잭션을 종료해야합니다. 하지만 함께MongoDB
데이터 를 문서 에 미리 포함시킬 것이므로 계층 구조가있는 이러한 풍부한 문서 이기 때문에 데이터를 포함 할 것 입니다. 우리는 종종 같은 일을 할 수 있습니다. 예를 들어 블로그 예제에서 블로그 게시물을 원자 적으로 업데이트하려면 전체 블로그 게시물을 한 번에 업데이트 할 수 있기 때문에 업데이트 할 수 있습니다. 마치 여러 관계형 테이블 인 것처럼 포스트 컬렉션 및 주석 컬렉션을 업데이트 할 수 있도록 트랜잭션을 열어야 할 것입니다.
MongoDB
트랜잭션 부족을 극복하기 위해 취할 수있는 접근 방식은 무엇 입니까?
- 재구성 -코드를 재구성하여 단일 문서 내에서 작업하고 해당 문서 내에서 제공하는 원자 적 작업을 활용합니다. 우리가 그렇게하면 보통 모든 것이 준비됩니다.
- 소프트웨어로 구현 -중요한 섹션을 만들어 소프트웨어 잠금을 구현할 수 있습니다. find와 modify를 사용하여 테스트, 테스트 및 설정을 할 수 있습니다. 필요한 경우 세마포어를 만들 수 있습니다. 어쨌든 그것은 더 큰 세상이 작동하는 방식입니다. 우리가 그것에 대해 생각하면, 한 은행이 다른 은행으로 돈을 이체 해야하는 경우 동일한 관계형 시스템에 살고 있지 않습니다. 그리고 그들 각자는 종종 자신의 관계형 데이터베이스를 가지고 있습니다. 그리고 한 데이터베이스 내에서 하나의 시스템 내에서만 해당 데이터베이스 시스템에서 트랜잭션을 시작하고 트랜잭션을 종료 할 수 없더라도 해당 작업을 조정할 수 있어야합니다. 따라서 소프트웨어를 통해 문제를 해결할 수있는 방법이 있습니다.
- 관용 -현대 웹 응용 프로그램과 엄청난 양의 데이터를 사용하는 다른 응용 프로그램에서 종종 작동하는 최종 접근 방식은 약간의 불일치를 허용하는 것입니다. 예를 들어 Facebook에서 친구 피드에 대해 이야기하는 경우 모두가 벽 업데이트를 동시에 보는 것이 중요하지 않습니다. 괜찮다면, 한 사람이 몇 초 동안 뛰고 그들은 따라 잡습니다. 많은 시스템 설계에서 모든 것이 완벽하게 일관성을 유지하고 모든 사람이 완벽하게 일관성 있고 동일한 데이터베이스 뷰를 갖는 것이 중요하지 않은 경우가 많습니다. 따라서 일시적인 약간의 불일치를 간단히 허용 할 수 있습니다.
Update
, findAndModify
, $addToSet
(업데이트 내) $push
(업데이트 이내) 동작들은 하나의 문서 내에서 원자 적으로 동작한다.
답변
Tokutek 이 확인하십시오 . 그들은 거래뿐만 아니라 성능 향상을 약속하는 Mongo 플러그인을 개발합니다.
답변
트랜잭션 무결성이 필수 인 경우 MongoDB를 사용하지 말고 트랜잭션을 지원하는 시스템의 구성 요소 만 사용하십시오. 비 ACID 호환 구성 요소에 ACID와 유사한 기능을 제공하기 위해 구성 요소 위에 무언가를 구축하는 것은 매우 어렵습니다. 개별 사용 사례에 따라 어떤 방식으로 조치를 트랜잭션 및 비 트랜잭션 조치로 분리하는 것이 좋습니다.
답변
이제 문제가 무엇입니까? MongoDB는 하나의 문서에서만 원자 업데이트를 수행 할 수 있습니다. 이전 흐름에서는 일종의 오류가 발생하고 메시지가 데이터베이스에 저장되지만 사용자의 잔액이 줄어들지 않거나 트랜잭션이 기록되지 않을 수 있습니다.
이것은 실제로 문제가되지 않습니다. 언급 한 오류는 논리적 (버그) 또는 IO 오류 (네트워크, 디스크 오류)입니다. 이러한 종류의 오류는 트랜잭션이없는 저장소와 트랜잭션 저장소가 일관성이없는 상태가 될 수 있습니다. 예를 들어, 이미 SMS를 전송했지만 메시지 저장 중 오류가 발생하면 SMS 전송을 롤백 할 수 없습니다. 즉, 기록되지 않으며 사용자 잔액이 감소하지 않습니다.
여기서 실제 문제는 사용자가 경쟁 조건을 이용하고 자신의 잔액보다 더 많은 메시지를 보낼 수 있다는 것입니다. 이는 균형 필드 잠금 (큰 병목 현상이 발생 함)을 사용하여 트랜잭션 내부에서 SMS 전송을 수행하지 않는 한 RDBMS에도 적용됩니다. MongoDB에 대한 가능한 해결책은 findAndModify
음수 전송이 허용되지 않고 금액 (원자 증가)이 아닌 경우 먼저 잔액을 줄이고 잔액을 확인하는 데 사용하는 것입니다. 긍정적 인 경우 계속 발송하고 금액을 환불하지 못한 경우. 잔액 이력 수집을 유지하여 잔액 필드를 수정 / 확인할 수 있습니다.
답변
이 프로젝트는 간단하지만 지불을위한 거래를 지원해야하므로 모든 것이 어려워집니다. 예를 들어 포럼이나 채팅 항목을 잃어 버리면 아무도 신경 쓰지 않기 때문에 수백 가지 컬렉션 (포럼, 채팅, 광고 등)이있는 복잡한 포털 시스템이 더 간단합니다. 반면에 심각한 문제인 결제 거래를 잃어버린 경우.
따라서 MongoDB의 파일럿 프로젝트를 정말로 원한다면 그 점 에서 간단한 프로젝트를 선택하십시오 .
답변
유효한 이유로 MongoDB에 트랜잭션이 없습니다. 이것은 MongoDB를 더 빠르게 만드는 것 중 하나입니다.
귀하의 경우, 거래가 필수적이라면 mongo는 적합하지 않은 것 같습니다.
RDMBS + MongoDB 일 수 있지만 복잡성이 추가되어 응용 프로그램을 관리하고 지원하기가 더 어려워집니다.