programing

mongodb 문서를 잠글 수 없습니다.필요하다면요?

newsource 2023. 5. 15. 21:55

mongodb 문서를 잠글 수 없습니다.필요하다면요?

mongodb 문서를 하나도 잠글 수 없다는 것을 알고 있습니다. 사실 컬렉션을 잠글 수 있는 방법도 없습니다.

그러나 이 시나리오에서는 두 개 이상의 스레드(또는 프로세스)가 문서를 수정하지 못하도록 방지하는 방법이 필요하다고 생각합니다.제 시나리오는 이렇습니다.

나는 A 유형의 객체가 포함된 컬렉션을 가지고 있습니다.하고, (A 다 의 문 검 있 가 코 지 으 속 배 요 문 추 인 성 가 합 열 니 소 를 에 서 의 며 고 서 를 형 유 색 드 하 를 는 ▁i a ▁that ▁that ▁an ▁in ▁code 합 ▁add , ▁array ▁retrieve 니 다 ▁a ▁some ▁element 가 ▁an ▁( ▁of ▁have 추 ▁of ▁document ▁typea.arr.add(new Thing()그런 다음 mongodb에 문서를 다시 저장합니다.이 코드는 병렬이며, 내 응용 프로그램의 여러 스레드가 이러한 작업을 수행할 수 있으며, 현재로서는 스레드가 동일한 문서에서 이러한 작업을 병렬로 수행하는 것을 방지할 방법이 없습니다.스레드 중 하나가 다른 스레드의 작업을 덮어쓸 수 있으므로 이는 좋지 않습니다.

저는 mongodb 컬렉션에 대한 액세스를 추상화하기 위해 저장소 패턴을 사용하기 때문에 CRUD 작업만 제 마음대로 합니다.

지금 생각해보면, 아마도 나에게 문제를 일으키는 것은 mongodb의 한계가 아니라 저장소 패턴의 한계일 것입니다.어쨌든, 어떻게 하면 이 코드를 "스레드 세이프"로 만들 수 있을까요?이 문제에 대한 잘 알려진 해결책이 있다고 생각합니다만, mongodb와 저장소 패턴에 익숙하지 않아서, 저는 그것을 즉시 보지 않습니다.

감사해요.

이봐, 내가 지금 생각하는 유일한 방법은 상태 매개 변수를 추가하고 문서를 원자적으로 수정할 수 있는 findAndModify() 작업을 사용하는 것입니다.조금 느리긴 하지만 요령을 터득해야 합니다.

따라서 상태 속성을 추가하고 문서를 검색할 때 상태를 "IDLE"에서 "PROCESING"으로 변경한다고 가정해 보겠습니다.그런 다음 문서를 업데이트한 후 상태를 "아이돌"로 다시 업데이트하는 컬렉션에 저장합니다.

코드 예:

var doc = db.runCommand({
              "findAndModify" : "COLLECTION_NAME",
              "query" : {"_id": "ID_DOCUMENT", "status" : "IDLE"},
              "update" : {"$set" : {"status" : "RUNNING"} }
}).value

COLLECTION_NAME 및 ID_DOCUMENT를 올바른 값으로 변경합니다.기본적으로 findAndModify()는 이전 값을 반환합니다. 즉, 클라이언트 측에서 상태 값이 여전히 IDLE 상태가 됩니다.업데이트를 마치면 모든 내용을 다시 저장/업데이트하기만 하면 됩니다.

한 번에 하나의 문서만 수정할 수 있습니다.

도움이 되길 바랍니다.

mongodb 업그레이드 작업 중에 이 질문에 답했습니다.이 질문을 받았을 때와 달리, 현재 mongodb는 문서 수준 잠금을 지원합니다.

보낸 사람: http://docs.mongodb.org/manual/faq/concurrency/

"MongoDB의 잠금은 얼마나 세분화되어 있습니까?

버전 3.0에서 변경되었습니다.

버전 3.0부터 MongoDB는 대부분의 읽기 및 쓰기 작업에 최적의 동시성 제어를 사용하는 WiredTiger 스토리지 엔진과 함께 제공됩니다.WiredTiger는 글로벌, 데이터베이스 및 수집 수준에서 인텐트 잠금만 사용합니다.스토리지 엔진이 두 작업 간의 충돌을 감지하면 쓰기 충돌이 발생하여 MongoDB가 해당 작업을 투명하게 재시도합니다."

스레드 안전한 것을 만들고자 할 때 전형적인 해결책은 잠금 장치(뮤텍스)를 사용하는 것입니다.이는 여기서 설명하는 낙관적 잠금과 반대되는 비관적 잠금이라고도 합니다.

비관적 잠금이 더 효율적인 시나리오가 있습니다(자세한 내용은 여기 참조).또한 구현이 훨씬 쉽습니다(낙관적 잠금의 주요 어려움은 충돌로부터의 복구입니다).

MongoDB는 잠금 메커니즘을 제공하지 않습니다.그러나 이는 애플리케이션 수준(즉, 코드에서)에서 쉽게 구현할 수 있습니다.

  1. 잠금 획득
  2. 문서 읽기
  3. 문서 수정
  4. 문서 작성
  5. 잠금 해제

잠금의 세분성은 전역, 컬렉션별, 레코드/문서별로 다를 수 있습니다.잠금이 더 구체적일수록 성능 저하가 줄어듭니다.

"닥터, 이렇게 하면 아파요"

"그럼 그러지 마!"

기본적으로, 당신이 설명하는 것은 MongoDB든 뭐든 간에, 당신의 알고리즘은 작업을 직렬화해야 하는 지점을 가지고 있는 것처럼 들립니다.그것은 본질적인 병목 현상이 될 것입니다. 그리고 만약 여러분이 그것을 반드시 해야 한다면, 여러분은 그것을 보호하기 위해 어떤 종류의 세마포를 준비해야 할 것입니다.

이제 여러분의 알고리즘을 살펴보도록 하겠습니다.그것을 없앨 수 있습니까?예를 들어, "로컬' 업데이트에 레코드 가져오기; 저장소 레코드"와 같은 충돌 해결 방법으로 처리할 수 있습니까? 그러면 저장소 이후에 새 레코드가 해당 키에 있는 레코드가 될 수 있습니까?

인터넷에서 조사를 하다가 해결책을 발견했기 때문에 나의 질문에 답하는 것.

제가 해야 할 일은 낙관적인 동시성 제어를 사용하는 것이라고 생각합니다.

모든 문서에 타임스탬프, 해시 또는 다른 고유 식별자(UUID 사용)를 추가하는 것으로 구성됩니다.문서를 수정할 때마다 고유 식별자를 수정해야 합니다. 문서를 업데이트하기 전에 다음과 같은 작업을 수행합니다(의사 코드).

var oldUUID = doc.uuid;
doc.uuid = new UUID();
BeginTransaction();
if (GetDocUUIDFromDatabase(doc.id) == oldUUID)
{
   SaveToDatabase(doc);
   Commit();
}
else
{
   // Document was modified in the DB since we read it. We can't save our changes.
   RollBack();
   throw new ConcurencyException();
}

업데이트: Wired Tiger Storage 구현을 기본 엔진으로 사용하는 MongoDB 3.2.2에서는 문서 수준에서 기본 잠금을 사용합니다.버전 3.0에 도입되었지만 버전 3.2.2에서 기본값으로 설정되었습니다.따라서 MongoDB에는 이제 문서 수준 잠금 기능이 있습니다.

4.0에서 MongoDB는 복제본 세트에 대한 트랜잭션을 지원합니다.MongoDB 4.2에서는 샤드 클러스터가 지원될 예정입니다.트랜잭션을 사용하면 충돌하는 쓰기가 발생하면 DB 업데이트가 중단되어 문제가 해결됩니다.

트랜잭션은 성능 면에서 훨씬 더 비용이 많이 들기 때문에 트랜잭션을 불충분한 NoSQL 스키마 설계의 핑계로 사용하지 마십시오!

또는 장소 업데이트를 수행할 수 있습니다.

예:

http://www.mongodb.org/display/DOCS/Updating#comment-41821928

db.users.update( { level: "Sourcerer" }, { '$push' : { 'inventory' : 'magic wand'} }, false, true );

모든 "소스러" 사용자의 인벤토리 배열에 '마법의 지팡이'를 밀어넣습니다.각 문서/사용자에 대한 업데이트는 원자적입니다.

서버가 1대 이상인 시스템을 사용하는 경우 분산 잠금이 필요합니다.

저는 헤이즐캐스트를 선호합니다.

저장하는 동안 엔티티 ID별로 헤이즐캐스트 잠금을 가져오고 데이터를 가져와 업데이트한 다음 잠금을 해제할 수 있습니다.

예: https://github.com/azee/template-api/blob/master/template-rest/src/main/java/com/mycompany/template/scheduler/SchedulerJob.java

그냥 사용하기lock.lock()lock.tryLock()

다음은 스프링 컨텍스트에서 헤이즐캐스트를 구성하는 방법입니다.

https://github.com/azee/template-api/blob/master/template-rest/src/main/resources/webContext.xml

다른 질문에 질문을 쓰는 대신 다음 질문에 답하려고 합니다.이 Wired Tiger Storage가 제가 여기서 지적한 문제를 해결할 수 있을지 궁금합니다: mongodb의 삽입 제한

배열의 요소 순서가 중요하지 않은 경우 $push 연산자는 스레드가 서로 변경 내용을 덮어쓰지 않도록 충분히 안전해야 합니다.

데이터베이스에서 데이터를 가져와(순서는 상관없고 모든 문서를 효율적으로 업데이트해야 함) 작업하고 결과를 다시 기록하는 동일한 애플리케이션의 여러 인스턴스가 있는 경우에도 비슷한 문제가 있었습니다.그러나 모든 인스턴스가 제대로 고정되지 않은 상태에서 인력을 지능적으로 분산하는 대신 동일한 문서를 사용했습니다.

애플리케이션 수준의 잠금을 구현하여 문제를 해결하려고 했습니다. 이를 통해 애플리케이션 수준을 추가하는 것입니다.locked현재 편집 중인 해당 문서의 -필드를 사용하여 다른 응용프로그램 인스턴스가 동일한 문서를 선택하지 않고 다른 인스턴스와 동일한 작업을 수행하여 해당 문서에 대한 시간을 낭비하지 않도록 합니다.

그러나 내 응용 프로그램의 인스턴스를 수십 개 이상 실행할 때 문서를 읽는 시간 간격(사용)find()) 및 설정locked-필드에서 로.true(사용)update()시간이 너무 오래 걸리고 인스턴스가 여전히 데이터베이스에서 동일한 문서를 꺼냈기 때문에 여러 인스턴스를 사용하여 작업 속도를 높이려는 제 생각은 무의미합니다.

다음은 상황에 따라 문제를 해결할 수 있는 세 가지 제안입니다.

  1. 사용하다findAndModify읽기 및 쓰기 작업이 해당 기능을 사용하여 원자적이기 때문에 ().이론적으로 응용프로그램의 한 인스턴스에서 요청한 문서는 다른 인스턴스에 대해 잠긴 것으로 나타납니다.그리고 문서가 잠금 해제되어 다른 인스턴스에 대해 다시 표시되면 문서도 수정됩니다.

  2. 하지만, 만약 당신이 읽기 사이에 다른 것들을 해야 한다면,find()그리고 쓰기update()작업, 트랜잭션을 사용할 수 있습니다.

  3. 또는 문제가 해결되지 않는 경우 응용 프로그램에서 문서를 대량으로 끌어와서 각 인스턴스가 해당 배치에서 임의의 문서를 선택하여 작업하도록 하는 것이 약간의 치즈 솔루션입니다.이 의심스러운 해결책은 우연의 일치로 인해 애플리케이션의 효율성이 저하되지 않는다는 사실에 기반을 두고 있습니다.

MongoDB의 원자 연산자를 사용하고 싶은 것처럼 들립니다. http://www.mongodb.org/display/DOCS/Atomic+Operations

언급URL : https://stackoverflow.com/questions/11076272/its-not-possible-to-lock-a-mongodb-document-what-if-i-need-to