

Total Events: 975Average Latency: 66us (66 마이크로초)read: 60.38ms (731 calls)write: 4.42ms (244 calls)eBPF 프로파일러 결과, 개별 시스템 콜의 평균 지연 시간(66us)은 매우 빠르다는 것이 확인되었다.
진짜 문제는 속도가 아니라 압도적으로 많은 호출 횟수이다. read 시스템 콜에 소요된 총 시간 60.38ms는, read 자체가 느려서가 아니라 매우 빠른 read를 731번이나 반복 호출하여 누적된 결과이다.
read 731회 발생read 시스템 콜이 발생했다. "로그인"보다 "의미 기반 검색" API가 이 오버헤드의 주범일 가능성이 매우 높다.main.py 코드의 의미 기반 검색 로직은 다음과 같이 추정된다.
SELECT한다. (SELECT * FROM article_semantic_vectors)for문으로 반복하며, 검색어 벡터와 일일이 코사인 유사도를 계산한다.read 731회의 정체는 2번 단계에서 발생한다. DB 드라이버가 네트워크 소켓을 통해 DB의 모든 벡터 데이터를 애플리케이션으로 가져오기 위해 731번에 걸쳐 잘게 쪼개어 읽어온 것이다.
이것은 전형적인 "Fetch-All-Loop-in-Python" 안티패턴이며, 데이터가 증가함에 따라 성능이 치명적으로 저하되는 구조이다.
이 분석 결과를 바탕으로 다음과 같은 조치를 취할 수 있다.
현재 방식은 기사가 1만 개면 1만 개를, 10만 개면 10만 개를 read해야 하므로 스케일링이 불가능하다.
그리고 현재 사용 중인 표준 MySQL RDS는 pgvector처럼 벡터 검색에 특화된 인덱스(HNSW, IVF 등)를 지원하지 않는다. 731번의 read를 유발하는 "Fetch-All-Loop"가 느린 근본적인 이유이다.
이 문제를 해결하기 위한 AWS 생태계 내의 조치는 다음과 같다.
대안 1 (DB 마이그레이션): Amazon Aurora (MySQL 호환 에디션) 사용
RDS for MySQL이 아닌, Amazon Aurora (MySQL 호환)는 벡터 스토어 기능을 지원한다.pgvector와 유사하게 DB가 직접 코사인 유사도를 계산하고 상위 N개만 반환하도록 쿼리를 최적화할 수 있다.read 731회가 read 10~20회로 줄어들어, 가장 근본적인 병목이 해결된다.대안 2 (하이브리드): Amazon OpenSearch Service 도입
WHERE article_id IN (id1, id2, ...) 쿼리를 보내 최종 데이터를 가져온다.벡터 DB 도입이 당장 어렵다면, DB 마이그레이션이 복잡하다면,read 횟수는 줄일 수 없지만 read 속도를 높이는 차선책을 선택할 수 있다.
해결책1 : Redis 같은 인메모리(In-Memory) 캐시를 도입한다.
변경 후 흐름:
article_semantic_vectors 테이블의 모든 벡터를 Redis에 미리 저장한다.read를 수행한다.기대 효과: read 총 시간이 60.38ms에서 10~15ms 정도로 감소할 수 있다.
한계: "Fetch-All-Loop"라는 근본적인 설계 문제는 해결되지 않아, 데이터 증가에 따른 부하는 여전히 존재한다.
해결책2 : Amazon ElastiCache (Redis)를 도입한다.
변경 후 흐름:
article_semantic_vectors 테이블의 모든 벡터를 Redis에 미리 저장해 둔다.read를 수행한다.기대 효과: read 총 시간이 60.38ms에서 10~15ms 정도로 크게 감소할 수 있다.
한계: "Fetch-All-Loop" 자체는 해결되지 않아, 기사가 수십만 개로 늘어나면 Redis의 메모리 한계와 루프 오버헤드에 부딪힌다.
write 호출 최적화 (로그 버퍼링)write: 4.42ms (244 calls)는 read에 비해 심각하지 않지만, 이 역시 불필요하게 잦은 호출이다.
logging.info(...) 같은 로그를 즉시 파일이나 stdout에 244번 write한 것이다.write한다.write 244회가 write 5~10회로 줄어들어 불필요한 I/O가 감소한다.