Issue 01중국 AI
AC POST
중국 AI 목록
掘金2026년 11월 4일 05:44중국어 → 한국어

Zig로 처음부터 만든 헤드리스 브라우저 Lightpanda, 100개 페이지에 123MB

Chrome을 개조하지 않고 Zig로 새로 구현한 헤드리스 브라우저로, 100개 페이지 처리 시 123MB 메모리를 쓴다고 소개했다.

중국어 원문을 AI로 번역했습니다. 고유명사와 수치는 원문 표기를 우선하며, 중요한 판단에는 아래 출처 원문을 함께 확인하세요.

AI Agent 한 무리에 브라우징 능력을 붙인다고 가정해 보자. 동시 실행 인스턴스 50개, 각 인스턴스는 실제 웹페이지를 열고 JavaScript를 실행하고 폼을 채우고 DOM을 읽어야 한다. 이 일을 headless Chrome으로 하면 메모리 청구서가 보기 좋지 않을 것이다. 단일 인스턴스가 몇백 MB를 가볍게 먹어치우고, 50개 인스턴스면 시작부터 수십 GB에 달하는데, CPU 점유율과 매번의 콜드 스타트에 걸리는 몇 초는 아직 계산에 넣지도 않았다. 크롤러와 자동화를 만드는 팀들은 이 고통에 이미 무뎌졌고, 너무 무뎌진 나머지 "왜 기계가 쓰는 브라우저가 사람의 육안을 위해 준비된 렌더링 엔진 한 세트를 등에 업어야 하는가"라고 되묻는 사람이 거의 없다. Lightpanda는 이 질문에 대한 정면 답변이다. Chromium을 fork하지 않고, WebKit을 patch하지도 않으며, Zig로 AI Agent와 자동화만을 위해 존재하는 헤드리스 브라우저를 처음부터 작성했다. GitHub에서 4만 1천 개가 넘는 스타는 이 문제에 시달리는 팀이 적지 않다는 것을 말해준다.

사람에게 픽셀을 렌더링하지 않는 브라우저

Lightpanda의 자기소개는 단 한 문장이다. AI와 자동화를 위해 설계된 헤드리스 브라우저. 이 문장의 핵심은 '헤드리스'가 아니다. headless Chrome도 헤드리스다. 핵심은 'AI를 위해 설계'되었다는 점이다. 오늘날의 웹페이지는 JavaScript를 떠나서는 거의 돌아가지 않는다. Ajax, 단일 페이지 애플리케이션, 무한 스크롤, 즉시 검색, 그리고 React, Vue, Angular 같은 프레임워크가 페이지를 실제로 스크립트를 실행해야만 내용을 볼 수 있는 프로그램으로 바꿔놓았다. 그래서 일찍부터 렌더링을 포기하고 HTTP 요청만 보내는 크롤링 방식은 대부분의 현대 사이트에서 이미 통하지 않으며, 자동화 도구에는 JavaScript를 돌릴 수 있는 커널이 반드시 있어야 한다.

문제는 기성 솔루션이 Chrome뿐이라는 점이다. Chrome의 설계 목표는 화면 위에서 사람에게 매끄럽고 아름답고 애니메이션이 있는 페이지를 그려주는 것이며, 이를 위해 완전한 렌더링 파이프라인과 합성기, GPU 프로세스, 폰트 조판, 미디어 디코딩을 달고 다닌다. 자동화 시나리오에서는 이런 것들이 하나도 쓰이지 않지만, 메모리 1MB, CPU 사이클 하나하나를 고스란히 지불해야 한다. 누군가는 Chrome에 시작 매개변수를 몇 개 더 넣으면 되지 않느냐고 물을 수 있다. 답은 안 된다는 것이다. Chrome의 헤드리스 모드가 꺼버리는 것은 오직 창뿐이며, 렌더링 파이프라인과 합성기, GPU 프로세스는 여전히 백그라운드에서 돌아가고 메모리의 큰 몫은 하나도 줄지 않는다. 이것은 스위치 문제가 아니라 아키텍처 문제다.

Lightpanda의 판단은 단호하다. Chromium에서 깎아내는 것보다, 자동화에 필요한 능력만 남긴 브라우저를 처음부터 만드는 편이 낫다는 것이다. 그래픽 렌더링 엔진이 없고, 사람에게 보여줄 픽셀 하나도 없으며, 메모리는 전부 Zig가 명시적으로 관리한다. 프로젝트는 2023년 2월에 착수했고 AGPL-3.0 라이선스로 오픈소스화되었으며, 내가 이 글을 쓰는 시점에 저장소는 41130개 스타, 2021개 fork를 기록하고 있고 가장 최근 코드 푸시는 바로 어제였다. 프로젝트 배후의 팀은 동시에 호스팅형 클라우드 서비스를 유지하고 있으며, 오픈소스 버전은 완전한 자체 호스팅 방식이고 두 라인은 동일한 커널 세트를 공유한다.

123MB 대 2GB: 공식 벤치마크의 셈법

말로만 가볍다고 하는 것은 의미가 없다. Lightpanda는 README에 재현 가능한 벤치마크 한 세트를 올려두었다. AWS EC2 m5.large 인스턴스에서 네트워크를 통해 실제 웹페이지 933개를 실제로 요청하고, 그중 100개 페이지의 데이터를 뽑아 비교한 것이다.

지표 Lightpanda Headless Chrome 격차 최대 메모리(100페이지) 123MB 2GB 약 16배 실행 시간(100페이지) 5초 46초 약 9배 그래픽 렌더링 엔진 없음 완전한 Blink 아키텍처 차이 구현 언어 Zig 주로 C++ —— 네이티브 Windows 버전 없음, WSL2 경유 있음 —— 라이선스 AGPL-3.0 BSD 등 허용적 라이선스 ——

테스트 방법 자체도 짚고 넘어갈 만하다. 이것은 정적 페이지 몇 개를 골라 돌려서 나온 홍보용 숫자가 아니라, 공식 demo 저장소에 공개된 크롤러 벤치마크로, 네트워크를 통해 실제로 933개 사이트를 요청한 것이며 누구든 그 m5.large를 띄워 다시 돌려볼 수 있다. m5.large는 vCPU 2개, 메모리 8GB의 엔트리급 기종으로, 이 사양을 고른 것 자체가 테스트 목표가 하드웨어를 쌓아 점수를 올리는 것이 아니라 비용에 민감한 프로덕션 환경을 모사하는 것임을 말해준다.

먼저 찬물을 한 바가지 끼얹자면, 이것은 공식 자체 측정 데이터이며 당신의 사이트 조합과 네트워크 조건, 동시성 모델이 다르면 수치는 반드시 달라질 것이다. 그러나 이 격차의 자릿수는 구조적인 것이지 매개변수를 조정해서 나온 것이 아니다. 렌더링 트리를 유지하지 않고 레이아웃 합성을 하지 않으며 GPU를 건드리지 않는 브라우저와, 완전한 그래픽 스택을 짊어진 브라우저가 같은 크롤링 작업을 수행할 때 메모리가 한 자릿수(10배) 차이 나는 것은 합리적인 예상이다. 최대 메모리 행을 다시 보라. 100개 페이지를 동시에 열어도 123MB만 차지한다는 것은 단일 페이지 상주 오버헤드가 대략 1~2MB이며, Chrome 쪽은 페이지당 20MB 안팎이라는 뜻이다. 이것을 비용의 언어로 환산해 보자. 원래 64GB 머신 한 대로 Chrome 인스턴스 30개를 돌리면 숨이 턱에 차던 것이, Lightpanda로 바꾼 뒤에는 같은 머신이 몇백 개 세션을 떠받치고도 여유가 있다. 인스턴스 단위로 과금하는 클라우드 Agent 플랫폼에게 이것은 최적화가 아니라 가격 모델의 재작성이다.

골격은 Zig, 심장은 여전히 V8

브라우저를 처음부터 만든다는 것은 분수에 맞지 않는 장난감 프로젝트처럼 들리지만, Lightpanda가 돌아갈 수 있는 핵심은 모든 것을 스스로 만들지 않았다는 데 있다. JavaScript 엔진은 V8을 그대로 내장하는데 Chrome과 같은 것이어서 ES 신기능과 온갖 기교를 부린 사이트 스크립트도 그대로 실행된다. HTTP 로딩은 Libcurl, HTML 파싱은 html5ever를 쓰는데 이는 Servo 프로젝트가 여러 해 다듬어온 파서다. Zig는 이 성숙한 C 및 Rust 컴포넌트들을 메모리가 통제 가능한 하나의 전체로 접착하는 역할을 하며, 빌드 요구 사항은 Zig 0.17.0이다.

왜 Chromium을 fork해서 고치지 않는가? Chromium은 수천만 줄 코드의 거대한 괴물이라 fork한 뒤에는 매일 업스트림의 보안 패치와 아키텍처 진화를 따라가야 하는데, 작은 팀은 도저히 쫓아갈 수 없다. Lightpanda가 택한 컴포넌트 전략은 시간으로 검증된 파싱 계층과 실행 계층만 빌려오고 스케줄링과 메모리 관리는 직접 작성하는 것으로, 이렇게 하면 업스트림이 업그레이드될 때 컴포넌트 버전만 교체하면 되고 숲 전체를 병합할 필요가 없다. V8에는 디테일이 하나 더 있다. 빌드 시 V8 스냅샷을 바이너리에 내장할 수 있어 매번 시작할 때 스냅샷을 생성하는 오버헤드를 절약하고 콜드 스타트가 더 빨라지는데, 이는 작업 단위로 브라우저를 띄우는 시나리오에 매우 실용적이다.

기능 목록을 봐도 이것이 노림수가 브라우징이 아니라 자동화라는 점을 알 수 있다. CORS, DOM 트리와 DOM API, XHR과 Fetch, 쿠키, 사용자 정의 HTTP 헤더, 프록시 지원, 네트워크 가로채기, 내장 광고 차단에 더해 robots.txt를 준수하는 스위치까지 갖추고 있어, 시작 시 해당 파라미터를 붙이면 사이트 규칙에 따라 얌전히 크롤링한다. 또 하나 주목할 만한 신호는 테스트를 대하는 태도다. 프로젝트는 매일 Web Platform Tests의 채점 결과를 perf.lightpanda.io에 공개적으로 게시하며, 통과율과 실패 항목을 한눈에 볼 수 있다. 매일 자신이 몇 점인지 공개하는 프로젝트는 대개 발표회 PPT에서만 점수를 자랑하는 프로젝트보다 신뢰할 만하다.

CDP는 그대로, 기존 스크립트는 한 줄도 고치지 않는다

브라우저를 바꿀 때 가장 숨은 비용은 자동화 코드를 다시 쓰는 것이다. Lightpanda는 이 비용을 거의 0에 가깝게 눌렀다. Chrome DevTools Protocol을 네이티브로 구현하고 WebDriver BiDi도 지원하므로, Puppeteer와 Playwright 스크립트는 연결 주소만 이쪽으로 지정하면 된다. CDP 서비스를 실행하는 데는 명령어 하나면 충분하다.

docker run -d --name lightpanda -p 127.0.0.1:9222:9222 lightpanda/browser:latest ./lightpanda serve --obey-robots --host 127.0.0.1 --port 9222 ./lightpanda fetch --dump markdown https://demo-browser.lightpanda.io/campfire-commerce/

Puppeteer 쪽은 이렇게 생겼다. connect 부분 한 줄을 빼면 나머지 코드는 그대로 유지된다.

import puppeteer from 'puppeteer-core' ; const browser = await puppeteer. connect ({ browserWSEndpoint : 'ws://127.0.0.1:9222' , }); const context = await browser. createBrowserContext (); const page = await context. newPage (); await page. goto ( 'https://demo-browser.lightpanda.io/amiibo/' , { waitUntil : 'networkidle0' }); const links = await page.evaluate( () => Array . from ( document . querySelectorAll ( 'a' )). map ( a => a. getAttribute ( 'href' )) ); console . log (links); await browser. disconnect ();

참고로 fetch 하위 명령 자체도 쓸모 있는 스위스 아미 나이프다. 페이지를 HTML, Markdown, PNG, PDF로 바로 내보낼 수 있고, 구조화 데이터 모드로는 JSON-LD, OpenGraph, Twitter Card와 meta 태그를 하나의 JSON으로 묶어낼 수 있어 콘텐츠 정제나 SEO 점검 시 파서를 다시 작성할 필요가 없다. 비동기 렌더링 페이지를 상대할 때 fetch는 대기 파라미터를 제공해, 고정 밀리초를 기다리거나 특정 셀렉터가 나타나기를 기다리거나, 아니면 일부 사용자 정의 스크립트가 참값을 반환하기를 기다렸다가 내보낼 수 있다. 지연 로딩 하나를 기디리려고 Puppeteer 전체를 끌고 나올 필요가 없다는 뜻이다. PNG 내보내기는 짚고 넘어가자면, 텍스트 수준 렌더링의 스냅샷으로 페이지 구조를 빠르게 확인하는 데 적합하며 픽셀 단위로 충실한 스크린샷은 아니므로, 시각적 회귀 테스트는 여전히 진짜 Chrome에 의존해야 한다.

또한 운영 환경을 겨냥한 두 가지 설계도 짚을 만하다. CDP 서비스는 TCP 포트를 수신하는 것 외에 Unix 도메인 소켓도 수신할 수 있으며, 파일 권한을 곧바로 소유자만 읽고 쓸 수 있게 설정해 두어 같은 머신의 멀티테넌트 시나리오에서는 포트를 여는 것보다 안전하다. BiDi 프로토콜 지원은 CDP와 동시에 켤 수 있는데, 이는 새로운 표준의 클라이언트와 옛 생태계의 스크립트가 같은 인스턴스에서 공존할 수 있음을 뜻하므로 마이그레이션 기간에 둘 중 하나를 골라야 할 필요가 없다. Playwright 사용자의 대응 진입점은 connectOverCDP로, 마찬가지로 연결 파라미터 한 줄만 바꾸면 되고 페이지 객체, 로케이터, 어서션 작성 방식은 전부 그대로 유지되어 기존 테스트 스위트를 브라우저와 함께 바꿀 필요가 없다.

Agent 모드와 PandaScript: LLM으로 시범 제작, 베어메탈에서 재실행

브라우저 내장 Agent는 올해 신규 프로젝트의 필수 요소인데, Lightpanda의 방식에는 보기 드문 실용적 설계가 하나 있다. agent 하위 명령은 자연어 작업을 받아 브라우저의 탐색, 클릭, 양식 작성, 구조화 데이터 추출을 제어하며, 모델 제공자는 Anthropic, OpenAI, Gemini, Vertex, Mistral, Hugging Face를 비롯해 Vercel AI Gateway와 OpenRouter 같은 집계 게이트웨이까지 포괄하고, 로컬 모델은 Ollama나 llama.cpp로 돌리며, 심지어 ChatGPT 구독에 로그인해 Codex를 곧바로 사용할 수도 있어 별도로 API key를 살 필요가 없다. 또 하나의 엔지니어링 디테일이 있다. Agent와 브라우저가 같은 프로세스에서 실행되어 매번의 도구 호출이 프로세스 내부의 직접 조작인데, 흔한 방식처럼 Agent 프로세스가 CDP를 통해 외부 Chrome과 메시지를 주고받지 않아 IPC 직렬화 오버헤드 계층 하나를 통째로 아낄 수 있으며, 속도와 메모리 우위가 Agent 모드에서도 그대로 유지된다.

진짜 묘수는 출력 단에 있다. 한 번의 Agent 세션 산출물은 하나의 PandaScript이며, 본질은 vanilla JavaScript에 Lightpanda에 내장된 브라우저 원시 연산(primitives) 집합을 더한 것이다. 세션에서 내보내기(export) 명령을 입력해 스크립트를 저장하고, 이후 run 서브커맨드로 오프라인 재생하면 스크립트 실행은 결정적이고 토큰 소모가 전혀 없다. 즉, 개발 단계에서는 대형 모델이 반복적으로 시행착오를 거쳐 흐름을 조정하게 하고, 프로덕션 환경에서는 모델이 전혀 들어가지 않은 결정적 스크립트를 실행한다. LLM은 탐색을, 스크립트는 실행을 담당하며 두 단계의 비용 모델이 완전히 분리된다. PandaScript가 평범한 JavaScript라는 점도 매우 중요하다. git에 넣을 수 있고, 코드 리뷰를 할 수 있고, diff를 뜰 수 있어 프로덕션 환경에서 문제가 생겼을 때 근거를 대고 확인할 수 있지, 모델 샘플링 기록 더미를 놓고 그때 무슨 일이 있었는지 추측할 필요가 없다. 수동 조작만 원한다면 모델이 없는 REPL 모드도 있어 디버깅 단계에서 명령을 하나씩 시험하기에 적합하다. 자주 쓰는 서브커맨드도 갖춰져 있다. 태스크 파라미터를 붙이면 한 번에 실행을 마치고 종료되어 스크립트화 호출에 적합하고, 현재 제공자에서 사용 가능한 모델을 나열하는 서브커맨드는 모델 이름을 추측하는 난감함을 피해 준다.

MCP 서비스의 세션 격리는 대다수 프레임워크보다 세밀하게 설계됐다

Lightpanda는 MCP 서버를 내장하며, stdio 모드는 표준 JSON-RPC 2.0을 사용해 MCP 설정에 적어 넣으면 Claude Code 같은 클라이언트가 직접 띄울 수 있다. 더 주목할 만한 것은 HTTP 모드다. 명령 하나로 9223 포트에서 서비스를 띄우고, 여러 Agent 클라이언트가 동시에 같은 엔드포인트에 POST해도 서로 간섭하지 않는다. 격리 메커니즘은 Mcp-Session-Id 요청 헤더에 의존한다. 이 헤더 없이 initialize를 발起하는 클라이언트는 완전히 새로운 세션에 배정되고, 응답에 세션 ID가 담겨 돌아오며, 이후 요청에 이 세션 ID를 붙이면 자기 세션에 남는다. 두 Agent가 일부러 같은 ID를 보내면 동일한 브라우징 컨텍스트를 공유하며, 여러 Agent가 같은 페이지를 협동 조작하는 워크플로에 적합하다.

세션에는 명시적 관리 인터페이스도 있어 생성, 목록, 종료에 대응하는 도구가 모두 있고, 특정 세션에 DELETE 요청을 보내면 파기된다. run 도구는 호출 측의 세션에서 PandaScript를 직접 실행하며, 기본 60초 타임아웃으로 스크립트가 멈춰버리는 것을 방지하고, 스크립트에서 연 페이지는 종료 시 자동으로 닫히지만 Cookie와 storage는 보존되어 로그인 상태가 여러 번의 실행에 걸쳐 이어질 수 있으니, 먼저 로그인한 뒤 작업해야 하는 스크래핑 흐름에 매우 우호적이다. 스크립트 파라미터는 소스 코드 문자열을 직접 넘길 수도 있고 이전에 저장한 파일 경로를 넘길 수도 있으며, 반환값과 콘솔 출력이 함께 돌아온다. 백엔드 엔지니어에게 접속 형태는 하나의 HTTP 엔드포인트이고, 요청 하나로 한 번의 브라우징 태스크를 완료하며 프로세스 생명주기를 전혀 스스로 관리할 필요가 없다. 공식 측은 별도로 Agent skill 저장소도 유지하고 있어, 코딩 Agent에 설치하면 바로 호출할 수 있다. 백엔드에서 curl 한 줄로 브라우저를 구동할 수 있다:

lightpanda mcp --port 9223 curl -s http://127.0.0.1:9223/mcp -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"run","arguments":{"script":"const page = new Page(); await page.goto(\"https://example.com\"); return page.title();"}}}'

시중의 적지 않은 MCP 브라우저 서버는 단일 페이지 전역 상태라서 두 Agent가 동시에 몰리면 서로의 페이지 내비게이션을 엉뚱하게 날려버린다. Lightpanda의 이 세션별 페이지 분리, Cookie 분리, 메모리 분리 설계는 다중 Agent 프로덕션 환경에서 가장 아픈 지점을 정면으로 겨냥한다.

언제 바꾸지 말아야 하는가

장점을 이렇게 많이 늘어놓았으니 마지막에는 경계를 분명히 그어야 한다. 그렇지 않으면 오도하는 셈이다. 첫 번째 칼날은 라이선스에 있다. AGPL-3.0은 강한 Copyleft이므로, Lightpanda를 폐쇄 소스 상업 제품에 내장해 외부에 서비스를 제공하려면 법무 검토를 먼저 통과해야 하며, 내부 자체 사용이라면 기본적으로 무방하다. 두 번째 칼날은 플랫폼 지원이다. 네이티브 Windows 바이너리가 없어 Windows 사용자는 WSL2로 들어가거나 Docker를 써야 하며, 팀 전체가 Windows 머신이라면 접속 비용을 계산에 넣어야 한다. 세 번째는 호환성 상한이다. 매일 공개하는 WPT 성적을 보면 아직 커버하지 못한 Web 플랫폼 기능이 적지 않으며, 복잡한 시각 렌더링, WebGL, Canvas 핑거프린팅, 미디어 재생에 크게 의존하는 사이트는 동작이 실제 Chrome과 일치하지 않을 가능성이 높으니 대상 사이트로 실측해야 하고, 돌아간다고 가정해서는 안 된다.

또 다른 두 가지 작은 함정이 있다. 텔레메트리가 기본으로 켜져 있으니 신경 쓰인다면 환경 변수로 끄면 된다. nightly 바이너리는 Linux 배포판의 glibc 버전 요구가 있어 x86_64는 2.35 이상, arm64는 2.38 이상이어야 하며, 오래된 이미지에서 그대로 실행하면 로더 부재 오류가 난다. 마이그레이션 전에 작은 검증 체크리스트를 만드는 것을 권한다. 다섯에서 열 개의 대상 사이트 대표 페이지를 골라 fetch에 Markdown 내보내기를 더해 한 번 돌려보고, 추출 결과가 완전한지 눈으로 대조한 뒤, Chrome 쪽 결과와 샘플링 비교하면 반나절이면 호환성 하한을 파악할 수 있다. 나의 제안은 시나리오별로 나누는 것이다. 스크래핑, 폼 자동화, 구조화 데이터 추출처럼 시각적 충실도가 필요 없는 작업은 먼저 Lightpanda로 전환하면 메모리와 속도의 장부상 이득을 당일 바로 확인할 수 있고, 사용자가 보는 것을 픽셀 단위로 재현해야 하거나 회귀 스크린샷 비교를 돌려야 하는 작업은 계속 Chrome 계열에 남겨두는 것이다. 30년 된 이 브라우저 카테고리에서 처음으로 어떤 프로젝트가 자신의 사용자가 인간이 아니라고 공개적으로 인정했다는 사실 자체만으로도, 4만 개의 스타 너머로 한 번 더 눈여겨볼 가치가 있다.