클러스터와 노드
클러스터는 여러 대의 컴퓨터나 구성 요소를 논리적으로 연결한 전체를 하나인 것처럼 사용하게 하는 기술을 말합니다.
- ElasticSearch 클러스터
- 여러 ElasticSearch 프로세스들을 논리적으로 연결해 하나의 프로세스처럼 사용하게 하는 기술
- 고유한 클러스터 이름과 `UUID`를 갖는다.
- 노드
- 클러스터를 구성하는 하나의 ElasticSearch 프로세스
- 고유한 노드 이름과 `UUID`를 갖는다.
(노드 이름을 설정하지 않으면 7.x 부터 `${HOSTNAME}`을 사용. 이전 버전은 랜덤 값 사용) - 클러스터 내에서 서로 동일한 클러스터의 이름을 인식한다.
위 그림의 각 노드들은 하나의 ElasticSearch로 동작하기 때문에 어떤 노드에 요청을 보내더라도 동일한 응답과 응답 속도를 보장받을 수 있습니다.
단일 노드로는 구성하지 않는다.
하나의 노드를 이용하더라도 하나의 클러스터 내에서 단일 노드로 구성되지만 이렇게 사용하진 않습니다.
왜일까요?
클러스터는 하나의 프로세스처럼 동작하기 때문에 클러스터 내 어떤 노드 하나에 장애가 발생해도 다른 노드에서 요청을 처리할 수 있기 때문에 높은 안정성을 보장합니다. 그렇기 때문에 단일 노드로 클러스터를 구성하는 것은 안정성을 포기하는 것과 마찬가지라 단일 노드로만 구성하진 않습니다.
노드의 역할
노드의 역할은 4가지가 있으며, 하나의 노드는 한 번에 여러 역할을 맡을 수 있습니다.
마스터 (Master-eligible) - 클러스터 관리
클러스터의 중심으로서, 클러스터의 전반적인 메타데이터를 관리합니다.
클러스터 내에서 반드시 한 대 이상으로 구성돼야 합니다.
마스터 노드가 3대라고 했을 때, 실제 동작하는 마스터 노드는 1대이고, 나머지 마스터 노드 2대는 장애 발생에 대비한 마스터 후보 노드가 됩니다.
모든 노드들은 마스터 노드에게 자신의 상태, 성능, 자신이 갖고 있는 샤드 정보 등을 마스터 노드에게 보고합니다.
마스터 노드는 이 정보들을 취합해 클러스터를 관리합니다.
데이터 (Data) - 저장/검색 처리
사용자의 문서(Document)를 실제로 저장하고 검색 요청을 처리하는 일꾼 노드입니다.
사용자의 요청이 오면 여러 데이터 노드들이 협력해서 자신이 처리할 일은 자신이 처리하고, 다른 데이터 노드가 처리할 일은 전달합니다.
전달하는 기준은 마스터 노드를 통해 전달받은 클러스터의 전체 정보를 기반으로 결정합니다.
인제스트 (Ingest) - 저장할 값 가공
사용자의 문서가 저장되기 전 내용을 가공합니다.
데이터 노드에 저장하기 전 어떤 필드의 값을 가공할 때 동작합니다.
코디네이트 (Coordinate) - 전달만 수행
사용자의 요청(저장이나 검색 등)을 직접 처리하지 않는 대신 다른 데이터 노드에 전달하고, 각 데이터 노드들의 응답 결과를 취합합니다.
인덱스와 타입
- 인덱스
- 데이터가 저장되는 논리적인 공간
- RDMBS의 데이터베이스 개념으로 생각할 수 있다.
- 하나의 인덱스에는 하나의 타입만 가질 수 있음
- log 파일로 치면 `server-log-2024-12-29`가 하나의 인덱스가 된다.
- 타입
- 인덱스 내의 데이터를 유형별로 구분한 공간
- RDBMS의 테이블 개념으로 생각할 수 있다.
- 6.x 부터 단일 타입만 허용. (대부분 `_doc`)
- `server-log-2024-12-29` 인덱스의 타입은 이슈가 없으면 `_doc` 타입이 된다.
- 매핑
- RDBMS의 스키마 개념으로 생각할 수 있다.
- 저장될 JSON 문서의 Key-Value 형식을 정의한다.
- 문서
- 사용자 요청에 의해 인덱스에 저장될 데이터 자체
- RDBMS의 레코드(ROW) 개념으로 생각할 수 있다.
- `server-log-2024-12-29` 인덱스 내에서 서버 정보를 담은 로그 한 줄이라고 생각할 수 있다.
- 필드
- 문서를 구성하는 요소
- RDBMS의 속성(COLUMN) 개념으로 생각할 수 있다.
- `server-log-2024-12-29` 인덱스 내에서 서버 정보를 담은 정보들 중에서 시간, 스레드 번호 등이라고 생각할 수 있다.
샤드와 세그먼트
- 샤드
- 인덱스에 색인되는 문서들이 저장되는 논리적인 공간
- RDBMS의 파티션 개념으로 생각할 수 있다.
- 샤드는 1개 이상의 세그먼트(물리적인 파일)로 구성된다.
- 샤드마다 세그먼트 개수가 다를 수 있다.
- 샤드의 번호는 0번부터 시작한다.
- 세그먼트
- 샤드의 데이터들을 갖고 있는 물리적인 파일
- 색인된 문서는 시스템의 메모리 버퍼 캐시에 먼저 저장되고, 이후 `refresh` 과정을 거쳐야 실제로 디스크에 세그먼트 단위로 문서가 저장된다.
- 실제로 디스크에 저장되고 나서야 검색이 가능해진다.
`log-2024-12-29`라는 파일로 인덱스를 만들었다고 가정해 보면, 이 파일의 한 줄 한 줄의 로그가 문서라고 할 수 있습니다.
이 여러 줄의 로그들은 샤드라는 단위로 나눠서 해시 알고리즘에 의해 여러 노드로 분산 저장됩니다.
그리고 하나의 샤드는 다시 여러 세그먼트로 이루어져 있고, 하나의 세그먼트에는 여러 문서들이 들어있습니다.
프라이머리 샤드와 레플리카 샤드
- 프라이머리 샤드 (원본 샤드)
- 원본 샤드를 의미합니다.
- 최초 인덱스를 생성할 때 개수를 설정해야 합니다.
- 한 번 개수를 설정하면 변경할 수 없기 때문에 신중하게 설정해야 합니다.
- 7.x 부터 1개가 기본 값이기 때문에 인덱스 생성 시 확장을 고려해서 설정해야 합니다.
- 레플리카 샤드 (안정성과 성능 측면에서 중요)
- 프라이머리 샤드에 장애가 발생했을 때를 대비해 복제한 샤드를 의미합니다.
- 기본적으로 프라이머리 샤드 1개당 1개의 레플리카 샤드가 있어야 안정성이 보장됩니다.
- 노드 별로 원본(프라이머리) 샤드의 번호와 복제본(레플리카) 샤드의 번호가 겹치지 않게 할당됩니다.
- 설정하지 않으면 프라이머리 샤드당 하나의 레플리카 샤드를 만듭니다.
- 레플리카 샤드의 개수는 운영 중에 변경이 가능합니다.
- 디스크를 병렬적으로 읽을 수 있기 때문에 성능 측면에서도 중요합니다.
세그먼트
문서들이 디스크에 물리적으로 저장되는 단위입니다. 세그먼트는 불변(`Immutable`)이라는 독특한 특성이 있습니다.
예를 들어, 문서를 생성한 후 업데이트를 하면 실제 물리적인 파일을 변경하지 않고 `삭제 플래그`를 기록하는 식으로 불용 처리합니다. (`disconnected`)
업데이트 작업은 갱신이 아니라 새로운 세그먼트를 생성(`create`)을 하는 것으로 데이터의 일관성(consistency)을 유지합니다.
병합(Merging)
이런 불변 특성으로 인해 시간이 지날수록 불용 처리된 세그먼트들이 쌓이면 문서를 검색할 때마다 많은 세그먼트들이 응답하기 때문에 별도로 처리를 해야 하는데, 이때 수행하는 작업을 병합(`merging`)이라고 합니다.
병합은 백그라운드 스레드에서 진행되며, 동작 방식은 삭제 플래그가 있는 세그먼트들을 빼고 나머지 세그먼트들을 하나의 큰 세그먼트로 병합합니다. 병합 과정에서 삭제 플래그가 기록된 세그먼트는 실제로 디스크에서 삭제됩니다.
이렇게 병합이 되면 문서를 검색할 때 응답하는 세그먼트가 줄어 응답 속도가 빨라지게 됩니다.
매핑
JSON 문서의 Key-Value 형태를 정의하므로 RDBMS의 스키마 개념과 유사합니다.
예시
curl -X GET "localhost:9200/firstindex/_mapping?pretty"
{
"firstindex": { // 인덱스 이름
"mappings": {
"_doc": { // 인덱스 타입의 이름
"properties": { // 매핑 정보
"account_number": { // 필드 이름
"type": "long" // account_number 필드는 long 데이터 타입을 사용
},
"address": { // 필드 이름
"type": "text", // address 필드는 text 데이터 타입을 사용
"keyword": { // nested 타입
"fields": {
"keyword": {
"type": "keyword", // keyword 라는 데이터 타입
"ignore_above": 256 // 256글자가 넘어가는 값부터는 검색에 사용하지 않는다는 의미
}
}
}
}
}
}
}
}
}
동적 매핑과 정적 매핑
- 동적 매핑
- 매핑 정보가 미리 정의되지 않은 상태에서 최초에 색인된 문서를 기반으로 ElasticSearch가 자동으로 매핑을 생성해주는 방식입니다.
- 만약 이미 매핑된 정보가 있다면 `update`를 진행합니다. (실제로는 새로운 세그먼트 생성)
- 색인 성능에는 좋지 않은 방법으로 성능이 중요하다면 정적 매핑을 사용해야 합니다.
- 정적 매핑
- 미리 매핑 정보를 정의해서 사용하는 방식을 말합니다.
어떤 매핑 방식을 사용하든, 한 번 매핑 정보가 정의되면 이후에 생성되는 문서는 반드시 기존 매핑 정보를 지켜야 합니다.
다시 말해, `long` 타입으로 정의된 필드에 `text` 타입이 들어오면 색인되지 않고 에러가 발생합니다.
참고
- (도서) 기초부터 다지는 ElasticSearch 운영 노하우
'ElasticSearch' 카테고리의 다른 글
ElasticSearch 샤드 배치 방식 변경하기 (0) | 2025.01.03 |
---|---|
ElasticSearch 클러스터 설정 톺아보기 (0) | 2024.12.30 |
bulk API 수행 시 'Malformed content, found extra data after parsing: START_OBJECT' 에러 해결하는 방법 (1) | 2024.12.26 |