2.X/1. Getting Started

1-03-10. Optimistic Concurrency Control

drscg 2017. 10. 1. 10:13

Elasticsearch is distributed. When documents are created, updated, or deleted, the new version of the document has to be replicated to other nodes in the cluster. Elasticsearch is also asynchronous and concurrent, meaning that these replication requests are sent in parallel, and may arrive at their destination out of sequence. Elasticsearch needs a way of ensuring that an older version of a document never overwrites a newer version.

Elasticsearch는 분산되어 있다. document가 생성되거나, 업데이트, 삭제되면, document의 새로운 버전은 cluster의 다른 node로 복제된다. Elasticsearch는 또한 비동기적이고 동시성을 가진다. 즉, 이들 복제 request는 병렬로 보내지고, 순서가 엉망인 채로 목적지에 도착할 수도 있다. Elasticsearch는 기존 버전의 document가 새로운 버전의 document를 절대로 덮어쓰지 않을 것을 보장하는 방법이 필요하다.

When we discussed indexget, and delete requests previously, we pointed out that every document has a _version number that is incremented whenever a document is changed. Elasticsearch uses this _version number to ensure that changes are applied in the correct order. If an older version of a document arrives after a new version, it can simply be ignored.

위에서 indexgetdelete request를 이야기할 때, 모든 document가 _version 을 가지며, document가 변경될 때마다 증가한다고 이야기 했다. Elasticsearch는 변경 사항이 올바름 순서로 적용되었다는 것을 보장하기 위해, 이 _version 을 사용한다. 기존 버전의 document가 새로운 버전보다 늦게 도착하면, 간단히 무시한다.

We can take advantage of the _version number to ensure that conflicting changes made by our application do not result in data loss. We do this by specifying the version number of the document that we wish to change. If that version is no longer current, our request fails.

응용프로그램에 의해 만들어지는 변경 사항의 충돌이, 데이터 손실로 나타나지 않도록 보장하기 위해,_version 을 이용할 수 있다. 변경하려는 document의 _version 을 지정함으로써 이것이 가능하다. 해당 버전이 더 이상 최신이 아니면, request는 실패한다.

Let’s create a new blog post:

새로운 블로그 포스트를 생성하자.

PUT /website/blog/1/_create
{
  "title": "My first blog entry",
  "text":  "Just trying this out..."
}

The response body tells us that this newly created document has _version number 1. Now imagine that we want to edit the document: we load its data into a web form, make our changes, and then save the new version.

response body는 이 새로 생성된 document의 _version 이 1 임을 보여준다. 이제 document를 편집한다고 생각해 보자. web form에 이 데이터를 표시하고, 수정하고, 새로운 버전을 저장한다.

First we retrieve the document:

먼저, document를 가져오자.

GET /website/blog/1

The response body includes the same _version number of 1:

response body는 동일한 _version 1 을 포함하고 있다.

{
  "_index" :   "website",
  "_type" :    "blog",
  "_id" :      "1",
  "_version" : 1,
  "found" :    true,
  "_source" :  {
      "title": "My first blog entry",
      "text":  "Just trying this out..."
  }
}

Now, when we try to save our changes by reindexing the document, we specify the version to which our changes should be applied:

이제, document를 다시 색인 하여, 변경 사항을 저장하자. 적용하려는 변경 사항에 version 을 지정한다.

PUT /website/blog/1?version=1 
{
  "title": "My first blog entry",
  "text":  "Starting to get the hang of this..."
}

index에 있는 이 document의 현재 _version 이 1 인 경우에만 업데이트 되어야 한다.

This request succeeds, and the response body tells us that the _version has been incremented to 2:

이 request는 성공한다. 그리고 response body는 _version 이 2 로 증가되었음을 나타낸다.

{
  "_index":   "website",
  "_type":    "blog",
  "_id":      "1",
  "_version": 2
  "created":  false
}

However, if we were to rerun the same index request, still specifying version=1, Elasticsearch would respond with a 409 Conflict HTTP response code, and a body like the following:

그러나, 여전히 version=1 을 지정하여, 동일한 index request를 다시 실행하면, Elasticsearch는 HTTP response code 409 Conflict 로 response할 것이다. body는 아래와 같다.

{
   "error": {
      "root_cause": [
         {
            "type": "version_conflict_engine_exception",
            "reason": "[blog][1]: version conflict, current [2], provided [1]",
            "index": "website",
            "shard": "3"
         }
      ],
      "type": "version_conflict_engine_exception",
      "reason": "[blog][1]: version conflict, current [2], provided [1]",
      "index": "website",
      "shard": "3"
   },
   "status": 409
}

This tells us that the current _version number of the document in Elasticsearch is 2, but that we specified that we were updating version 1.

이것은, Elasticsearch에 있는 document의 현재 _version 이 2 인데, version 1 을 업데이트하려 했다고 알려주는 것이다.

What we do now depends on our application requirements. We could tell the user that somebody else has already made changes to the document, and to review the changes before trying to save them again. Alternatively, as in the case of the widget stock_count previously, we could retrieve the latest document and try to reapply the change.

이에 따라 해야 할 작업은, 응용프로그램의 요구사항에 따라 달라진다. 다른 이가 이미 document를 변경했다고, 다시 저장하기 전에 변경사항을 검토해야 한다고, 사용자에게 알려줘야 한다. 그렇지 않으면, 위의 상품 재고 수(stock_count) 의 예처럼, 예전 document를 가져와, 변경사항을 다시 적용하려 할 수 있다.

All APIs that update or delete a document accept a version parameter, which allows you to apply optimistic concurrency control to just the parts of your code where it makes sense.

document의 수정이나 삭제를 위한 모든 API는 version 매개변수를 사용할 수 있다. version 매개변수는 낙관적인(optimistic) 동시성 제어를 적절한 곳에 코드의 일부분으로 적용할 수 있도록 한다.

Using Versions from an External Systemedit

A common setup is to use some other database as the primary data store and Elasticsearch to make the data searchable, which means that all changes to the primary database need to be copied across to Elasticsearch as they happen. If multiple processes are responsible for this data synchronization, you may run into concurrency problems similar to those described previously.

일반적인 설정은 기본 데이터 저장소로서 어떤 다른 데이터베이스를 사용하고, 데이터를 검색 가능하도록 만들기 위해 Elasticsearch를 사용하는 것이다. 즉, 기본 데이터 저장소에서의 모든 변경 사항을, 변경이 발생하자마자, Elasticsearch에 복사해야 한다. 멀티프로세스가 이 데이터 동기화를 책임지고 있다면, 위에서 언급한 것과 유사한 동시성 문제가 발생할 수 있다.

If your main database already has version numbers—or a value such as timestamp that can be used as a version number—then you can reuse these same version numbers in Elasticsearch by adding version_type=external to the query string. Version numbers must be integers greater than zero and less than about 9.2e+18--a positive long value in Java.

주 데이터베이스가 이미 버전(또는 버전으로 사용될 수 있는 timestamp 같은 값)를 가지고 있다면, query string에 version_type=external 을 추가함으로써, Elasticsearch에 이들 동일한 버전을 그대로 쓸 수 있다. 버전은 0보다 크고, 9.2e+18 보다 작은, 정수여야 한다. Java에서는 양수 long 이다.

The way external version numbers are handled is a bit different from the internal version numbers we discussed previously. Instead of checking that the current _version is the same as the one specified in the request, Elasticsearch checks that the current _version is less than the specified version. If the request succeeds, the external version number is stored as the document’s new _version.

외부 버전을 다루는 방법은, 위에서 언급했던 내부 버전과 약간 다르다. 현재의 _version 이 request에 지정된 버전과 동일하다 는 것을 확인하는 대신, Elasticsearch는 현재의 _version 이 지정한 버전보다 작은지 를 확인한다. request가 성공하면, 외부 버전을 document의 새로운 _version 으로 저장된다.

External version numbers can be specified not only on index and delete requests, but also when creating new documents.

외부 버전은 index, delete request 뿐만 아니라, 새로운 document를 생성 할 때에도 지정할 수 있다.

For instance, to create a new blog post with an external version number of 5, we can do the following:

예를 들면, 외부 버전을 5 로 해서, 새로운 블로그 포스트를 생성하려면, 아래와 같이 한다.

PUT /website/blog/2?version=5&version_type=external
{
  "title": "My first external blog entry",
  "text":  "Starting to get the hang of this..."
}

In the response, we can see that the current _version number is 5:

response에서, 현재 _version 이 5 라는 것을 볼 수 있다.

{
  "_index":   "website",
  "_type":    "blog",
  "_id":      "2",
  "_version": 5,
  "created":  true
}

Now we update this document, specifying a new version number of 10:

이제, 새로운 version 을 10 으로 해서, 이 document를 업데이트해 보자.

PUT /website/blog/2?version=10&version_type=external
{
  "title": "My first external blog entry",
  "text":  "This is a piece of cake..."
}

The request succeeds and sets the current _version to 10:

request는 성공하고, 현재의 _version 은 10 으로 설정된다.

{
  "_index":   "website",
  "_type":    "blog",
  "_id":      "2",
  "_version": 10,
  "created":  false
}

If you were to rerun this request, it would fail with the same conflict error we saw before, because the specified external version number is not higher than the current version in Elasticsearch.

이 request를 다시 실행하면, 이전에 보았던 것과 동일한 충돌 에러를 내면서, 실패할 것이다. 왜냐하면, 지정한 외부 버전이 Elasticsearch의 현재 버전보다 높지 않기 때문이다.


'2.X > 1. Getting Started' 카테고리의 다른 글

1-03-08. Deleting a Document  (0) 2017.10.01
1-03-09. Dealing with Conflicts  (0) 2017.10.01
1-03-11. Partial Updates to Documents  (0) 2017.10.01
1-03-12. Retrieving Multiple Documents  (0) 2017.10.01
1-03-13. Cheaper in Bulk  (0) 2017.10.01