방문 노드: 11. 비교 횟수: 그대로.
2026년 9월의 로컬 시험에서 발견 프로토타입은 같은 수치를 반복 보고했다. 네트워크에 Agent가 32개일 때도, 512개로 늘었을 때도 같았다. 요청은 근처에서 최대 두 홉만 전파되므로 예상에 맞아 보였다.
그런데 시간은 달라졌다. 쿼리 지연의 95번째 백분위수가 5.66밀리초에서 47.64밀리초로 올랐다. 네트워크가 16배 커지자 쿼리는 여덟 배 넘게 느려졌다.
상충하는 숫자가 가리킨 곳은 하나였다. 방문 수 밖에서도 일이 벌어지고 있었다.
요청이 출발하기 전에 이미 전 네트워크를 돌았다
먼저 쿼리가 하는 일을 보자. 프로토타입의 각 Agent는 발견용 신호를 저장하고 소수 이웃과 연결된다. 요청이 노드를 지날 때 근처에 더 탐색할 만한 대상이 있는지 판단해야 한다. 이를 위해 그 노드와 한 홉 이웃의 공개 신호를 합친 이웃 요약을 만든다.
도시 지도에 비유하면 쿼리는 몇 개 거리만 걸을 예정이다. 이웃 요약은 교차로 안내판으로, 어느 쪽으로 갈지 돕는다.
초기 구현은 쓰기 편한 방식을 택했다. 쿼리가 시작할 때 모든 노드의 안내판부터 다시 만들고 요청을 출발시켰다.
# 早期请求路径的简化结构
adverts = build_all_neighborhood_summaries(network)
return walk_local_routes(request, adverts)
둘째 줄은 실제로 지역 경로만 걷는다. 하지만 첫째 줄이 이미 전 네트워크를 스캔했다.
기존 자원 계수는 주로 전파와 비교를 다뤄 “11개 노드 방문”을 정확히 보고했다. 전파 단계의 작업량을 답한 것이다. 전체 요약 재구축은 전파 전에 일어나 시간을 쓰고 네트워크 규모에 따라 늘었지만, 그 장부에는 없었다.
데이터 시스템에서 낯선 현상은 아니다. 데이터베이스는 소수 행을 반환해도 많은 행을 먼저 읽을 수 있고, LIMIT가 있는 쿼리도 정렬이나 인덱스 구성의 시작 비용을 먼저 낼 수 있다. PostgreSQL의 EXPLAIN 문서는 출력 행 수, 시작 비용, 전체 비용을 구별한다. 각 수치가 어느 작업 구간을 다루는지 알아야 한다.
이 Agent 프로토타입의 문제는 구체적이었다. 지역 방문으로 아낀 작업을 지역 방문에 들어가기 전에 다시 하고 있었다.
실제 필요해질 때 요약 만들기
일괄 구성을 노드별 구성으로 나눴다. 쿼리가 어느 경계에 도달해 그 이웃을 살펴봐야 할 때만 해당 요약을 만든다. 같은 동기 쿼리에서 다시 쓰면 이미 계산한 결과를 재사용한다.
# 修订后请求路径的简化结构
adverts = {}
def summary_for(edge_id):
if edge_id not in adverts:
adverts[edge_id] = build_one_neighborhood_summary(edge_id)
return adverts[edge_id]
return walk_local_routes(request, summary_for)
adverts는 한 쿼리 동안만 존재한다. 다음 쿼리는 현재 노드와 연결을 다시 읽으므로 노드 갱신, 참여, 이탈 뒤 새 요약을 자연스럽게 얻는다. 의도적으로 단순함을 남긴 것이다. 현재 프로토타입은 동기 실행하고 한 번의 발견 중 네트워크가 동시에 바뀌지 않는다. 쿼리 안의 재사용만으로 주된 이득을 얻으면서 요청 간 캐시 무효화의 복잡함도 피한다.
전체 요약을 만드는 진입점은 진단이나 전체 스냅샷 내보내기에 여전히 유용하다. 일반 쿼리가 반드시 지나는 경로에서만 옮겼다.
동시에 실제 동작을 반영하는 자원 수치 두 개를 추가했다. 요약을 몇 개 만들었는지, 요약에 기여하는 노드를 몇 번 읽었는지다. 기존 방문 수도 유지해 준비 단계까지 관찰 범위에 넣었다.
같은 부하에서 지연 곡선이 평평해졌다
같은 컴퓨터, 토폴로지, 쿼리, 설정으로 비교했다. 각 규모마다 발견 요청 12회를 실행했다. 고정 양방향 링에서 각 노드는 오프셋 1과 3의 이웃에 연결되며 최대 두 홉 전파한다. 다음은 당시의 짧은 로컬 구성 시험 기록이다.
| 네트워크 Agent 수 | 수정 전 p95 | 수정 후 p95 |
|---|---|---|
| 32 | 5.66 ms | 4.28 ms |
| 128 | 13.21 ms | 4.91 ms |
| 512 | 47.64 ms | 5.15 ms |
그림 1: 동일 부하의 과거 전후 비교. 가로축은 세 시험 규모를 배열했고 연결선은 읽기를 돕는다. 각 점은 쿼리 12회의 p95다.
Agent 512개인 묶음에서 처리량은 초당 약 22회에서 약 209회로 늘었다. 매 쿼리는 여전히 Agent 11개를 방문한다. 이제 요약 10개만 만들고 기여자 50개를 확인한다. 이 두 수치도 세 규모에서 같았다.
쌍체 분석으로 후보 수, 인계 수, 방문 수, 기존 자원 수치를 대조했고 기록상 이들은 같았다. 따라서 변경의 설명은 명확하다. 쿼리가 쓰지 않는 전처리를 없앴다. 새 시간 곡선과 추가 작업량 수치가 서로를 뒷받침한다.
이 결과는 당시 단일 컴퓨터, 동기 실행, 구성한 토폴로지에 해당한다. 각 묶음에 요청이 12개뿐이며 p95는 짧은 표본에 선형 보간한 통계량이다. 운영 환경의 꼬리 지연에는 동시성, 네트워크, 데이터 변화도 작용한다. 여기서 가치 있는 결과는 전체 규모에 따라 늘던 요청 전 작업을 실제로 찾아 제거했다는 점이다.
지역 알고리즘에는 지역적인 요청 경로가 필요하다
핵심 루프는 절제되어도 초기화, 직렬화, 인덱스 유지, 정리 단계에서 전체 데이터를 읽을 수 있다. 이번 누락은 요약 구성에 있었다. 추가 수치가 이를 같은 요청의 비용에 포함했다.
자기 시스템에서도 작은 실험을 할 수 있다. 요청에 필요한 대상은 고정하고 무관한 대상만 계속 늘리며 전체 소요 시간을 기록한다. 핵심 연산 수가 같은데 시간이 계속 늘면 요청 경로를 따라 아직 장부에 없는 일을 찾는다.
수정 뒤에는 요청이 쓰는 요약만 만든다. 요약 10개, 기여자 50개다. 한 번의 지역 쿼리를 위해 전 네트워크의 안내판을 준비하지 않게 되었다.
자료 설명: 데이터는 2026년 9월 1일 Discovery Front 로컬 용량 시험과 쌍체 분석에서 왔다. 이번에 원본 비교 파일, 실행 설정, 현재 요약 구성 코드를 대조했다. 본문 코드는 설명용 간략 구조다. 상세 위치는 출판 패키지의 SOURCE-NOTES.md를 참조한다. 기존 실험을 바탕으로 다시 쓴 엔지니어링 노트다.