ElasticSearch의 동시성 제어

0


ElasticSearch와 같은 분산형 시스템을 다룰 때 동시성 때문에 문제가 생길 수도 있다.
ElasticSearch는 어떻게 동시성 문제를 제어할까?

우선 그 전에 동시성 문제가 무엇인지 알아야한다.

두 클라이언트가 동시에 동일한 작업을 수행하려고 한다면 어떻게 될까?
만약 버튼을 누를 때마다 문서(document)에 저장된 숫자가 1씩 증가하는 환경이 존재하고
이에 더불어 두 클라이언트가 대규모 분산 웹에서 애플리케이션을 실행하고 있다고 가정해보자 또
두 사람이 웹사이트에서 두 개의 다른 웹 서버를 통해 같은 같은 버튼을 동시에 보고 있다고 치자

문서에 저장된 숫자가 10인 시점에, 두 클라이언트가 버튼을 동시에 누른 다음 Elasticsearch에서 문서의 숫자를 조회한다면 12가 아닌 11이 된다.

버튼을 눌러 현재 숫자를 업데이트해서 새 숫자를 만드는데 짧은 시간 간격이 있고 이로 인해 동시성 문제가 발생해 오류가 생길 수 있다는 말이다.

그럼 어떻게 해야 할까?

다행히 ElasticSearch에는 '낙천적(Optimistic) 동시성 제어'라는 해결책이 있다.
이는 우리가 문서 업데이트에 관해 얘기했을 때 버전(_version) 필드가 사용된 방식과 비슷하다.
차이점은 단일 버전 필드 대신 '순서 번호(sequence number)''주요 용어(primary term)'를 함께 가져옴으로써 이 문서의 고유한 연대 기록을 갖게 된다.

예를 들어보자 위의 사진에서 두명의 클라이언트가 숫자가 10인 문서를 보고있으며, 각각의 시퀀스 넘버는 9이다. 하지만 한명이 버튼을 눌러 숫자를 11로 만들었다면 이 문서의 시퀀스 넘버는 10이 되고 두번째 유저가 버튼을 누르려 할때는 시퀀스 번호가 9가 아닌 10이 되기 때문에 에러가 발생할 것이다. 이것이 낙천적 동시성 제어이다.

그럼 실제로 어떻게 작동하는지 알아보자

curl -XGET 127.0.0.1:9200/movies/_doc/109487?pretty

위 명령어를 통해 인터스텔라 문서를 확인해보면 다음과 같이 _seq_no와 _primary_term이 포함된 것을 알 수 있다.

이후 특정한 시퀀스 넘버와 프라이머리 텀을 가지는 문서의 수정을 수행해보자

curl -XPUT "127.0.0.1:9200/movies/_doc/109487?if_seq_no=7&if_primary_term=1" -d '
{
	"genres": ["IMAX", "Sci-Fi"],
    "title": "Interstellar foo",
    "year": 2014
}'

그럼 다음과 같이 시퀀스 넘버가 변경된 것을 확인할 수 있다.

그럼 같은 걸 다시 한번 해보면 어떻게 될까? 우리가 동시에 같은 일을 하려는 다른 클라이언트라고 가정해 보자

위 화살표를 두어 번 눌러 이전의 요청으로 돌아가 '주요 용어' 1의 '순서 번호' 7을 특정해서 업데이트를 시도해본다. 그럼 당연하게도 오류가 발생한것을 확인할 수 있다.

따라서 이 두 업데이트를 동시에 수행한다고 가정할 경우, 둘 중 하나의 요청만 성공할 것이고 이는 정확히 우리가 원하는 바이다.

그렇다면 '순서 번호'를 요청할때 일일이 작성을 해주어야 할까? '순서 번호'를 직접 사용할 수 있지만 귀찮은 방법이고 대신 우리는 'retry_on_conflict' 변수를 Elasticsearch를 통해 사용할 수 있다.

curl -XPOST 127.0.0.1:9200/movies/_doc/108487/_update?retry_on_conflict=5 -d '
{
	"doc": {
    	"title": "Interstellar typo"
    }
}'

위 명령어는 업데이트시 동시성 충돌이 발생할 경우 새 시퀀스 번호로 최대 5번까지 자동으로 다시 시도한다는 의미이다.

profile
Software engineer who is interested in server development, computer vision, and soccer

0개의 댓글