Skip to content
isdnetworks
Go back

검색 결과와 DB가 다를 때

(수정됨)

목록 검색이 느려서 OpenSearch 에 products 색인을 따로 두고 검색은 그쪽에서 하게 했다. 빨라진 대신 같은 데이터가 두 곳에 있는 상태가 됐고 그때부터 다른 문제가 시작됐다.

Table of contents

Open Table of contents

원인 — 어긋나는 세 순간

색인은 IndexProductJob 이 큐를 타고 데이터베이스 변경을 따라 갱신하므로 그 사이에 틈이 생긴다. 상품을 등록하면 MySQL 에는 바로 들어가는데 검색에는 refresh_interval 만큼 뒤에 나오므로 사용자는 등록했는데 안 보인다고 한다.

삭제는 더 곤란한데 검색 결과에는 나오는데 클릭하면 없는 상태가 된다. IndexProductJob 이 실패하면 MySQL 만 바뀐 채로 남는다. 사용자 요청은 이미 성공으로 끝난 뒤라 그 실패가 사용자에게 안 보인다.

조치 — 유형별로 다르게 다루기

등록하고 목록으로 돌아가는 화면은 검색이 아니라 최근 등록 순이므로 색인이 필요 없어서 MySQL 에서 조회하게 했다. 삭제는 두 가지 방법이 있었는데 나머지처럼 큐로 보내는 것과 요청 안에서 색인 삭제를 기다리는 것이다. 뒤쪽을 골랐다. 이유는 나머지는 나중에 반영돼도 되지만 삭제된 것이 보이는 것은 곤란해서다. 대신 삭제 요청의 응답이 색인 왕복만큼 느려지는 것을 감수했다.

검색으로 얻은 목록을 화면에 뿌리기 전에 WHERE id IN (...) 으로 한 번 더 확인해 색인에 있는데 없는 것은 뺐다. 검색을 빠르게 하려고 색인을 뒀는데 결국 MySQL 을 또 보는 셈이지만 확인만 하는 것이라 무겁지 않았다.

검증 — 밀림을 아는 방법

밀려 있다는 것을 알아야 대응할 수 있으므로 큐의 대기 개수와 indexed_at 의 최댓값 둘을 봤다. 두 번째가 더 정확했는데 개수가 적어도 오래된 것이 안 처리되면 문제이기 때문이다.

기준을 넘으면 알림이 오게 했는데 처음에 기준을 잘못 잡아서 새벽 _bulk 배치가 돌 때마다 알림이 왔다. 배치는 원래 색인을 몰아서 갱신하므로 밀리는 것이 정상이라 정상적으로 밀리는 시간대를 빼고 기준을 다시 잡았다.

주의 — 끊기지 않는 재색인

색인이 크게 어긋나면 다시 만들어야 하는데 처음에는 전체를 지우고 다시 넣었다가 그 사이 몇 분 동안 검색이 비었다. 지금은 products_v2 를 따로 만들어 다 채운 뒤 _aliases 로 별칭을 바꾸고 옛 색인을 지운다.

OpenSearch 공식 문서대로 add 와 remove 가 원자적으로 일어난다. 별칭이 두 색인을 동시에 가리키는 순간이 없으므로 사용자가 못 느낀다. 색인에 무엇을 넣을지도 정했다. 검색 조건에 쓰이는 것과 목록에 보이는 것만 넣고 상세 내용은 상세 화면에서 MySQL 로 가져온다.

배경 — 남은 어려움

갱신 실패를 어떻게 복구할지가 아직 어렵다. failed_jobs 에 기록해 두고 나중에 다시 넣는데 그것이 밀리면 어긋난 채로 오래 간다.

매핑을 바꾸려면 _reindex 로 전체를 다시 만들어야 하는 것도 남아 있는데 필드 하나 추가에 몇 시간이 걸리기도 한다. 두 곳의 값이 다를 때 MySQL 이 맞다는 것은 분명하다. 그러면 색인의 값 필드가 왜 필요한지가 애매하게 남았다.

정리


Share this post on:

Previous Post
이름으로 리소스를 판단하지 않는다
Next Post
실제로 읽히던 두 컬럼