상품 페이지를 스트리밍 가지치기로 받아 수신 단계에서 메모리 바운드 - #48
Open
m-a-king wants to merge 2 commits into
Open
Conversation
- 응답을 전부 메모리에 올린 뒤 자르던 것을, jsoup StreamParser 로 흘리며 하류가 읽지 않을 노드(style·주석·데이터 아닌 script)를 닫히는 즉시 버리는 방식으로 교체 - 원안(#47)은 Content-Length 검사 + 상한 초과 시 payload-too-large 실패였으나 두 이유로 전환. 실패는 지금 앞부분으로 추출에 성공하던 페이지를 확정 실패로 바꾸고 새 permanent code 가 infra→core→extractor 3 repo 순차 PR 을 부른다. 절단도 마찬가지로 손해다 - sanitize 가 절단을 LLM 직전으로 미뤄 둔 이유가 코드에 적혀 있듯, JS·style 을 걷어낸 뒤라야 같은 길이에 상품 정보가 더 담긴다. 가지치기는 버리는 대상이 어차피 하류가 버릴 것들이라 둘 다 피한다 - 작업 중 발견한 함정: StructuredDataExtractor 가 일반 JS script 를 훑어 window.__PRELOADED_STATE__ 를 찾는다(유니클로 계열). "데이터 script 아니면 버린다"로 짰다면 그 경로가 조용히 깨졌다. 보존 규칙이 두 벌(수신용·LLM 입력용) 이라는 사실을 DataScripts 에 박고, 표지 상수는 그것을 찾는 쪽이 소유하게 함 - Content-Type 게이트 신설. 지금까지 검사가 0건이라 링크가 50MB mp4·zip 을 가리켜도 전부 받았다. recall 보호를 위해 명백한 바이너리만 막고 미상은 통과 - PageContent 가 String 대신 Document 를 든다. 하류가 전부 Document 를 원해 문자열은 중간 표현일 뿐이었고, 그 결과 HtmlSnapshotPipeline 과 EmptyShellDetector 가 같은 HTML 을 두 번 파싱하던 것도 사라짐 - 상한은 둘. 와이어 바이트(끝나지 않는 스트림용, 해제 후 바이트에 걸린다)와 보존분 문자(가지쳐도 안 줄어드는 문서용). 정상 페이지는 어느 쪽에도 안 닿는다
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- 수신 바이트 상한과 보존분 문자 상한을 @ConfigurationProperties 에서 빼고 HttpPageFetcher.MAX_FETCH_BYTES · PruningHtmlParser.MAX_RETAINED_CHARS 상수로 둔다 - 이 값들이 설정이던 근거는 이관 규율("하드코딩 상수를 외부화하되 기본값 유지")인데 그 규율은 명시적으로 이관 기간 한정이었고 이관은 끝났다. 되돌아본 적이 없었을 뿐 - 밖에서 조절할 대상이 아니다. 튜닝 손잡이가 아니라 안전장치이고, SSM 실측 결과 /piki-extractor/app/ 에 있는 파라미터 4개 중 이 값들은 하나도 없었다 - 설정으로 둔 내내 아무도 지정한 적이 없다 - 같은 성격의 다른 상한(GeminiHtmlExtractor.MAX_LLM_CHARS 20만, HttpHeadlessRenderer 의 해제 상한 64MB)이 이미 상수라, 이쪽만 설정이면 같은 종류가 두 방식으로 갈린다. 그 불일치를 없앤다 - 부수효과로 이번 PR 이 만든 설정 키 개명 리스크(옛 키로 지정해 둔 값이 조용히 무시되는 것)가 사라진다. 키 자체가 없어졌다 - 상한 파라미터 오버로드는 package-private 으로 남긴다. 상한 동작 검증에 3백만 자 픽스처가 필요해 실용적이지 않기 때문이고, 패키지 밖에서는 안 보여 우회할 수 없다 - 바이트 상한 테스트는 주입 대신 실제 상수를 넘기는 17MB 본문으로 검증한다. 단언은 정확히 16MiB 에서 끊겼는지를 본다 - 부등호로 두면 몇 바이트만 읽고 끝나도 통과해 상한이 걸렸다는 증거가 안 된다 - 헤드리스 상한 주입 테스트는 가지치기 배선 테스트로 교체한다. 상한을 못 넣게 됐고, 그 테스트가 실제로 지키려던 것은 "렌더 경로도 같은 가지치기를 통과하는가" 다
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Situation
Task
원래 이슈는 "받은 뒤 자르는 지점을 앞당기자"였다. 그런데 자르는 것 자체가 손해라는 게 드러나면서, "다 받은 뒤 어떻게 자르나"가 아니라 "다 안 받는다" 로 문제를 다시 잡았다.
제약 둘: 절단도 실패도 recall 을 깎는다. 그리고 새 실패 code 를 만들면 3 repo 순차 PR 이 된다.
Action
접근 선택
수신 단계
조용히 깨질 뻔한 자리
구조 정리
안전 상한은 설정이 아니라 상수로
처음엔 두 상한을 기존 방식대로
@ConfigurationProperties에 두고 이름만 새 의미에 맞게 고쳤다. 리뷰 중에 그 전제를 다시 봤다./piki-extractor/app/에 있는 파라미터는 4개(Gemini 키 2개, 렌더 서비스 주소, 렌더 스위치)뿐이고 이 값들은 없다. 설정으로 둔 내내 아무도 지정한 적이 없다GeminiHtmlExtractor.MAX_LLM_CHARS20만, 렌더 응답 해제 상한 64MB)은 이미 상수다. 이쪽만 설정이면 같은 종류가 두 방식으로 갈린다그래서 상수로 내렸다. 부수효과로 설정 키 개명 리스크 자체가 사라진다 - 옛 키로 지정해 둔 값이 조용히 무시되는 사고는 키가 없으면 일어날 수 없다.
상한을 인자로 받는 오버로드는 package-private 으로 남겼다. 상한 동작 검증에 3백만 자 픽스처가 필요해 실용적이지 않기 때문이고, 패키지 밖(수신 경계)에서는 안 보여 안전장치를 우회할 수 없다.
구현 좌표
PruningHtmlParserHttpPageFetcher(toEntity→exchange,MAX_FETCH_BYTES상수),FetchProperties(크기 상한 제거)PageContent(String → Document + retainedChars),DataScripts(retainForParsing),StructuredDataExtractor(표지 상수 공개)HtmlSnapshotPipeline,EmptyShellDetector,DefaultProductLinkExtractor,HttpHeadlessRenderer,HeadlessExtractionPropertiesResult
fetch설정에는 UA 와 타임아웃, redirect hop 상한만 남는다. 이건 장애 때 실제로 만지고 싶어질 수 있는 값들이라 밖에 둔다연관 이슈