구글이 RSS를 죽인 방식, 그리고 인프라 엔지니어가 아직도 RSS를 쓰는 이유
사내 위키에 "릴리즈 노트 모아보는 대시보드 좀 만들어주세요"라는 요청이 들어왔다. Kubernetes, Terraform, 각종 CVE 공지... 제품마다 알림 채널이 제각각이라 결국 내가 꺼내든 건 20년 넘은 프로토콜, RSS였다. 그런데 막상 피드 URL을 모으다 보니 절반쯤은 죽어 있거나, 찾기가 이상하리만치 어려웠다.
왜 이렇게 됐는지 잘 정리한 글이 Open RSS의 "How Google helped destroy adoption of RSS feeds"다. Hacker News에서 주기적으로 다시 올라오는 글인데, 단순한 구글 욕이 아니라 "플랫폼이 개방형 프로토콜을 다루는 패턴"에 대한 케이스 스터디로 읽으면 실무자에게도 쓸모가 많다.
도입: 왜 피드 URL 찾기가 이렇게 어려워졌나
원문이 정리한 구글의 RSS 관련 행보를 시간순으로 요약하면 이렇다.
- Chromium 초기 버전: 주소창에 RSS 버튼이 기본 내장. 피드가 있는 페이지면 아이콘이 떴다. 어느 날 예고도 이유도 없이 사라짐.
- 2007년 FeedBurner 인수: 원래 피드를 구글이 소유한 사설 피드로 대체하고 광고·추적을 붙이는 서비스. 2012년 10월 API 종료, 2022년 7월에는 이메일 구독 등 대부분의 기능을 걷어냄. 구독 메일에 박혀 있던 피드 URL이 그대로 깨졌다.
- 2013년 Google Reader 종료: "충성 사용자층은 있지만 사용량이 감소했다"는 것이 공식 사유. 당시 구글 엔지니어는 "프로젝트에 있는 내내 여러 사람이 이걸 죽이려 했다"고 말했다고 원문은 전한다.
- Google Alerts: 2008년 10월 RSS 수신 추가 → 2013년 7월 제거 → 반발 후 복원. 다만 그땐 이미 많은 사용자가 떠난 뒤였다.
- Chrome RSS 확장: 제거했다가 일주일 만에 "실수였다"며 복원.
- Google News: RSS 지원을 deprecate 후 2017년 12월 완전 종료. 구글 자체 링크는 계속 잘 동작했다.
- 2021년 5월: Chrome에 RSS 지원을 다시 넣겠다고 발표. 이후 공식 출시 소식은 없는 상태로 보인다.
원문은 이 패턴을 Embrace, Extend, Extinguish로 부른다. 개방형 프로토콜 위에 제품을 올려 신뢰와 점유율을 얻고, 락인이 끝나면 프로토콜 지원을 걷어내는 방식이다. 기술적으로 RSS가 죽은 게 아니다. 원문 첫 문장도 "RSS 피드는 살아 있고 지금도 많이 쓰인다"로 시작한다. 죽은 건 발견 가능성(discoverability)과 사용자 신뢰다.
핵심: RSS는 죽지 않았다, 눈에 안 보일 뿐
RSS의 동작 원리는 허무할 만큼 단순하다. 정적 XML 파일 하나를 HTTP로 GET 해오는 게 전부다. 서버 푸시도, 인증 협상도, SDK도 없다. 웹 페이지는 <head>에 다음 한 줄로 피드 위치를 알려준다.
<link rel="alternate" type="application/rss+xml"
title="RSS" href="https://example.com/feed.xml">
브라우저의 RSS 버튼이 하던 일이 딱 이 태그를 파싱해서 아이콘을 띄우는 것이었다. 그 버튼이 사라지자, 피드는 존재하는데 일반 사용자 눈에는 안 보이는 상태가 됐다. 마치 서버에 서비스는 떠 있는데 로드밸런서에서 타겟 그룹을 빼버린 것과 같다. 헬스체크는 통과하는데 트래픽이 0인 상황.
직접 확인해보자. 임의의 블로그에서 피드 링크를 뽑아내는 한 줄짜리 명령어다.
$ curl -sL https://openrss.org/blog | \
grep -oE '<link[^>]*application/(rss|atom)\+xml[^>]*>'
<link rel="alternate" type="application/rss+xml" title="Open RSS" href="/blog/feed">
피드를 찾았으면 실제로 긁어본다. XML 파싱은 xmllint(libxml2-utils 패키지)로 충분하다.
$ curl -sL https://news.ycombinator.com/rss | \
xmllint --xpath '//item/title/text()' - | head -3
Show HN: I built a thing
Ask HN: How do you monitor your homelab?
The unreasonable effectiveness of plain text
여기서 중요한 포인트. 이 두 명령어는 API 키도, OAuth 토큰도, rate limit 협의도 필요 없다. 요즘 어떤 SaaS든 알림을 받으려면 앱 등록하고 스코프 정하고 토큰 로테이션 정책까지 세워야 하는 걸 생각하면, RSS의 운영 비용은 거의 0에 수렴한다. 인프라 엔지니어가 RSS를 아직 좋아하는 이유가 바로 이거다.
실무 관점: 어디에 쓰고, 어디서 터지는가
실제로 쓰는 자리
내가 굴려본 용도는 대략 이렇다.
- 업스트림 릴리즈 추적: GitHub 릴리즈는
https://github.com/{org}/{repo}/releases.atom로 피드가 나온다. 태그는/tags.atom. 웹훅 설정 없이 조회만으로 끝난다. - 보안 공지 수집: 벤더 시큐리티 어드바이저리 페이지 상당수가 여전히 RSS/Atom을 제공한다. 슬랙 채널로 흘려보내면 담당자 눈에 들어온다.
- 상태 페이지: Statuspage 기반 서비스는 대부분
/history.rss를 제공한다. 클라우드 장애를 이메일보다 먼저 잡을 때가 있다.
파이프라인도 단순하다. cron이나 CronJob으로 주기 실행 → 마지막 처리 GUID 저장 → 신규 항목만 Webhook 전송. Python 기준 핵심만 추리면 20줄 안에 끝난다.
import feedparser, json, pathlib, requests
STATE = pathlib.Path("/var/lib/feedbot/seen.json")
seen = json.loads(STATE.read_text()) if STATE.exists() else {}
url = "https://github.com/kubernetes/kubernetes/releases.atom"
d = feedparser.parse(url, etag=seen.get("etag"))
if d.status == 304: # 변경 없음 → 조용히 종료
raise SystemExit(0)
known = set(seen.get("ids", []))
for e in reversed(d.entries):
if e.id in known:
continue
requests.post(WEBHOOK, json={"text": f"{e.title}\n{e.link}"}, timeout=5)
known.add(e.id)
STATE.write_text(json.dumps({"etag": d.get("etag"), "ids": list(known)[-200:]}))
etag를 넘겨서 304를 받으면 바로 빠지는 부분이 핵심이다. 이걸 빼먹고 5분마다 전체 피드를 받아오면 상대 서버 입장에서는 그냥 봇 트래픽이다. 실제로 차단당한다.
흔한 함정
1) 파서는 관대하지만, 서버 응답은 아니다. 가장 자주 보는 에러가 이거다.
xmllint --xpath '//item/title' feed.xml
feed.xml:1: parser error : Start tag expected, '<' not found
<!DOCTYPE html>
^
XML인 줄 알았는데 HTML이 왔다는 뜻이다. 원인은 대개 셋 중 하나다. (a) 피드 URL이 옮겨졌는데 301이 아니라 홈으로 200 리다이렉트, (b) Cloudflare 챌린지 페이지, (c) User-Agent 없는 요청 거절. curl -I로 Content-Type부터 확인하는 습관을 들이자.
$ curl -sIL -A "feedbot/1.0" https://example.com/feed | grep -iE '^(HTTP|content-type|location)'
HTTP/2 301
location: https://example.com/feed.xml
HTTP/2 200
content-type: application/rss+xml; charset=UTF-8
2) FeedBurner 경유 URL. 오래된 블로그는 아직도 feeds.feedburner.com/...을 걸어둔 경우가 있다. 원문에 나오듯 구글은 2012년에 API를, 2022년 7월에 이메일 구독을 포함한 대부분의 기능을 정리했다. 이 URL을 파이프라인에 박아두면 언제 끊길지 모르는 SPOF다. 가능하면 원본 사이트의 피드로 갈아타라.
3) 상대 경로 href. 위 grep 예시에서 href="/blog/feed"처럼 상대 경로가 나온다. 자동화에서 그대로 GET 하면 InvalidURL로 죽는다. 반드시 base URL과 join 해야 한다.
4) GUID 신뢰 문제. 어떤 CMS는 글을 수정할 때마다 GUID를 새로 발급한다. 그러면 같은 글이 반복 알림된다. 이럴 땐 GUID 대신 link의 정규화된 형태(쿼리스트링 제거)를 키로 쓰는 게 안전하다. 반대로 pubDate만 믿으면 타임존 없는 값 때문에 하루치가 통째로 재발송되는 사고가 난다.
트레이드오프와 대안
RSS는 폴링 기반이다. 실시간성이 필요한 알림(장애 탐지 같은)에는 부적합하다. 5분 폴링이면 최대 5분 지연이고, 폴링 간격을 줄이면 상대 서버에 부담이다. 실시간이 중요하면 Webhook을, 그게 없으면 RSS를 쓰는 식으로 계층을 나누는 게 맞다.
대안으로는 GitHub Releases API(rate limit·토큰 필요), 벤더 SNS/이메일(파싱 지옥), 유료 SaaS 모니터링 등이 있다. 셋 다 RSS보다 운영 비용이 높다. 반대로 RSS는 제공자가 언제든 끌 수 있다는 게 최대 리스크다. 이 글이 지적하는 바로 그 지점이다. 그래서 나는 중요한 피드는 응답 자체를 아카이빙해두고, 피드가 죽었을 때 알림이 오도록 "N일간 신규 항목 0건" 조건도 같이 건다. 조용히 죽는 게 제일 무섭다.
정리
한 줄 요약: RSS는 기술적으로 멀쩡한데 플랫폼이 발견 경로를 걷어내서 안 보이게 된 것이고, 자동화 관점에서는 여전히 가장 싸고 튼튼한 알림 소스다.
누가 언제 쓰면 되냐면,
- 쓰기 좋은 경우: 업스트림 릴리즈/보안 공지/상태 페이지 추적, 인증 없이 읽기만 하면 되는 정보, 지연 수 분을 감내할 수 있는 알림.
- 피해야 할 경우: 초 단위 실시간성이 필요한 장애 알림, 인증이 필요한 사내 데이터, 항목 수가 수만 건인 대용량 동기화.
- 운영 시 필수: ETag/If-Modified-Since 조건부 요청, GUID 정규화, "피드가 조용히 죽었는지" 감시, FeedBurner 같은 중개 URL 제거.
그리고 한 가지 더. 이 글의 진짜 교훈은 RSS가 아니라 의존성 선택에 있다. 플랫폼이 무료로 얹어주는 편의 기능은 그 회사의 전략이 바뀌는 순간 사라진다. Google Reader가 그랬고, FeedBurner API가 그랬다. 우리 스택에서 "그 회사가 내일 없애도 괜찮은가"를 한 번쯤 점검해볼 만하다. 개방형 프로토콜 위에 직접 얇게 구현해두면, 벤더가 손을 떼도 curl은 계속 돈다.