초당 100건은 서버 용량이 아니다: 결제 API 요청 제한을 다시 측정한 이유
결제 API 앞 Redis 필터에 사용자별 5건/초, 전역 100건/초 제한을 두었다. 하지만 단일 계정과 닫힌 루프 부하는 전역 용량을 측정하지 못했다. 개방 루프에서 100~120건/초의 성능 꺾임을 확인하고, 요청률 제한과 과부하 보호를 구분한 과정을 정리한다.
검색 결과가 없습니다
제목, 태그, 카테고리로 검색
결제 API 앞 Redis 필터에 사용자별 5건/초, 전역 100건/초 제한을 두었다. 하지만 단일 계정과 닫힌 루프 부하는 전역 용량을 측정하지 못했다. 개방 루프에서 100~120건/초의 성능 꺾임을 확인하고, 요청률 제한과 과부하 보호를 구분한 과정을 정리한다.
나무위키+한국어 위키백과+영어 위키백과+뉴스+웹텍스트+C4 한국어 코퍼스 1,215만 건 검색 엔진 프로젝트를 2개월간 26편의 기술 블로그로 기록하고 총정리한다. MySQL LIKE 5,000ms 타임아웃에서 시작하여 임베디드 Lucene + Nori 한국어 형태소 분석으로 전환하고, Caffeine+Redis 2계층 캐시(82% 히트율), MySQL Replication R/W 분리, Nginx 스케일아웃(에러율 13.25%→0%), Debezium+Kafka CDC, Redis 3노드 Consistent Hashing까지 분산 아키텍처를 완성한다. 검색 품질은 동의어 확장, 오타 교정, UnifiedHighlighter snippet, LTR(NDCG +4.8%p), 카테고리 28개 자동 분류, Aho-Corasick 금칙어 필터링으로 고도화하고, RAG(Gemini SSE 스트리밍)로 AI 검색 요약을 제공한다. 자동완성 시스템 설계(CQRS + MapReduce + CDC)의 이론과 실제 구현의 매핑, 26편 전체 시리즈 링크, 핵심 수치 총정리를 포함한다.
BM25 수동 가중치(title:3, content:1)의 한계를 Learning to Rank(LTR)로 극복한다. 카테고리 28개 자동 분류(키워드 기반, 정확도 83%) → SortedSetDocValuesFacetCounts 네이티브 Facet 전환 → 태그 216만 건 인덱싱을 1회 재색인으로 통합 반영한다. LLM-as-a-Judge(Gemini)로 학습 데이터 900쌍을 생성하고(1차 실패 98% → 5초 딜레이+지수 백오프로 해결), XGBoost LambdaMART 14개 피처로 학습하여 NDCG@10을 0.6910 → 0.7387(+4.8%p) 개선한다. XGBoost4J ARM64 네이티브 추론, Rescorer Top-200 재랭킹, RefreshListener 기반 FacetState 캐싱, MultiCollectorManager 단일 패스 수집까지 구현하지만, 2코어 ARM Free Tier에서 LTR ON 시 CPU 포화(72배 악화)를 k6로 실측하여 LTR_ENABLED=false로 비활성화한다.
단일 Redis 인스턴스에서 KEYS 블로킹(34.6ms), 배치↔실시간 워크로드 간섭(GET 최악 15.5ms), volatile-lru 보안 위험을 실측하고, KEYS→SCAN 전환 + 3노드 Consistent Hashing + 블랙리스트 전용 인스턴스 격리로 해결한다. 가상 노드 150개 ConcurrentSkipListMap 라우팅, 노드 장애 시 Lucene fallback, 100 VU 부하 테스트로 검증한 과정을 정리한다.
PostService의 dual-write 구조(MySQL + Lucene 직접 호출)가 데이터 불일치, 강결합, 불완전한 캐시 무효화를 유발하는 문제를 점진적으로 해결한다. Spring ApplicationEvent로 디커플링 → @ApplicationModuleListener 비동기 전환(쓰기 5,315ms→33ms) → Debezium + Kafka CDC로 binlog 기반 모든 변경 캡처까지. 100 VU 부하 테스트로 각 전환을 검증하고, dual-write를 원천 차단하여 검색 인덱스 정확성을 보장한다.
Caffeine(L1) + Redis(L2) 2계층 캐시를 구현하고, Trie 자동완성을 Redis flat KV O(1) GET으로 전환하여 Stateless 앱을 만든 뒤 k6 부하 테스트로 Before/After를 비교한 과정을 정리한다. 분산 전환 순서(Redis → Replication → 스케일아웃)의 의존 관계와 비용 분석을 포함한다.
k6 stress 테스트(200 VU, 25분)로 단일 서버(ARM 2코어, 12GB)의 한계점(~100-150 VU)을 수치로 확인하고, JVM/Tomcat 튜닝이 CPU-bound 병목에서 역효과를 낸 과정과 배포 미반영 사고를 기록한다.
1,215만 건 테이블에서 COUNT(*) 제거(Page→Slice), 30페이지 제한, Deferred Join을 조합하여 최신 게시글 목록 조회를 19,424ms에서 8.33ms로 개선하고, k6 load 테스트(100 VU, 20분)에서 에러율 32.53%→0%를 달성한 과정을 정리한다.