낙관적 잠금이 작동하지 않으면 어떻게해야합니까? 오래되었으므로 두 번째 PUT

이 시나리오는 다음과 같습니다.

  1. 사용자는 GET 요청을 /projects/1하고 ETag를 받습니다 .
  2. 사용자는 1 단계부터 ETag 로 PUT 요청을 /projects/1합니다.
  3. 사용자는 /projects/11 단계에서 ETag 로 다른 PUT 요청을 합니다.

일반적으로 ETag가 오래되었으므로 두 번째 PUT 요청은 412 응답을 수신합니다. 첫 번째 PUT 요청이 자원을 수정 했으므로 ETag가 더 이상 일치하지 않습니다.

그러나 두 PUT 요청이 동시에 전송되거나 정확히 하나씩 전송되면 어떻게됩니까? 첫 번째 PUT 요청에는 PUT # 2가 도착하기 전에 리소스를 처리하고 업데이트 할 시간이 없으므로 PUT # 2가 PUT # 1을 덮어 씁니다. 낙관적 잠금의 요점은 그것이 일어나지 않는 것입니다 …



답변

ETag 메커니즘은 낙관적 잠금을위한 통신 프로토콜 만 지정합니다. 낙관적 잠금을 적용하기 위해 동시 업데이트를 감지하는 메커니즘을 구현하는 것은 애플리케이션 서비스의 책임입니다.

데이터베이스를 사용하는 일반적인 응용 프로그램에서는 일반적으로 PUT 요청을 처리 할 때 트랜잭션을 열어서이 작업을 수행합니다. 일반적으로 해당 트랜잭션 내에서 데이터베이스의 기존 상태를 읽고 (읽기 잠금을 얻기 위해), Etag 유효성을 확인하고, 데이터를 덮어 씁니다 (호환되지 않는 동시 트랜잭션이있을 때 쓰기 충돌을 일으키는 방식으로). 그런 다음 커밋하십시오. 트랜잭션을 올바르게 설정하면 동일한 데이터를 동시에 업데이트하려고하기 때문에 커밋 중 하나가 실패해야합니다. 그런 다음이 트랜잭션 실패를 사용하여 응용 프로그램에 적합한 경우 412를 반환하거나 요청을 다시 시도 할 수 있습니다.


답변

다음 쌍을 원자 적으로 실행해야합니다.

  • 태그의 유효성 검사 (즉, 최신)
  • 리소스 업데이트 (태그 업데이트 포함)

다른 사람들은 이것을 트랜잭션이라고 부릅니다. 그러나 기본적으로이 두 작업의 원자 실행은 타이밍 실수로 다른 하나를 덮어 쓰는 것을 방지합니다. 이것이 없으면 경쟁 조건이 있습니다.

큰 그림을 보더라도 여전히 낙관적 잠금으로 간주됩니다. 업데이트 여부에 관계없이 모든 사용자 또는 데이터를보고있는 사용자가 리소스 자체를 초기 읽기 (GET)로 잠그지 않습니다.

약간의 원자 적 동작이 필요하지만 여러 네트워크 상호 작용에 대한 잠금을 유지하려고 시도하지 않고 단일 요청 (PUT) 내에서 발생합니다. 이것은 낙관적 잠금입니다. 객체는 GET에 의해 잠기지 않았지만 여전히 PUT에 의해 안전하게 업데이트 될 수 있습니다.

이 두 가지 작업을 원자 적으로 실행하는 방법은 여러 가지가 있습니다. 리소스를 잠그는 것이 유일한 옵션은 아닙니다. 예를 들어, 가벼운 스레드 또는 객체 잠금으로 충분할 수 있으며 응용 프로그램의 아키텍처 및 실행 컨텍스트에 따라 다릅니다.


답변

실제로 E-Tag를 확인하고 해당 논리를 제공하는 것은 응용 프로그램 개발자에게 있습니다. E-Tag정적 콘텐츠의 헤더 를 계산하는 방법 만 알고 있기 때문에 웹 서버가 당신을 위해하는 것은 마술이 아닙니다 . 위의 시나리오를 살펴보고 상호 작용이 발생하는 방식을 세분화하십시오.

GET /projects/1

서버는 요청을 수신하고이 버전의 레코드에 대한 E- 태그를 판별하여 실제 컨텐츠와 함께 리턴합니다.

200 - OK
E-Tag: "412"
Content-Type: application/json
{modified: false}

클라이언트는 이제 E-Tag 값을 가지므로 PUT요청에 이를 포함 할 수 있습니다 .

PUT /projects/1
If-Match: "412"
Content-Type: application/json
{modified: true}

이 시점에서 응용 프로그램은 다음을 수행해야합니다.

  • E-Tag가 여전히 올바른지 확인하십시오. “412”== “412”?
  • 그렇다면 업데이트하고 새 E- 태그를 계산하십시오.

성공 응답을 보냅니다.

204 No Content
E-Tag: "543"

다른 요청이 와서 PUT위의 요청과 유사한 작업을 수행하려고하면 서버 코드에서 두 번째로 요청을 평가하면 오류 메시지를 제공해야합니다.

  • E-Tag가 여전히 올바른지 확인하십시오. “412”! = “543”

실패하면 실패 응답을 보내십시오.

412 Precondition Failed

이것은 실제로 작성해야하는 코드입니다. E- 태그는 실제로 모든 텍스트 (HTTP 사양에 정의 된 제한 내) 일 수 있습니다. 숫자 일 필요는 없습니다. 해시 값일 수도 있습니다.


답변

다른 답변을 보완하기 위해 기본 문제를 충실하게 설명하는 ZeroMQ 설명서 에 최고의 인용문 중 하나를 게시합니다 .

완전히 완벽한 MT 프로그램을 만들기 위해 (그리고 말 그대로), 뮤텍스, 잠금 또는 ZeroMQ 소켓을 통해 전송되는 메시지를 제외한 다른 형태의 스레드 간 통신이 필요하지 않습니다.

“완벽한 MT 프로그램”이란 말은 작성하기 쉽고 이해하기 쉽고 모든 프로그래밍 언어와 운영 체제에서 동일한 설계 방식으로 작동하며 대기 상태가없고 포인트가없는 여러 CPU에 걸쳐 확장되는 코드를 의미합니다. 반품 감소.

잠금 및 세마포어 및 중요한 섹션을 사용하여 MT 코드가 전혀 작동하지 않도록 트릭을 배우는 데 몇 년을 소비했다면, 그것이 아무것도 아니라는 사실을 깨닫게되면 역겨워 할 것입니다. 30 년 이상의 동시 프로그래밍에서 배운 교훈이 있다면 상태를 공유하지 마십시오. 맥주를 마시려고하는 두 명의 술꾼과 같습니다. 그들이 좋은 친구인지는 중요하지 않습니다. 조만간 그들은 싸울 것입니다. 그리고 술에 취한 사람이 많을수록 맥주 위에서 서로 더 많이 싸 웁니다. MT 응용 프로그램의 비극적 인 대다수는 술 취한 바 싸움처럼 보입니다.