김병찬

Backend Engineer

chan4527@naver.com
github.com/GitBchan

문제가 생기면 추측으로 고치지 않고, 측정하고 재현해 원인을 좁힌 뒤 최소한으로 고치는 걸 선호합니다. 눈에 보이는 증상보다 원인을 끝까지 파고드는 편입니다.

특히 보안·동시성·장애처럼 평소엔 안 보이다 터지면 큰 지점을 코드와 데이터로 막는 데 관심이 많습니다. 성능을 위해 코드를 넓게 갈아엎기보다, 필요한 곳만 고치고 그 근거를 남기는 편입니다.

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 조회를 고정 풀로 묶었습니다.
  • 여러 페이지가 같은 잡을 동시에 갱신하다 나는 유실은 비관적 락으로 막았습니다.

Project — Jobveloper

AI 면접 시뮬레이션 서비스캡스톤·산학

2025.03–06 · 백엔드 리드

질문 생성·음성 변환·분석이 이어지는 AI 면접 서비스. 빌드 이후 부하 테스트로 병목을 재가며 리팩터링했습니다.

목록 API를 느리게 하던, 안 쓰는 COUNT 제거 20×
  • 보관함 목록 API가 부하 시 p99 55초·에러 17.8%로, 목록을 여는 것조차 사실상 실패했습니다.
  • 검색이 느린 줄 알았는데 EXPLAIN으로 보니 검색은 0.4ms였고, 원인은 목록에 쓰지도 않는 COUNT를 Spring Data가 매번 자동으로 날리던 것이었습니다.
  • 풀·로깅 설정으로 55초를 14.3초까지 줄인 뒤 이 COUNT를 빼니 14.3초 → 694ms(20배), 에러도 0%가 됐습니다.
풀을 키워도 안 풀리던 커넥션 풀 포화, 원인은 N+1 5.4×
  • 세션 상세 API는 부하에서 커넥션 풀이 금방 꽉 차 요청이 밀렸습니다.
  • 풀을 10에서 30으로 늘려도 안 풀려 요청당 쿼리를 세어보니, 문제는 풀 크기가 아니라 한 요청에 같은 데이터를 두 번 읽느라 쿼리가 21번 나가던 N+1이었습니다. 21번을 4번으로 줄였습니다.
  • 974ms → 182ms(5.4배), 풀 대기도 사라졌습니다.
외부 API·비동기가 얽힌 흐름에서 정합성·중복 제어
  • 무거운 AI 후처리가 저장이 커밋되기도 전에 실행돼 아직 없는 데이터를 읽거나, 연속 클릭에 같은 작업이 중복 실행됐습니다.
  • 후처리를 커밋 이후로 미루고, 중복은 멱등키와 분산 락으로 한 번만 실행되게 했습니다.

Etc.

활동 SW마에스트로 17기 (2026.04–11) — Surtitle(AI 검색 노출 진단 서비스) 스캔 코어 백엔드 개발
학력 경기대학교 컴퓨터공학부 · 2026.08 졸업예정

S3에 index.html로 업로드 · 인쇄(Ctrl+P) 시 페이지 단위로 끊깁니다