본문 바로가기

Backend/AWS

AWS와 Elasticsearch를 이용해 실시간 검색 구현하기 (CDC)

 

[문제 상황]

상품을 검색할 때, 검색엔진을 별도로 사용하지 않고 데이터베이스에게 위임하여 사용하고 있습니다.
데이터베이스에서 제공하는 검색기능이 부족하다보니, 원하는 상품을 검색하는데 어려움이 있습니다.
상품을 검색하는데 결과에 나오지 않기 때문에 마치 고객에게는 상품이 없는 것처럼 인식되기도 하였습니다.
그래서 저희는 Elasticsearch를 도입하여 이 문제를 해결하기로 하였습니다.
 
검색엔진을 사용하는 것은 크게 문제가 되지 않습니다. document를 저장하고 검색할 필드를 통해서 원하는 상품을 조회하는건 어렵지 않습니다.
다만, 문제는 상품의 변화가 실시간으로 검색엔진에 바로 반영되어야 한다는 점입니다.
 
구체적인 요구사항은 다음과 같습니다.
- 상품의 변화가 바로 검색엔진에 반영되어야 한다.
- 누락되지 않고 검색엔진에 동기화가 되어야 한다.
예를 들어, 상품이 판매가 불가능한 상황인데 검색 결과에 나오면 안됩니다.
상품 이름이 변경되면, 변경된 이름이 조회되어야 합니다.
 
이 요구사항의 핵심 포인트는 누락되는 데이터 없이 빠르게 검색엔진에 반영되어야 하는 것입니다.
 
 


[문제 해결 방법]

처음으로 생각한 것은 어플리케이션 레벨에서 이벤트 기반으로 동작하는 것입니다.
상품의 변화를 처리하는 도메인 메서드 내부에서 어플리케이션 이벤트가 발행되고 이를 AWS SNS+SQS 조합을 통해서 처리하는 것입니다.
이러한 구조를 가지면, 여러 서버에서 발생하는 이벤트를 하나의 어플리케이션에서 처리할 수 있게 됩니다.
다만, 데이터베이스에 직접적으로 변경을 하거나 도메인이 변경되면 이벤트가 발행되지 않거나 누락될 수 있습니다.
데이터의 변화를 누락없이 처리하는게 가장 중요한 포인트입니다. 이러한 이유로, 어플리케이션보다 더 로우레벨인 데이터베이스의 변경을 감지하는 방법을 이용하게 되었습니다.
이 방법을 CDC(Change Data Capture)라고 합니다.
 
CDC를 간단히 설명하면, 데이터베이스의 변화가 생기면 이를 감지하는 것입니다. 어플리케이션 레벨에서 변화를 체크하는 것보다 더 안정적으로 변화를 감지할 수 있습니다.
만약 mysql를 CDC의 source로 한다면, DB 서버와 CDC 서버는 master-slave(replication)원리로 동작합니다 CDC 서버가 replication이 되어서 bin log를 통해 변경을 감지하는 것입니다.
 
CDC를 이용해 실시간으로 검색엔진에 반영되도록 하였습니다. AWS에서 제공하는 기능을 통해 설계해보았습니다.

AWS + Elasticsearch를 이용한 실시간 검색

 
흐름은 다음과 같습니다.
1. Aurora DB에서 발생한 데이터의 변화를 AWS DMS 서버가 감지
2. AWS DMS에서 변경된 테이블/로우 정보를 Kinesis에 전송
3. Lambda가 정기적으로 Kinesis의 레코드를 consume하며, Elasticsearch에 반영
4. 고객이 검색을 요청하면, 고객 api서버는 Elasticsearch로 요청
 

[AWS Data Mirgration Service (DMS)]

역시 AWS에서는 Data Mirgration Service (DMS)라는 서비스를 통해서 CDC를 지원하고 있습니다.
다만, DMS는 이름에서 볼 수 있듯 데이터베이스를 마이그레이션하는데 초점을 맞추고 있습니다.
특정 테이블의 변화를 감지할 수 있지만, 특정 칼럼의 변화까지는 감지할 수 없습니다. 예를 들어, Item 테이블의 name 칼럼의 변화만 감지하고 싶지만 item.description이 변화가 생겨도 DMS는 이벤트를 발행합니다.
이러한 이유로 특정 칼럼의 변화만 감지할 수 있는 Debezium을 이용하려고 했지만, 카프카를 함께 운영 해야하는 부담이 있어 DMS를 이용했습니다.
 
DMS는 감지한 변화를 kafka, kinesis, s3등으로 레코드를 전송할 수 있습니다.
이 중에서, kinesis stream를 이용하였습니다.
 

[AWS Kinesis + Lambda]

AWS kinesis는 스트림을 제공합니다. DMS에서 전송하는 CDC record 정보를 kinesis에 저장합니다.
그리고 kinesis에 저장된 레코드들을 AWS Lambda가 주기적으로 처리합니다.
Lambda를 이용한 이유는 서버 운영에 대한 부담도 적은게 가장 컸습니다.
 
DMS가 kinesis에 레코드가 잘 전달되는지 테스트하기 위해서, KCL(Kinesis Client Library)를 spring boot 서버에서 띄웠습니다. 이때 샤드를 어디까지 읽었는지 확인하는 checkpointing을 하는게 조금 까다로웠습니다.
다만, Lambda는 EventBridge를 통해서 checkpointing을 자동으로 처리해줍니다.
https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-pipes-kinesis.html

Amazon Kinesis stream as a source - Amazon EventBridge

Amazon Kinesis stream as a source You can use EventBridge Pipes to receive records in a Kinesis data stream. You can then optionally filter or enhance these records before sending them to one of the available destinations for processing. There are settings

docs.aws.amazon.com

 

[API서버와 검색엔진]

고객용 api는 이제 검색엔진에 검색을 위임하게 됩니다. 그러면 검색엔진에 문제가 생기면, 검색 api를 사용할 수 없게 됩니다. 이러한 경우를 대비해서 fallback 전략이 필요합니다.
기본적인 예외 발생과 더불어, 2초 이상 요청이 완료되지 않으면 데이터베이스에 직접 쿼리하는 방식으로 장애를 대응하도록 했습니다.
 


 

[결과]

- Elasticsearch를 통해 더 정확한 검색이 가능해졌습니다.
- 실시간으로 상품의 변화를 바로바로 반영할 수 있게 되었습니다.
- AWS의 리소스를 최대한 활용하여, 서버 운영의 부담은 줄이고 가용성 높은 구조를 가지게 되었습니다.