검색엔진 색인 파이프라인 구축 CDC, Kafka, Elasticsearch

ms-shin·2024년 4월 15일
0

개선

목록 보기
4/4

검색 엔진 파이프라인 구축 과정

배경

기존에는 Mongo의 Atlas search를 활용하여 Full text(전문 검색) 서비스를 제공하고 있었습니다. 하지만 동의어와 오탈자를 처리하기 위해서 에 nori 한글 형태소 분석기로
nori와 사용하지 않는 한글 (죵프수트 등)과 같은 데이터가 들어있는 Synonyms Source Collection을 동의어 매핑하는 경우, 인덱싱이 오류가 납니다. 더군다나 애플리케이션에서 해당 인덱스로 검색을 하던 것도 에러가 떨어집니다. 몽고 팀에게 문의를 해봤을 때도 명확한 해답을 얻지 못 했습니다. 그래서 검색 엔진으로도 유명했던 elasticsearch로 옮기기로 결정했습니다. 이는 로그 시스템에서도 사용하고 있던 터라 오히려 제품 비용 절감이 되는 효과도 있어서 쉬운 결정이었습니다.

검색엔진 교체 과정에서 요구 사항

Data sync를 위한 Double Write 로직 제거: PG를 main DB로 사용하고, Mongo를 read용으로 사용하고 있었습니다. 이 때, 두 저정소의 sync를 맞추기 위해서 application에서 double write로 삽입, 갱신, 삭제를 진행했었습니다. 이는 코드를 복잡하게 만들고, 버그를 낳았습니다. 그러던 중, RDB에서 CDC 패턴으로 파이프라인을 만드는 방식에 대해 알게 됐습니다. 이를 활용하면 위와 같은 요구사항을 만족할 수 있을 것으로 생각했습니다. 추가적으로, 최종 일관성만 맞으면 되는 비즈니스였기에 CDC로 최종 결정할 수 있었습니다.

아키텍처

전체적인 구조는 아래와 같이 설계되어 있습니다. 사실 비용 부담으로 인해 sink connector가 많은 역할을 하고 있지만 여기 설명에서는 관계가 없기 때문에 생략하여 표시했습니다. Kafka-connect Debezium을 사용했고, sink connector는 go로 구현했습니다.

  • Kafka는 MSK로 구축했습니다. 구축 과정이나 유지관리 면에서도 쉬울 것이라고 생각했고, 모니터링도 Cloudwatch에서 제공하기 때문에 선택했습니다.

여러가지 문제 - 원인 - 해결

  1. DevDB와 같은 CUD가 거의 없는 DB의 경우에는 connector에서 slot을 읽지 않습니다. 이는 debezium document에서도 적혀있는 부분입니다. 이로 인해, lag이 쌓이고, storage가 금방 50~60G가 늘어납니다. 그래서 db가 다운되는 경우가 생겼습니다. 이 때, 읽기복제본이나 WAL이 쌓이는 이유는 읽기 복제본에서 가져가지 않은 LSN부터 계속 저장하고 있기 때문입니다. 그래서 hearbeat을 주기적으로 요청할 수 있게 MSK connector에서 제공을 해줍니다. hearbeat이라는 테이블을 만들어주고, 아래와 같이 설정하면 주기적으로 insert를 요청하기 때문에 wal이 쌓이지 않게 됩니다.

https://velog.io/@alstn5038/CDC-%EA%B5%AC%EC%B6%95-WAL-%EB%A1%9C%EA%B7%B8%EB%A1%9C-%EC%9D%B8%ED%95%9C-DB-%EC%84%9C%EB%B2%84-down

  1. 초기 Sink Connector는 이벤트에 대해서 처리할 목록들이 처리되면 커밋 후에 다음 이벤트를 읽는 동기 Consumer로 구현을 했었습니다. 처리 목록 중 Webhook으로 부터 받는 응답이 딜레이가 되면서 lag이 커져 전체 이벤트의 처리가 9시간이 delay되어 서비스 장애가 생겼습니다. 이를 개선하기 위해, group.id(컨슈머 그룹)/job(작업)/worker count(워커 수)를 Config에서 설정해서 추가할 수 있도록 설계했습니다.

  2. 2번의 async로 100개의 worker로 작업을 하다보니, elasticsearch의 memory limit으로 circuit break걸리는 현상이 발생하여 순간 모든 쿼리가 안 되어, 조회 뿐만 아니라 동기화도 안 되는 현상이 발생했습니다. 이는 한가지의 원인으로만 발생하는 것은 아니기에 많은 분석이 필요한 상황입니다. 일단 데이터 생성 및 색인시 bulk api를 통해서 메모리 자원을 효율적으로 사용할 수 있다고 설명되어있어, event를 batch로 받아 bulk command 하도록 변경했습니다.

추가적으로 진행 중인 부분은 스코어링 쿼리 개선과, 재시도 처리입니다.

profile
지식을 깊게 파고드는 개발자입니다.

0개의 댓글