엘라스틱 서치란
- 분산형 검색, 분석 엔진이다.
- 확장 데이터 저장, 벡터 DB 역할 가능
- 하나의 클러스터에 여러개의 노드가 존재할 수 있다.
인덱스
-
샤드 설명
- 샤드는 인덱스(ES의 논리적 그룹핑 단위)를 더 작은 조각으로 나누는 방법이다.
- 각 조각은 샤드(Shard)라 부른다.
- 샤딩은 인덱스 레벨에서 이뤄진다.
- 주요 목적은 데이터 볼륨을 가로로(Horizontally) 늘리기(?) 위함이다.
- 인덱스가 저장할 수 있는 문서 수를 늘릴 수 있다. 따라서, 노드에 인덱스 수를 늘릴 수 있다.
- 각 샤드는 Apache Lucene Index 이다(?)
- ES 인덱스는 하나 이상의 Apache Lucene Indices 이다.
- 샤드는 정해진 사이즈가 없으며, Doc이 추가될 수록 증가할 수 있다. Doc은20억개 가량 저장할 수 있따(?)
- 인덱스는 디폴트로 싱글 샤드를 가진다.
- 샤딩은 쿼리 Throughput을 향상 시킬 수 있다.
※ 퀴즈)
인덱스가 사이즈를 늘리게 된다면, 하나의 노드로는 부족할 수 있다. 결국 클러스터 안의 어떠한 노드도 해당 인덱스를 가진 문서를 수용할 수 없게 된다. 따라서, 데이터 볼륨 스케일을 늘리는 것은 샤딩으로 가능하다. 샤드 Replica 증가가 곧 노드 증가로 이어진다.
"샤드는 인덱스를 찢는다!!"
Managing Documents
# 인덱스 삭제 DELETE /pages # 인덱스 생성 PUT /products { "settings": { "number_of_shards": 2, "number_of_replicas": 2 } } # 인덱스 목록 조회 GET /_cat/indices # 인덱스 결과 조회 GET /products # 인덱스 도큐먼트 지정(랜덤 ID, 지정 ID) POST /products/_doc { "name": "Coffee Maker", "price": 64, "in_stock": 10 } POST /products/_doc/100 { "name": "Toster", "price": 49, "in_stock": 4 } # ID 포함 결과 조회 GET /product/_doc/100 # 값 업데이트, 추가 및 조회 POST /product/_update/100 { "doc": { "in_stock": 3 } } # 새로운 필드 추가 POST /product/_update/100 { "doc": { "tags": ["electronics"] } } GET /product/_doc/100 # 스트립트 업데이트 POST /products/_update/100 { "script": { "source": "ctx._source.in_stock = 10" } } # 스크립트 업데이트 with 파라미터 사용 POST /products/_update/100 { "script": { "source": "ctx._source.in_stock -= params.quantity", "params": { "quantity": 4 } } } # 스크립트 업데이트 with 조건문 POST /products/_update/100 { "script": { "source": """ if (ctx._source.in_stock > 0) { ctx._source.in_stock--; } """ } } |
Routing
- 엘라스틱서치가 문서를 저장한 위치를 아는 것
- 엘라스틱서치가 인덱싱된 문서를 찾는 것
- 샤딩된 문서 위치를 해석하는 것
위의 것은 라우팅과 관련이 있다.
- 기본 라우팅 전략은 문서가 균등하게 분산되도록 한다.
- 문서를 인덱싱, 검색 및 업데이트할 때 공식이 사용된다.
shard_num = hash(_routing) % num_primary_shards
엘라서틱서치가 문서를 읽는 원리
- 읽기 요청은 코디네이팅 노드에서 수신되고 처리됩니다
- 라우팅은 문서의 복제 그룹을 결정하는 데 사용됩니다
- ARS는 최적의 사용 가능한 샤드에 쿼리를 보내는 데 사용됩니다
- ARS는 Adaptive Replica Selection(적응형 복제본 선택)의 약자입니다
- ARS는 쿼리 응답 시간을 줄이는 데 도움이 됩니다
- ARS는 본질적으로 지능형 로드 밸런서입니다
- 코디네이팅 노드는 응답을 수집하여 클라이언트에 전송합니다
엘라서틱서치가 문서를 쓰는 원리
프라이머리 텀(Primary terms)
- 이전 프라이머리 샤드와 새 프라이머리 샤드를 구분하는 방법
- 기본적으로 프라이머리 샤드가 변경된 횟수를 계산하는 카운터
- 프라이머리 텀은 쓰기 작업에 추가됨
시퀀스 번호(Sequence numbers)
- 프라이머리 텀과 함께 쓰기 작업에 추가됨
- 기본적으로 각 쓰기 작업마다 증가하는 카운터
- 프라이머리 샤드가 시퀀스 번호를 증가시킴
- Elasticsearch가 쓰기 작업을 정렬할 수 있게 함
프라이머리 샤드 실패 시 복구
- 프라이머리 텀과 시퀀스 번호는 Elasticsearch가 프라이머리 샤드 실패로부터 복구해야 할 때 핵심 요소
- Elasticsearch가 어떤 쓰기 작업을 적용해야 하는지 더 효율적으로 파악할 수 있게 함
- 대규모 인덱스의 경우, 이 과정은 매우 비용이 많이 듦
- 속도를 높이기 위해 Elasticsearch는 체크포인트 사용
글로벌 및 로컬 체크포인트
- 기본적으로 시퀀스 번호임
- 각 복제 그룹은 글로벌 체크포인트를 가짐
- 각 복제 샤드는 로컬 체크포인트를 가짐
- 글로벌 체크포인트
- 복제 그룹 내 모든 활성 샤드가 최소한 이 지점까지 정렬된 시퀀스 번호
- 로컬 체크포인트
- 수행된 마지막 쓰기 작업의 시퀀스 번호
요약)
- 쓰기 작업은 프라이머리 샤드로 전송됨
- 프라이머리 샤드는 작업을 복제 샤드로 전달
- 프라이머리 텀과 시퀀스 번호는 장애 복구에 사용됨
- 글로벌 및 로컬 체크포인트는 복구 프로세스 속도를 높임
- 프라이머리 텀과 시퀀스 번호는 응답에서 확인 가능
동시성 제어
- 동시 작업으로 인해 문서가 부주의하게 덮어쓰여지는 것을 방지
- 이러한 상황이 발생할 수 있는 여러 시나리오가 있음
- 예: 웹 애플리케이션에서 동시 방문자 처리
실패를 어떻게 처리할까요?
- 애플리케이션 수준에서 상황 처리
- 문서를 다시 검색
- 새 업데이트 요청에 primary_term과 seq_no 사용
- 필드 값을 사용하는 모든 계산을 다시 수행해야 함을 기억
요약
- Elasticsearch에 쓰기 요청을 동시에 보내면 다른 동시 프로세스에 의해 변경된 내용을 덮어쓸 수 있음
- 전통적으로는 _version 필드를 사용하여 이를 방지함
- 오늘날에는 primary_term과 seq_no 필드를 사용함
- Elasticsearch는 잘못된 primary term이나 sequence number가 포함된 쓰기 작업을 거부함
- 이는 애플리케이션 수준에서 처리되어야 함
쿼리로 문서 업데이트
여러 문서 업데이트하기
소개
- 이미 한 번에 하나의 문서를 업데이트하는 방법을 다루었습니다
- 이제 단일 쿼리 내에서 여러 문서를 업데이트하는 방법을 살펴보겠습니다
- RDBMS의 UPDATE WHERE 쿼리와 유사합니다
- 이 쿼리는 방금 다룬 세 가지 개념을 사용합니다
- Primary terms(프라이머리 텀)
- Sequence numbers(시퀀스 번호)
- Optimistic concurrency control(낙관적 동시성 제어)
스냅샷 사용 방법
- 스냅샷이 생성된 후 변경된 내용이 덮어쓰여지는 것을 방지합니다
- 많은 문서를 업데이트하는 경우 쿼리가 완료되는 데 시간이 걸릴 수 있습니다
- 각 문서의 primary term과 sequence number가 사용됩니다
- 문서는 값이 스냅샷의 값과 일치하는 경우에만 업데이트됩니다
- 아시다시피, 이것을 낙관적 동시성 제어라고 합니다 😉
- 버전 충돌 수는 version_conflicts 키 내에서 반환됩니다
강의 요약 (1/2)
- 쿼리는 낙관적 동시성 제어를 위한 스냅샷을 생성합니다
- 검색 쿼리와 벌크 요청은 복제 그룹에 순차적으로 전송됩니다
- Elasticsearch는 이러한 쿼리를 최대 10번까지 재시도합니다
- 쿼리가 계속 실패하면 전체 쿼리가 중단됩니다
- 이미 문서에 적용된 변경 사항은 롤백되지 않습니다
- API는 실패에 관한 정보를 반환합니다
강의 요약 (2/2)
- 스냅샷을 생성한 이후에 문서가 수정된 경우, 쿼리는 중단됩니다
- 이는 문서의 primary term과 sequence number로 확인됩니다
- 쿼리를 중단하는 대신 버전 충돌을 계산하려면 conflicts 옵션을 proceed로 설정할 수 있습니다
요약
여러 문서를 한 번에 업데이트할 때는 낙관적 동시성 제어를 위한 스냅샷이 사용됩니다. 문서의 primary term과 sequence number를 통해 문서가 스냅샷 이후 변경되었는지 확인하고, 충돌이 발생하면 기본적으로 쿼리가 중단됩니다. 그러나 conflicts 옵션을 통해 충돌을 무시하고 진행할 수도 있습니다. 이 과정에서 이미 변경된 문서는 롤백되지 않으므로 주의가 필요합니다.
POST /products/_update_by_query
{
"conflicts": "proceed",
"script": {
"source": "ctx._source.in_stock--"
},
"query": {
"match_all": {}
}
}
쿼리로 문서 삭제
POST /products/_delete_by_query
{
"query": {
"match_all": {}
}
}
배치 처리
Bulk API 소개
소개
- 문서를 인덱싱, 업데이트 및 삭제하는 방법을 배웠습니다
- 이제 단일 쿼리로 여러 문서에 대해 이러한 작업을 수행하는 방법을 살펴보겠습니다
- 이것은 Bulk API로 수행됩니다
- Bulk API는 NDJSON 사양을 사용하여 포맷된 데이터를 예상합니다
action_and_metadata\n
optional_source\n
action_and_metadata\n
optional_source\n
주의해야 할 사항 (1/3)
- HTTP Content-Type 헤더는 다음과 같이 설정해야 합니다
- Content-Type: application/x-ndjson
- application/json도 허용되지만 올바른 방법이 아닙니다
- Console 도구는 이것을 자동으로 처리합니다
- Elasticsearch SDK도 이것을 처리합니다
- HTTP 클라이언트를 사용할 경우 직접 처리해야 합니다
- 다음 강의에서 이를 수행하는 방법을 볼 것입니다
주의해야 할 사항 (2/3)
- 각 줄은 개행 문자(\n 또는 \r\n)로 끝나야 합니다
- 마지막 줄도 포함됩니다
- 텍스트 에디터에서는 마지막 줄이 비어 있어야 합니다
- Console 도구에서 자동으로 처리됩니다
- 일반적으로 스크립트가 bulk 파일을 생성하는데, 이 경우 이를 처리해야 합니다
- 텍스트 에디터에서 \n 또는 \r\n을 직접 입력하지 마세요 🙂
- 마지막 줄도 포함됩니다
주의해야 할 사항 (3/3)
- 실패한 작업은 다른 작업에 영향을 미치지 않습니다
- 전체 bulk 요청이 중단되지도 않습니다
- Bulk API는 각 작업에 대한 자세한 정보를 반환합니다
- 특정 작업이 성공했는지 확인하려면 items 키를 검사하세요
- 순서는 요청 내의 작업 순서와 동일합니다
- errors 키는 오류 발생 여부를 편리하게 알려줍니다
- 특정 작업이 성공했는지 확인하려면 items 키를 검사하세요
Bulk API를 사용하는 경우
- 한 번에 많은 쓰기 작업을 수행해야 할 때
- 예: 데이터를 가져오거나 많은 데이터를 수정할 때
- Bulk API는 개별 쓰기 요청을 보내는 것보다 더 효율적입니다
- 많은 네트워크 왕복이 방지됩니다
두 가지 더...
- 라우팅은 문서의 샤드를 결정하는 데 사용됩니다
- 필요한 경우 라우팅을 사용자 정의할 수 있습니다
- Bulk API는 낙관적 동시성 제어를 지원합니다
- 작업 메타데이터에 if_primary_term 및 if_seq_no 매개변수를 포함하세요
요약
Bulk API는 여러 문서에 대한 작업을 단일 요청으로 처리할 수 있게 해주는 효율적인 방법입니다. NDJSON 형식을 사용하며, 각 줄은 개행 문자로 끝나야 합니다. 실패한 작업은 다른 작업에 영향을 주지 않으며, 응답에는 각 작업의 성공 여부에 대한 자세한 정보가 포함됩니다. 대량의 데이터를 처리할 때 네트워크 왕복을 줄여 성능을 향상시킬 수 있으며, 낙관적 동시성 제어도 지원합니다.
POST /_bulk
{"index": {"_index": "products", "_id": 200} }
{"name": "Espresso Machine", "price": 199, "in_stock": 5}
{"create": {"_index": "products", "_id": 201} }
{"name": "Milk Frother", "price": 149, "in_stock": 14}
POST /_bulk
{ "update": {"_index": "products", "_id": 201} }
{"doc": {"price": 129}}
{ "delete": {"_index": "products", "_id": 2500} }
'시스템 > DB' 카테고리의 다른 글
ElasticSearch (Mapping & Analysis) (0) | 2025.03.16 |
---|---|
SELECT 기본 용법 (0) | 2022.08.02 |