내장 브라우저에 광고 차단 레이어 구현해 로딩 속도 2배 개선
목차
광고 차단을 직접 붙여본 이유
사내 도구로 쓰는 내장 브라우저에 외부 트래커가 너무 많이 붙어서 응답 속도가 들쭉날쭉했음. 페이지 로딩 자체보다 추적 스크립트 기다리는 시간이 더 길어 보일 정도였고, 그래서 차단 레이어를 직접 끼워 넣어봤음.
접근 방식 비교
확장 기능을 그대로 가져다 쓰는 방법도 있었지만, 임베디드 환경이라 권한이 제한적이었음. 결국 네트워크 가로채기 후 룰 매칭으로 결정.
| 방식 | 장점 | 포기한 이유 |
|---|---|---|
| 확장 기반 | 룰셋 풍부 | 임베디드에서 로드 불가 |
| 호스트 파일 | OS 단에서 끝 | 사용자 머신 건드려야 함 |
| 네트워크 인터셉트 | 앱 내부에서 완결 | 룰 직접 관리 필요 |
세 번째로 가니까 룰 파싱이 골치였음. EasyList 형식을 그대로 쓰면 좋았겠지만 일부 신택스만 지원하기로 타협함.
룰 매칭 로직
요청 URL이 들어오면 도메인 기준으로 1차 컷, 그 다음 패턴 매칭. 패턴은 글롭만 지원하고 정규식은 제외했음 — 사용자 작성 룰에서 정규식이 잘못 들어가면 매칭 비용이 폭주해서.
fun shouldBlock(url: String): Boolean {
val host = url.toHost() ?: return false
if (host in domainDenyList) return true
return patternRules.any { it.matches(url) }
}
처음엔 룰을 한 번에 로드해서 매번 순회했는데, 룰셋이 1만 줄 넘어가니까 페이지 한 번 열 때 수백 ms 손해봄. 도메인 딕셔너리로 인덱싱하고, 패턴 룰은 도메인별 버킷으로 쪼갰더니 체감 차이가 컸음.
- 도메인 정확 일치는 해시 셋으로 O(1)
- 와일드카드는 서픽스 트라이로
- 패턴 룰은 도메인 기준 버킷에서만 평가
시행착오
- WebSocket 누락: 처음엔 일반 HTTP만 가로챘다가, 추적 스크립트가 WS로 빠져나가는 케이스 발견하고 핸들러 추가
- CSS 인젝션 타이밍: DOM 로드 전에 스타일 주입하니 깜빡임이 사라짐. 너무 늦게 넣으면 광고 영역이 한 번 보였다가 사라져서 거슬림
- 화이트리스트: 파트너 페이지 일부가 광고 도메인과 같은 CDN을 써서 오탐. 호스트 + 경로 조합으로 예외 처리
효과 측정
룰 적용 전후로 동일 페이지 10회 평균을 재봤음.
| 지표 | 적용 전 | 적용 후 |
|---|---|---|
| DOMContentLoaded | 1.8s | 0.9s |
| 총 요청 수 | 142 | 61 |
| 전송량 | 3.2 MB | 1.1 MB |
요청 수 절반 이하로 떨어지니 모바일에서 특히 체감이 컸음. 다만 룰셋 갱신 주기를 너무 짧게 잡으면 시작 시점이 느려져서 12시간 캐시로 절충함.
남은 숙제
룰 충돌 디버깅이 여전히 불편함. "이 요청이 왜 막혔지?"를 추적하려면 로그를 토글해야 하는데, 매칭된 룰 ID를 응답 헤더로 떨어뜨리는 식으로 개선 예정. 그리고 사용자별 커스텀 룰을 어디까지 허용할지가 다음 라운드 고민거리.
다음.
댓글 0
첫 댓글 달아줘.