본문 바로가기

Log,Monitorings

[ECK Elasticsearch] 데이터 노드가 재시작되면 레이턴시가 급증했던 이슈

반응형

필자는 현재 ECK Operator로 ElasticSearch를 운영중이다.

 

현재 ECK Elasticsearch는 글을 쓰는 기점으로 2.15 버전이 나왔으며 상당히 만족하면서 사용하고 있다.

 

https://www.elastic.co/guide/en/cloud-on-k8s/current/index.html

 

Elastic Cloud on Kubernetes [2.15] | Elastic

 

www.elastic.co

 

 

ECK ES를 운영하면서 참고할만한 내용에 대해서도 적을 내용이 꽤나 있긴 한데 사실 ES를 잘 알지 못하기에 그런 부분들은 따로 적지 않으려고 한다.

 

최근에 경험했던 이슈에 대해서 간략히 정리해보려 한다.

 

 

[참고하면 좋을 무신사, 당근마켓 ECK 관련 글]

 

https://medium.com/musinsa-tech/%EB%AC%B4%EC%8B%A0%EC%82%AC%EC%9D%98-%EC%97%98%EB%9D%BC%EC%8A%A4%ED%8B%B1%EC%84%9C%EC%B9%98-muse-musinsa-elasticsearch-e6355516186a

 

무신사의 엘라스틱서치 MusE (Musinsa Elasticsearch)

10분만에 만드는 엘라스틱서치 클러스터

medium.com

 

https://medium.com/daangn/%EB%8B%B9%EA%B7%BC%EB%A7%88%EC%BC%93-%EA%B2%80%EC%83%89-%EC%97%94%EC%A7%84-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4%EB%A1%9C-%EC%89%BD%EA%B2%8C-%EC%9A%B4%EC%98%81%ED%95%98%EA%B8%B0-bdf2688df267

 

당근마켓 검색 엔진, 쿠버네티스로 쉽게 운영하기

안녕하세요. 당근마켓 검색 플랫폼팀 Teddy 에요. 당근마켓 검색 플랫폼 팀은 검색 인프라와 검색 서비스를 운영하면서 당근마켓의 모든 문서를 검색 가능하게 하고, 검색 트래픽을 안정적으로

medium.com

 

 

 


1. 문제 발생

팀원이 Kubernetes 버전 업그레이드를 진행하기 위해 ECK Operator 버전도 그에 맞춰 올렸다.

 

이 때 ECK Operator는 ElasticSearch, Kibana 파드를 재시작한다고 한다.

 

 

사실 ES 롤링 재시작하는 작업은 예전부터 수십번 해보았기 때문에 별 이슈가 없을 것이라 판단했었다. ES 버전을 업그레이드 하거나 ES의 스펙을 변경한다거나 AntiAffinity를 적용한다거나 EC2 Instance Type을 변경하기 위해 재배포한다거나 등등..

 

하지만 데이터 노드가 재시작될 때 API에서 Latency가 급증하는 이슈가 발생했다.

 

2. 문제 원인 파악 및 테스트

문제의 원인을 파악하기 위해 이것저것 조사해봤던 것 같다.

 

- es-exporter에 의해 추출되는 메트릭 (그라파나)

- metricbeat에 의해 수집되는 메트릭 (키바나)

 

이 중 처음에 의심됐었던 부분은 데이터 노드가 1대씩 순차적으로 재시작될 때 Shard가 다른 Node로 Relocation 되면서 Indexing Rate가 순간적으로 높아지고 이로 인해 검색 속도에도 영향이 미치는 게 아닐까? 였다.

 

따라서 Data Node가 재시작될 때 어떤 일이 발생하는지를 확인해보기로 했다.

 

data-01, data-02, data-03 3대의 data node가 있다고 가정, Local Volume이 아닌 EBS gp3 Volume을 사용

 

1. data-01 노드 종료

1.1. 해당 노드에 있는 shard들은 Unassign shard 상태가 되고, primary shard는 다른 노드에 있는 replica shard가 승격받아 primary shard가 된다.

1.2. 1분이 지난 뒤 해당 노드에 있는 shard들은 recovery process가 시작된다.
(index.unassigned.node_left.delayed_timeout의 기본값이 1분)

1.3. 다른 노드로 shard들이 relocating 된다.

 

2. data-01 노드 시작

 

3. data-01 노드 Join

3.1. 다른 노드로 relocating 됐던 shard들이 다시 분산되기 시작하며 data-01 노드에도 shard들이 이동된다.

 

따라서 처음에는 위의 불필요한 프로세스로 인해 갑작스럽게 부하가 발생하는게 아닌가 생각했다.

 

따라서 ElasticSearch를 안전하게 재시작하기 위해 다음의 테스트를 진행해보았다.

 

1. Locust로 ES에 지속적으로 Indexing, Search 요청을 초당 20회씩 날린다.

2. Data node를 다양한 조건 하에 재시작해본다.

- 위의 시나리오대로 그냥 Data node를 재시작

- Data node를 안전하게 재시작
(안전하게 재시작하는 방법은 다음 문서에 자세히 설명되어 있음. 참고 : https://opster.com/guides/elasticsearch/operations/how-to-perform-rolling-restarts-using-the-api-in-elasticsearch/)

 

 

2.1. 그냥 Data node 재시작(Shard Recovery가 자연스럽게 일어나도록)

예상대로 Data node가 재시작될 때 Locust에서 순간적으로 응답을 받지 못하는 이슈가 발생했고 레이턴시도 확 튀었음을 확인했다.

 

 

2.2. Data node를 안전하게 재시작(Shard Recovery가 수행되지 않도록)

예상과 다르게 Data node가 재시작될 때 동일하게 Locust에서 순간적으로 응답을 받지 못했다 이에 따라 레이턴시도 동일하게 확 튀었다.

 

 

위 테스트로 인해 우선 Shard가 Relocating 된다고해서 이렇게 많이 레이턴시가 확 치는 것과는 상관관계가 없다는 것을 파악했다.

 

(물론 대규모 클러스터 환경이나 Data volume size가 수백GB, TB 단위라면 당연히 Shard Recovery가 수행되지 않도록 해야 하겠지만 우선 필자의 환경에서는 위 시나리오가 원인이 아니었음을 확인했다.)

 

따라서 해당 Data Node의 Node Exporter 메트릭을 면밀히 관찰하게 되었다.

 

이 때 특이사항을 1가지 발견했었는데 Data node가 재시작될 때 CPU 사용량 중 IOWait이 상당 부분을 차지한다는 것을 확인했다.

 

User 사용량은 아마도 JVM 초기 부팅 시 사용되는 CPU 자원일테고 그 외에는 EBS Volume으로부터의 IOWait이라는 뜻인데 부팅 후 첫 쿼리를 할 때 EBS Volume으로부터 가져와야 하다 보니 이로 인한 레이턴시였음을 추측할 수 있었다.

 

따라서 ES가 재시작될 때 미리 Memory 내 File system cache로 laod 할 수 있는 방법이 있는지 확인해보던 와중 다음의 설정을 확인했다.

 

https://www.elastic.co/guide/en/elasticsearch/reference/current/preload-data-to-file-system-cache.html

 

Preloading data into the file system cache | Elasticsearch Guide [8.16] | Elastic

Preloading data into the file system cache edit This is an expert setting, the details of which may change in the future. By default, Elasticsearch completely relies on the operating system file system cache for caching I/O operations. It is possible to se

www.elastic.co

 

 

PUT /my-index-000001
{
  "settings": {
    "index.store.preload": ["nvd", "dvd"]
  }
}

 

 

 

인덱스에 위 설정을 하게 되면 미리 file system cache에 preload 하는 설정이다.

 

참고로 Memory Size보다 해당 preload 해야 하는 데이터의 사이즈가 커야 한다는 점은 주의해야 하기에 미리 사이즈를 계산하고 적용하는 것이 좋다.

 

느렸던 이유로는 유사도 kNN 검색을 할 때 머신이 재시작되면 해당 데이터들이 file system cache가 비어 있는 상태이기 때문에 load 되는데 시간이 소요되기 때문이었다.

 

 

따라서 HNSW graph랑 비양자화 vector 값들에 사용되는 vex, vec를 preload 하는 설정을 인덱스에 추가해주었다.

 

PUT /my-index-000001
{
  "settings": {
    "index.store.preload": ["vex", "vec"]
  }
}

 

 

 

위 설정을 적용하고 그냥 Data node 재시작(Shard Recovery가 자연스럽게 일어나도록)해보았더니 말끔하게 레이턴시가 사라진 것을 확인할 수 있었다.

 

물론 대규모 환경이라면 Shard Recovery가 최대한 일어나지 않도록 재시작하는게 안전하지 않을까 생각해본다.

 

 

3. 정리

기존에는 왜 데이터 노드를 재시작할 때 이슈가 발생하지 않았나 생각해보면 예전에는 유사도 kNN Search에 사용되는 인덱스를 사용하기 전에 데이터 노드를 재시작해보는 작업을 했어서 이런 이슈를 겪어보지 못했었다.

 

해당 인덱스가 추가되고 몇달 뒤에 데이터 노드가 재시작되면서 이미지 검색하는 API 서버에서는 Latency가 급증했고 이로 인해 문제 원인을 파악하기 시작했다.

 

1. 원인으로는 file system cache에 미리 load 되지 않았기 때문에 느렸다. 만약 ebs volume이 아니라 Local volume을 사용했다면 조금 더 빠르지 않았을까 생각해본다.

 

2. 만약 대규모 환경이고, 대규모 환경이 아니지만 ES Data node를 좀 더 안전하게 rolling restart 하고 싶다면, Data node를 안전하게 재시작하기 위해서는 shard allocation을 비활성화한채로 1대씩 재시작하고 shard allocation 활성화 -> 데이터노드 교체 -> shard allocation 비활성화 -> ... 순차적으로 해야하지 않을까 생각한다.

 

+ Local volume은 ec2가 교체되면 데이터가 날라가기 때문에 es shutdown 전에 다른 node로 shard들을 옮겨야하지 않을까? 이 부분은 테스트해보지 않아서 잘 모르겠다.

 

3. 여러가지 메트릭을 수집해 문제 발생 시 이슈를 확인할 수 있다. 이 때 es-exporter, node-exporter, istio requests metric 등 여러가지 활용할 수 있다.

 

당연히 ECK에서 내장으로 제공하는 MetricBeat, FileBeat의 메트릭이나 로그(slow query, ..)도 활용할 수 있으니 참고할 것

 

 

 

반응형