모두의 음악 프로젝트는 그룹 기반의 커뮤니티 서비스입니다. 특정 내용의 게시글 검색 기능이 필요한 상태예요.
사용자 A는 일렉 기타 에 관한 게시글을, 사용자 B는 클래식 에 관한 게시글을 보고 싶을 수 있거든요.
기본적으로 문서의 내용 전체를 검색하는 전문(fulltext) 검색이 필요할 것 같아요.

가장 간단하게 실행해볼 수 있는 LIKE 키워드를 통해 해당 기능을 구현해봤어요.

일본 이라는 텍스트를 검색했을 때 605ms, 즉 0.6초가 걸렸네요. 빠른 응답까진 아니더라도 사용하지 못할 정도는 아니라고 느껴졌어요.

보다 덜 사용될 것 같은 데카르트 라는 단어를 검색해봤습니다. 3.15s 라는 좋지 않은 결과가 나왔네요. 슬슬 문제로 인식되기 시작했어요.

머스탱 이라는 단어를 검색하니 무려 8.19s가 걸렸습니다. LIKE의 경우, 페이지를 채우기 위한 데이터 개수를 찾기 위해 레코드의 평문을 순회하며 확인하게되고, 이 때문에 사용 빈도가 적은 키워드의 검색에 오랜 시간이 걸리는 것 같아요.
LIKE 연산의 경우 index를 타지도 않으니 지금 상태로는 시간을 줄이기 힘들겠네요.
전문 검색을 위해 MySQL이 지원하는 FULLTEXT 라는 인덱스가 존재합니다. 이는 inverted index 방식으로 동작하며, 단어가 포함된 문서를 저장하여 빠르게 검색할 수 있도록 도와줘요.
검색할 필드인 content 컬럼에 FULLTEXT 인덱스를 적용했습니다.

기존에 원하던 기능인 단어가 포함된 게시글을 검색하기 위한 쿼리를 작성해봤습니다. 일본 검색의 경우 기존 0.6s 가 걸렸지만 인덱스를 적용하니 2.49s 로 증가했어요.

뭔가 이상해 기존에 8.19s 가 걸린 머스탱 검색을 해봤습니다. 0.1s 만에 완료되네요.
혹시 FULLTEXT 인덱스를 선택하지 않는 걸까? 실행 계획을 확인해봤습니다.

인덱스는 정상적으로 선택하네요. 다만, 정렬에 filesort 를 사용한다고 해요.
정렬을 하지 않는 일본 키워드 검색은 어떤 성능을 보일까요?

order by 구문만 제거했음에도 0.1s 이하로 내려왔네요. filesort 에 의해 성능이 저하됨을 확인했어요.
왜 filesort 가 발생하는지에 대한 두가지 가정을 세워봤습니다.

첫번째는 정렬에 사용되는 sort_buffer 을 초과할 데이터에 대해 정렬을 시도해 filesort 가 발생했다는 가정이예요.

sort_buffer 를 기존 256kb에서 8mb로 변경했음에도 여전히 filesort 가 발생합니다.
이 가정은 아닐 확률이 높고, 맞다고 해도 sort_buffer 크기를 데이터 크기가 증기함에 따라 키울 수는 없기에 FULLTEXT 인덱스를 사용하긴 힘들 것이라는 생각이 드네요.

FULLTEXT 인덱스는 연관성 점수를 측정한다고 합니다. inverted index 라는 특징 때문에 일반 인덱스로 지정할 수 없죠.
현재 실행 계획은 FULLTEXT 인덱스를 사용하는 것으로 결정됐고, 실제로도 이 계획이 모든 레코드를 순회하는 것보다 좋을 거예요.
다만, 이럴 경우 index를 정렬에 사용할 수 없기에 filesort 가 발생했고, 자주 사용되어 많은 결과가 나오는 키워드에 대해 좋지 않은 성능을 보여준 것이죠.
검색 기능을 2.49s 까지 줄였지만 아직도 사용할 수 없는 수준이네요.
결국 전문 검색 엔진인 ElasticSearch 를 도입했습니다.
이를 사용하기 위해선 몇가지 사전 준비가 필요했어요. 데이터 저장소인 MySQL 과 ElasticSearch 간의 데이터 정합성(sync)를 맞춰야하며, 기존에 존재하던 300만건의 게시글 데이터 또한 ElasticSearch 에 옮겨줘야하죠.
ELK Stack이라 불리는 ElasticSearch + Log stash + Kibana 의 조합을 많이 사용하지만, 프로젝트에 이미 Kafka 를 사용중이기에 Kafka Connect를 사용했습니다.
ElasticSearch 에서 게시글의 identifier인 ID 를 조회하고, 해당 데이터를 통해 MySQL 에서 데이터를 반환해줬습니다.
이제 MySQL 에서 테스트해봤던 여러 키워드들을 조회해볼까요?




평균 60ms의 굉장히 빠른 성능을 보여줍니다. 이제 실제 서비스에서 사용할 수준이 된 것 같아요! 배포 후 동작을 확인해볼까요?


만족스러운 결과네요!