문제가 생기면 추측으로 고치지 않고, 측정하고 재현해 원인을 좁힌 뒤 최소한으로 고치는 걸 선호합니다.
눈에 보이는 증상보다 원인을 끝까지 파고드는 편입니다.
특히 보안·동시성·장애처럼 평소엔 안 보이다 터지면 큰 지점을 코드와 데이터로 막는 데 관심이 많습니다.
성능을 위해 코드를 넓게 갈아엎기보다, 필요한 곳만 고치고 그 근거를 남기는 편입니다.
Tech Stack
Java
Spring Boot
JPA
MySQL
PostgreSQL
Redis
AWS
Docker
k6
Project — Surtitle
AI 검색 노출 진단 서비스SW마에스트로 17기
2026.04–진행중 · 팀 프로젝트 · 스캔 코어 담당
ChatGPT·Perplexity 같은 AI 검색에 사이트가 잘 노출되는지 진단하는 서비스.
서버가 사용자 URL을 대신 스캔하는 구조라 보안·동시성·외부연동 안정성이 핵심이었습니다.
팀이 기능을 10여 개 슬라이스로 나눠 맡았고, 저는 fetch·content·보안·scoring 등 스캔 코어를 담당했습니다.
담당 부분은 외부 호출을 모의 구현으로 바꿔 네트워크 없이 통합 테스트로 검증했습니다.
사이트를 여러 개 등록하면 화면이 전부 느려지던 N+1 제거 9.4×
- 한 계정이 사이트를 여러 개 등록하면 각 사이트 화면이 다 느려졌습니다. 발행본 수·사이트 수를 하나씩만 바꿔 재보니, 응답 크기는 그대로인데 사이트 수에 비례해 느려졌습니다.
- 원인은 그룹의 사이트를 돌며 목록에 쓰지도 않을 발행본을 전량 읽던 N+1이었습니다. id만 가져오는 2쿼리로 바꿨습니다.
- 481ms → 51ms(9.4배). 결과값은 같아 눈에 안 띄는 회귀라, 전량 조회가 한 번도 안 나가는지 테스트로 확인했습니다.
스캔 각 단계 시간을 재서 숨은 병목 제거 2.8×
- 단계별로 시간을 재보니 스캔 시간의 94%가 content 분석 한 단계에 몰려 있었습니다.
- 중복 파싱부터 없앴는데 10%밖에 안 줄었습니다. 다시 보니 여러 AI 크롤러 관점이 같은 페이지를 매번 처음부터 다시 추출하던 것이었습니다.
- 같은 HTML은 한 번만 추출해 재사용하도록 바꿔 content 단계를 283ms → 100ms(2.8배)로 줄였습니다.
부하 테스트로만 드러난 사용량 88% 유실 수정
- 부하 테스트 뒤 카운터를 열어보니 기록돼야 할 서빙 사용량의 88%가 버려지고 있었습니다.
- 저부하에선 멀쩡해서 트래픽 많은 고객일수록 더 어긋나던 문제입니다.
- 서빙마다 바로 저장하던 걸 모아서 한 번에 저장하도록 바꿔 유실을 없앴습니다.
사용자 URL을 서버가 대신 요청하는 구조의 공격 표면 하드닝
- 아무 URL이나 서버가 대신 요청하다 보니 내부망 주소나 클라우드 메타데이터가 새어 나갈 위험이 있었습니다.
- 외부 요청을 하나의 보안 경로로 통일해 사설 IP·리다이렉트 우회를 매번 검사하고, 느린 호스트가 스레드를 잡아먹지 않도록 DNS 조회를 고정 풀로 묶었습니다.
- 여러 페이지가 같은 잡을 동시에 갱신하다 나는 유실은 비관적 락으로 막았습니다.