AI 조회를 실행할 노드는 등록할 때가 아니라 실행할 때 고른다

AI 조회를 주 노드에서 떼어 내려고 연결을 스탠바이 주소로 등록하면, 실행할 노드는 등록하는 순간에 정해집니다. 그 뒤 노드 역할이 바뀌어도 연결은 같은 주소를 읽습니다. 이중화가 전환되어 그 스탠바이가 주 노드가 되면 AI 조회는 경고 없이 주문·결제와 같은 노드에서 돕니다. 연결이 옛 주 노드를 가리키고 그 노드가 아직 살아 있으면, 조회는 성공하면서 전환 시점에 멈춘 데이터로 답합니다. 복제 지연이 커진 스탠바이도 마찬가지로 실패 신호 없이 몇 분 전 재고로 답합니다.
OwlDB로 연결한 DB에서는 OwlAI가 노드를 정하지 않습니다. 실행 요청에는 노드가 없습니다. OwlDB가 요청을 받은 순간의 노드 역할과 복제 지연을 보고 실행할 노드를 고르고, 응답에 어느 노드에서 왜 실행했는지를 싣습니다. 고를 노드가 없으면 OwlAI가 잠시 뒤 같은 요청을 다시 보냅니다. 이 글은 노드를 언제 누가 고르는지, 고를 노드가 없을 때 무엇을 하는지, 그리고 스키마 분석의 통계 조회가 왜 주 노드로 가는지를 설명합니다.
주소로 정한 노드는 역할이 바뀐 것을 모른다
AI는 질문 하나에 SQL을 여러 번 보냅니다. 코드 값 몇 개를 확인하는 짧은 조회, 실행 계획 조회, 본 조회가 모두 원천 DB로 갑니다. DB를 처음 연결할 때 도는 스키마 분석(「컬럼의 뜻은 DDL에 없다, 질문 전에 값을 읽어 둔다」)은 테이블마다 카탈로그 조회와 표본 조회를 이어 보냅니다. 이 조회가 주 노드로 가면 업무 트랜잭션과 CPU·입출력을 나눠 씁니다. 그래서 운영 DB에 스탠바이(주 노드를 실시간으로 복제해 두는 대기 서버)가 있으면 AI 조회를 그쪽으로 보내려는 것이 자연스럽습니다.
직접 연결(관리자가 접속 정보를 손으로 입력한 연결)로도 그렇게 할 수 있습니다. 연결을 등록할 때 스탠바이 주소를 넣으면 됩니다(「운영 DB에 AI를 붙이자는 말에 보안팀이 묻는 세 가지」). 설정 하나로 끝나고 OwlAI 쪽에 장치를 더할 필요가 없습니다. 대신 연결이 아는 것은 주소 하나뿐이고, 그 주소의 노드가 지금 어떤 역할인지는 모릅니다. 노드 상태가 바뀔 때 주소를 고정한 연결에서 일어나는 일을 표로 놓았습니다.
| 노드 상태 변화 | 주소를 고정한 연결에서 일어나는 일 |
|---|---|
| 이중화 전환으로 등록한 스탠바이가 주 노드가 됨 | AI 조회가 경고 없이 주 노드에서 돈다 |
| 등록한 스탠바이가 멈춤 | 조회가 실패하고, 관리자가 연결을 고칠 때까지 그 DB를 채팅에서 쓸 수 없다 |
| 복제 지연이 커짐 | 조회는 성공하고, 지연만큼 지난 데이터로 답한다 |
| 연결이 가리키던 옛 주 노드가 전환 뒤에도 살아 있음 | 조회는 성공하고, 전환 시점에 멈춘 데이터로 답한다 |
위험한 쪽은 뒤의 두 줄입니다. 조회가 실패하면 사용자가 알아차리지만, 지난 데이터로 낸 답은 맞는 답과 모양이 같습니다. 창고 하나의 품목 재고를 물은 사람은 숫자를 받아도 그것이 몇 분 전 숫자인지 알 길이 없습니다.
OwlAI가 노드 상태를 따로 감시하면 판단이 두 곳에 생긴다
연결에 노드 목록을 넣고 OwlAI가 노드마다 역할과 복제 지연을 주기적으로 확인하는 방법도 있습니다. OwlDB 없이 돈다는 장점이 있습니다. PostgreSQL이라면 pg_is_in_recovery()로 역할을, 마지막으로 재생한 트랜잭션의 시각으로 지연을 읽을 수 있습니다.
그런데 이 판단은 확인 주기만큼 늦습니다. 이중화 전환은 몇 초 안에 끝나고, 그 사이에는 OwlAI가 아는 역할과 실제 역할이 다릅니다. 더 큰 문제는 같은 판단을 하는 곳이 둘이 된다는 점입니다. DB 관리 솔루션은 이미 노드 역할·지연·부하를 감시하고 전환을 직접 일으킵니다. OwlAI가 같은 감시를 한 벌 더 두면, 전환 순간에 두 제품이 서로 다른 노드를 주 노드로 압니다. 노드 상태를 가장 먼저 아는 쪽은 전환을 일으키는 쪽입니다. 그래서 OwlDB 연결에서는 노드를 고르는 일을 OwlDB가 맡습니다.
실행 요청에는 노드가 없고, 응답에는 실행한 노드가 있다
OwlDB 연결에서 OwlAI가 보내는 실행 요청에는 DB 식별자, 질문한 사람의 역할에 대응하는 계정 식별자, SQL, 행 상한이 실립니다(「OwlDB 연결은 접속 정보 대신 DB 식별자만 든다」). OwlDB는 요청을 받은 순간의 노드 역할과 복제 지연을 보고 실행할 노드를 고릅니다. 테이블 데이터를 읽는 조회는 읽을 수 있는 스탠바이로 갑니다. 이중화가 전환되면 OwlDB가 다음 요청부터 새 역할을 보고 고르므로, OwlAI의 연결에는 고칠 것이 생기지 않습니다.
응답에는 결과와 함께 실제로 실행한 노드와 그 노드를 고른 이유가 실려 옵니다. OwlAI는 두 값을 관리자 화면 SQL 실행 이력의 그 SQL 행에 함께 남깁니다. 어제 오후의 답이 어느 노드의 데이터였는지 나중에 그 행에서 확인할 수 있습니다. 스탠바이가 있는데도 주 노드에서 돈 조회가 잦다면, 그 이유도 같은 기록에 있습니다.
지난 데이터를 어디까지 받을지는 OwlDB가 정한다
스탠바이에서 읽으면 복제 지연만큼 지난 데이터를 읽습니다. 「지난달 지역별 매출」은 몇 초의 지연으로 답이 바뀌지 않지만, 방금 들어온 주문을 확인하는 질문은 다릅니다. OwlDB는 복제 지연 허용 기준을 갖고, 기준 안의 지연은 받아들이며, 기준을 넘은 스탠바이는 고르지 않습니다.
기준을 넘은 스탠바이를 건너뛰고 주 노드에서 읽는 길도 있습니다. 그러면 지연이 커질 때마다 AI 조회가 모두 주 노드로 몰립니다. 복제 지연은 주 노드에 쓰기가 몰릴 때 잘 커지므로, 주 노드가 가장 바쁜 순간에 AI 조회까지 얹히게 됩니다. 그래서 기준을 넘으면 OwlDB는 고를 노드가 없다고 답합니다.
고를 노드가 없으면 OwlAI가 잠시 뒤 다시 요청한다
읽을 수 있는 스탠바이가 없거나(NO_READABLE_REPLICA), 스탠바이의 복제 지연이 기준을 넘었거나(REPLICA_LAG_EXCEEDED), DB가 바쁘면(DATABASE_BUSY) OwlDB는 SQL을 실행하지 않고 사유 코드를 돌려줍니다. 셋 다 시간이 지나면 풀리는 일시적인 사유입니다. OwlAI는 재시도 간격을 늘려 가며 같은 요청을 몇 차례 다시 보내고, 그동안 SQL은 바꾸지 않습니다.
이 사유는 모델이 받는 도구 결과에 싣지 않습니다. 모델이 SQL을 고쳐서 풀 수 있는 사유가 아니어서입니다(「무거운 SQL은 cost 문턱 대신 DB 상태를 아는 OwlDB가 판정한다」). 재시도가 모두 실패하면 도구 결과에는 지금 이 DB를 읽을 수 없다는 사실만 실립니다. 모델이 고칠 SQL이 없으니, 멀쩡한 조건을 지우거나 다른 테이블로 돌아가는 SQL도 나오지 않습니다. 실행 비용 기준을 넘은 거절(QUERY_COST_EXCEEDED)은 다릅니다. SQL을 고치면 풀리므로 기준을 넘긴 계획 노드와 함께 모델에게 갑니다(「무거운 SQL은 cost 문턱 대신 DB 상태를 아는 OwlDB가 판정한다」).
스키마 분석의 통계 조회는 주 노드에서 읽는다
스키마 분석은 테이블마다 DB가 이미 아는 것을 읽어 옵니다(「컬럼의 뜻은 DDL에 없다, 질문 전에 값을 읽어 둔다」). PostgreSQL에서 읽는 것을 어디에 쌓이는 정보인지로 나누면, 스탠바이에서 읽어도 되는 것과 안 되는 것이 갈립니다.
| 분석이 읽는 것 | 어디에 쌓이나 | 스탠바이에서 읽으면 |
|---|---|---|
컬럼·키·주석, 값 분포(pg_stats), 행 수 추정 |
시스템 카탈로그. 주 노드의 변경이 스탠바이로 복제된다 | 주 노드와 같다 |
| 표본 행 | 테이블 데이터. 복제된다 | 지연만큼 지난 행이다 |
마지막 통계 수집 시각, 그 뒤 바뀐 행 수(pg_stat_all_tables) |
노드마다 따로 쌓는 누적 통계 | 스탠바이에서는 통계 수집이 돌지 않아 값이 비거나 다르다 |
고객이 실제로 실행한 SQL(pg_stat_statements) |
노드마다 자기 메모리에 쌓는 실행 통계 | 그 스탠바이에서 돈 SQL만 보인다 |
뒤의 두 줄을 스탠바이에서 읽으면 분석이 틀린 결론을 냅니다. 통계가 멀쩡한 테이블을 수집한 적 없는 테이블로 보고, 업무 화면이 그 테이블을 어떻게 조인하는지 보여 줄 SQL을 찾지 못합니다. 스탠바이에 남는 것은 그 노드에 붙은 보고서 조회뿐입니다. AI가 보낸 SQL은 맨 앞에 고정 주석이 붙어 있어 분석이 이 목록에서 뺍니다.
그래서 OwlDB는 분석 조회도 성격을 보고 나눕니다. 카탈로그와 표본 행을 읽는 조회는 채팅의 조회처럼 스탠바이로 가고, 노드마다 따로 쌓이는 통계를 읽는 조회는 주 노드로 갑니다. 주 노드로 가는 조회는 테이블마다 통계 몇 행을 읽는 가벼운 조회입니다. 테이블 데이터를 읽는 조회는 스탠바이가 맡으니, 스탠바이가 있으면 업무 시간에도 분석을 돌릴 수 있습니다.
설계에서 고른 것
연결에 노드를 고정하는 대신 실행할 때마다 OwlDB가 고르게 했습니다. 등록할 때 고정하면 단순하고 OwlDB 없이도 돌지만, 노드 상태가 바뀐 것을 모릅니다. OwlAI가 노드를 직접 감시하면 상태를 알 수 있지만, 같은 판단을 두 제품이 따로 합니다. 대가로 OwlAI 쪽에서는 조회마다 노드를 지정할 수 없고, OwlDB가 응답하지 않으면 OwlDB 연결의 조회는 돌지 않습니다.
지연 기준을 넘었을 때 주 노드로 넘기는 대신 다시 요청하게 했습니다. 주 노드로 넘기면 답은 빨리 나오지만, 주 노드가 가장 바쁠 때 부하를 더합니다. 대가로 지연이 길어지면 답이 늦고, 끝내 그 DB를 읽지 못한다는 답이 나올 수 있습니다. 방금 들어온 데이터를 읽어야 하는 질문도 같은 기준을 따릅니다.
일시적인 사유는 모델 대신 OwlAI가 다룹니다. 모델에게 보여 줄 정보는 모델이 SQL을 바꿔서 결과를 바꿀 수 있는 정보이고, 노드 상태는 그런 정보가 아닙니다. 대가로 재시도하는 동안 답이 늦어집니다.
노드마다 따로 쌓이는 통계는 주 노드에서 읽습니다. 분석 조회를 모두 스탠바이로 보내면 주 노드는 더 가볍지만, 분석은 업무가 실제로 도는 노드의 통계와 SQL을 보지 못합니다. 그 조회만큼의 부하는 주 노드가 집니다.
고르는 일은 맡겨도 고른 결과는 돌려받습니다. 실행 노드와 이유를 SQL 실행 이력에 남겨, 관리자가 노드 선택이 기대대로 도는지 확인할 수 있게 했습니다.
운영 DB에 스탠바이가 있고 그 이중화를 OwlDB가 관리한다면, OwlDB 연결로 노드 선택을 맡기는 편이 맞습니다. 이중화에 끼지 않은 분석 전용 복제본이 따로 있다면, 그 주소로 등록한 직접 연결로 충분합니다. 그 경우 스키마 분석이 읽는 실행 SQL과 통계 수집 시각은 그 복제본의 것이라는 점을 감안합니다.
어떤 문제를 해결하나요?
DB 연결과 OwlDB의 다른 글

엔지니어링 노트 · DB 연결과 OwlDB
배스천에는 계정 대신 DB 포워딩만 여는 키 한 줄을 넣는다
운영 DB가 사설망 안에 있고 그 앞에 배스천 호스트(사설망으로 들어가는 SSH 서버)가 있으면, OwlAI는 배스천을 거치는 SSH 터널로 DB에 붙습니다.

엔지니어링 노트 · DB 연결과 OwlDB
인증서 오류는 검증을 끄지 않고, 빠진 CA와 틀린 이름을 고쳐서 푼다
기업망에 설치한 OwlAI가 클라우드 LLM이나 고객 DB에 TLS로 붙을 때, 인증서 오류가 나는 경우는 크게 둘입니다.

엔지니어링 노트 · DB 연결과 OwlDB
RDS 목록은 액세스 키 대신 60분 뒤 만료되는 역할로 읽는다
OwlAI SaaS에서 고객의 Amazon RDS·Aurora를 연결하려면 엔드포인트·포트·엔진과 함께 DB가 공개 서브넷에 있는지, 어느 VPC·보안 그룹에 속하는지 같은 망 정보가 필요합니다.
