본문 바로가기
C.W.K.
Stream
Lesson 02 of 04 · published

뇌가 멈춰도 검색은 계속돼

~11 min · determinism, guarantee, offline, availability

Level 0꺼진 심지
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"전부 켜졌을 때 잘 되는지는 쉬운 시험이야. 화려한 부품을 뺐을 때 무엇이 남는지를 봐야 해."

새벽 세 시에 무엇이 남을까

임베딩 서버와 reranker가 멈춘 밤을 생각해봐. 그래도 2년 전에 쓴 한 문장을 찾아야 해. 모델이 검색 경로에 들어 있는 시스템이라면 모델과 함께 검색도 멈춰. Lantern에서는 키워드 쿼리를 그대로 보낼 수 있어. 우연히 비상 기능이 발동해서가 아니라, 핵심 경로가 애초에 모델 서버와 연결되어 있지 않기 때문이야.

언제나 로컬에서 끝나는 경로가 둘 있어

  • 키워드 검색은 쿼리 단어를 디스크의 역색인과 맞추고 순위를 계산해. 모델도 네트워크도 필요 없어.
  • 문구 자동완성은 입력한 말 뒤에 코퍼스에서 실제로 이어진 표현을 로컬 인덱스에서 찾아. 키를 누르는 속도로 답하지.

모델 서버를 완전히 지워도 이 두 경로는 같은 입력에 같은 결과를 내.

모델이 필요한 기능은 부족함을 숨기지 않아

dense 벡터 검색과 하이브리드의 벡터 절반, rerank에는 모델 서버가 필요해. 순수 벡터 요청은 서버가 없으면 503 오류로 실패 사실을 알리고, 하이브리드 검색은 키워드 결과를 내되 벡터가 빠졌다고 응답에 표시해. 일부 기능이 빠진 결과를 완전한 검색인 것처럼 포장하지 않는 거야.

가장 중요한 경로를 로컬 상태만으로 계산되게 만들어. 원격 서비스는 이미 작동하는 결과를 더 좋게 하는 데 쓰고, 그 서비스가 멈췄을 때는 무엇이 빠졌는지 이름 붙여 알려.

보장은 재시도 횟수에서 나오지 않아

캐시와 재시도, 긴 제한 시간은 장애 가능성을 낮춰줄 뿐이야. Lantern의 키워드 검색은 모델에 연결된 적이 없어서 모델 장애로 실패할 수 없어. 없는 의존성의 장애를 대비할 필요도 없지. '대체로 될 것'이라는 희망보다 '그 고장과 연결되어 있지 않다'는 구조가 훨씬 강한 보장이야.

이 구분은 시험 방법도 단순하게 만들어. 모델 서버의 연결을 끊은 상태에서 FTS와 자동완성의 결과가 그대로인지 확인하면 돼. 하이브리드와 벡터 요청은 약속한 오류나 기능 저하 표시를 내야 하고. 고장 난 척을 복잡하게 흉내 내지 않고 실제 의존성을 제거해 구조를 검증할 수 있어.

핵심은 더 좋은 대체 기능을 준비하는 것이 아니라, 어떤 기능이 어떤 의존성을 갖는지 처음부터 분리하는 데 있어. 그래야 장애가 생겼을 때 계속 작동하는 경로와 멈추는 경로를 예측할 수 있고, 운영 중에도 약속한 범위를 정확히 설명할 수 있어.

Code

FTS는 모델 없이 돌고, 하이브리드는 기능 저하를 밝혀·python
def search(query: str, mode: str = "fts") -> Envelope:
    if mode == "fts":
        # Pure local index. No network. Cannot be taken down by a model outage.
        return Envelope(results=fts_match(query), degraded=[])

    if mode == "vector":
        if not model_server.reachable():
            raise ServiceUnavailable("vector search needs the embedding server (503)")
        return Envelope(results=vector_match(query), degraded=[])

    if mode == "hybrid":
        fts_hits = fts_match(query)               # always available
        try:
            vec_hits = vector_match(query)         # best-effort enhancement
            return Envelope(results=fuse(fts_hits, vec_hits), degraded=[])
        except ServiceUnavailable:
            # Serve the half that works — and SAY the other half is missing.
            return Envelope(results=fts_hits, degraded=["vectors_unavailable"])

External links

Exercise

매일 쓰는 것 중 장애가 났을 때 잃으면 가장 속상할 기능 하나를 적어. 그 기능의 모든 원격 의존성을 추적해. 호출마다 따져 봐: 반드시 필요한가, 없어도 핵심은 돌아가는 보조 기능인가? 필수 호출 하나를 보조 기능으로 재설계해서, 그 서비스가 꺼져도 코어가 계속 돌게 해.
Hint
매번 통하는 방법은 하나야. 미리 계산하거나 색인해 둘 수 있는 건 로컬에 두고, 그 기능이 이미 가진 데이터만으로 답하게 만들어. 원격 호출은 이미 작동하는 답을 더 좋게 할 뿐, 답과 빈 화면을 가르는 조건이 되면 안 돼.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.