11만 건 데이터에서 100ms 응답! NewCodes 자동완성 API 최적화 비법 공개

by DD
4개월 전
조회수 132

11만 개 데이터 기반 자동 완성 API의 응답 속도를 1초에서 100ms 이내로 90% 이상 개선

인덱스 추가, LOWER 함수 인덱스, JOIN → EXISTS, 비정규화, JDBC Template 등 다양한 기술을 활용하여 성능 향상

PostgreSQL 데이터베이스(DB)의 쿼리 최적화와 Nginx 설정을 통해 API 응답 시간 단축

AI를 활용하여 코드 최적화 방향성을 잡고, 개발 환경과 운영 환경의 차이점을 파악하여 문제 해결

CompletableFuture를 활용한 병렬 처리, 응답 데이터 크기 축소, Nginx Rate Limit 설정 변경 등 부가적인 개선

최종적으로 운영 서버에서 40ms의 응답 속도를 달성하며, 사용자 경험을 극대화함

PostgreSQL 인덱스(Index) 최적화 전략

본문에서는 자동 완성 API 성능 개선을 위해 PostgreSQL의 다양한 인덱스 기법을 활용했다는 점이 눈에 띈다.

B-Tree 인덱스(B-Tree Index): 초기 성능 개선을 위해 `varchar_pattern_ops` 연산자 클래스를 사용한 접두사 검색에 최적화된 인덱스 생성

함수 기반 인덱스(Functional Index): `LOWER()` 함수로 인해 인덱스를 타지 못하는 문제를 해결하기 위해 함수 기반 인덱스를 생성하여 성능 향상

커버링 인덱스(Covering Index): `term` 테이블의 `total_frequency` 컬럼을 포함하는 커버링 인덱스를 생성하여 I/O 횟수를 줄이고 성능을 개선

이처럼 데이터베이스(DB) 쿼리 성능 향상을 위해서는 인덱스 종류, 컬럼 선택, 함수 사용 여부 등을 고려한 적절한 인덱스 설계(Index Design)가 필수적이다.

JOIN 대신 EXISTS를 사용한 쿼리 최적화

글에서는 `JOIN` 연산으로 인한 성능 저하 문제를 해결하기 위해 `EXISTS` 연산자를 활용한 사례를 제시한다.

JOIN의 문제점: `JOIN`은 두 테이블의 모든 매칭 레코드를 조합하여 Planning Time과 Execution Time이 길어지는 문제 발생

EXISTS의 장점: 데이터 존재 여부만 확인하고, 존재하면 즉시 종료하여 스캔 범위를 줄여 성능 향상

최적화 효과: `EXISTS`를 사용함으로써 기업 검색 쿼리의 성능을 개선하고, 100ms 이내의 응답 시간을 달성

이처럼 데이터베이스(DB) 쿼리 최적화는 JOIN, EXISTS, 서브쿼리(Subquery) 등 다양한 연산자의 특성을 이해하고, 데이터 특성에 맞는 연산자를 선택하는 것이 중요하다.

JPA 오버헤드(Overhead) 제거를 위한 JDBC Template 적용

본문에서는 JPA의 오버헤드를 줄이기 위해 자동 완성 쿼리에 한정하여 JDBC Template을 적용한 경험을 공유한다.

JPA의 단점: JPA는 ORM(Object Relational Mapping) 기술로, 객체지향적인 개발을 돕지만, 단순 조회 쿼리에서는 오버헤드가 발생

JDBC Template의 장점: JDBC Template은 JPA를 거치지 않고, JDBC를 사용하여 데이터베이스(DB)에 직접 접근하여 성능 향상

최적화 효과: JDBC Template 적용을 통해 자동 완성 쿼리의 응답 시간을 더욱 단축하고, 최종적으로 운영 서버에서 40ms의 응답 시간을 달성

성능이 중요한 부분에서는 JPA 대신 JDBC Template과 같은 로우 레벨(Low-level) 기술을 활용하는 것이 효과적일 수 있다.

Nginx Rate Limiting 설정과 API 안정성 확보

글에서는 Nginx의 Rate Limiting 설정을 잘못하여 API 요청이 실패하는 문제를 겪고, 이를 해결한 과정을 설명한다.

문제 발생 원인: Nginx의 Rate Limiting 설정이 과도하여, 사용자의 연속된 요청이 제한되어 API 요청 실패

해결 방법: Rate Limiting 설정을 조정하여, 1초에 10개의 요청을 허용하도록 변경

교훈: 간단한 코드 배포에도 전체 아키텍처를 고려해야 하며, 특히 Rate Limiting, 캐싱(Caching) 등은 시스템 안정성에 중요한 영향을 미침

이처럼 API의 안정성을 위해서는 Rate Limiting, Circuit Breaker 등 다양한 기법을 활용하여, 과도한 트래픽으로부터 시스템을 보호해야 한다.

AI 기반 코드 최적화와 개발자의 역할

본문에서는 AI를 활용하여 코드 최적화 방향성을 잡고, 개발자가 최종 판단을 내리는 균형 잡힌 태도를 강조한다.

AI 활용: AI를 통해 코드 수정, CompletableFuture를 활용한 병렬 처리, 쿼리 및 인덱스 수정 등 다양한 최적화 시도

개발자의 역할: AI가 제시한 결과가 항상 정확하지 않으므로, 개발자는 문제 정의, 설계 능력, 검수를 통해 최종적인 판단을 내려야 함

AI의 한계: AI가 Nginx 설정을 제대로 이해하지 못하는 등, AI의 한계를 인지하고 개발자의 주도적인 역할 강조

AI 시대에도 개발자는 문제 해결 능력, 아키텍처 설계 능력, 코드 검증 능력을 갖추는 것이 중요하다.

자동 완성 API 응답 데이터 크기 축소

글에서는 네트워크 전송 시간을 줄이기 위해 응답 데이터 크기를 축소한 경험을 공유한다.

개선 방법: 불필요한 필드명을 제거하고, 배열 첫 번째 요소로 타입을 구분하여 JSON 응답 크기 감소

효과: 가독성은 다소 떨어지지만, 자동 완성 API와 같이 빈번한 요청에서는 효과적

병렬 처리: CompletableFuture를 사용하여 Corporation, Theme, Term 조회를 병렬 처리하여 쿼리 실행 시간 단축

이처럼 API 성능 개선을 위해서는 응답 데이터 크기 최적화, 병렬 처리, 캐싱(Caching) 등 다양한 방법을 고려해야 한다.

11만 개 데이터에서 100ms 내에 응답