Browserless — это headless Chrome, упакованный как сервис, который ты разворачиваешь у себя. Его Docker-контейнер постоянно работает, принимает задачи по HTTP или WebSocket и управляет доступом через общие лимиты, а не встраивается в каждый вызывающий процесс. В REST-тестах здесь у сервиса было 0 процессов Chrome в простое: процессы Chrome появлялись только во время активного запроса и исчезали после него. То, что реально «пулится», — это пропускная способность сервиса и очередь, а не заранее прогретый набор браузерных процессов.
Я прогнал v2.55.0 на контролируемом локальном стенде — разложил запуск по этапам, проверил контроль доступа в трёх конфигурациях, сверил ответы эндпоинтов с известной эталонной картиной, сделал прогон из 30 сессий и проверил границу таймаута. Практическая польза оказалась не в ускорении, а в эксплуатации: лимиты доступа совпадали с тем, что видел клиент, а основные подводные камни были связаны с развёртыванием.
Самый полезный результат — не цифра задержки. Browserless не ускоряет старт Chrome, а ставит Chrome в режим «контрольно-пропускного пункта»: внутри одновременно находится фиксированное число сессий, за ними стоит очередь, а всем остальным возвращается HTTP 429. Этот потолок менялся с 4 до 8 и до 10, когда я менял две переменные окружения, и собственный учёт контейнера полностью совпадал со статус-кодами клиента на каждом запросе.
Что Browserless представляет собой на самом деле
Чаще всего люди ошибаются именно на уровне категории. Browserless — это не библиотека, которую ты импортируешь и вызываешь. Это Docker-образ — ghcr.io/browserless/chromium, — который запускается как долго живущий сервис. Он обслуживает браузерные задачи и отдаёт их двумя способами: через REST-эндпоинты (/content, /scrape, /screenshot, /pdf, а также /function и /unblock) и через CDP/WebSocket-интерфейс, к которому могут подключаться Puppeteer и Playwright с помощью connect().
Я тестировал REST-поверхность. WebSocket-путь тоже рабочий и широко используется, но я его не измерял.
Тестировалась версия v2.55.0, проверка выполнена 27 июля 2026 года.
| Параметр | Значение |
|---|---|
| Версия образа | v2.55.0, опубликована 14 июля 2026 |
| Chrome | 149.0.7827.0 |
| Node | 24.18.0 |
| Базовый образ | Ubuntu 24.04 |
| Звёзды GitHub | примерно 13 525 на 27 июля 2026 |
Количество звёзд меняется со временем, поэтому воспринимай это как снимок на конкретный момент.
Лицензия: SSPL-1.0 или коммерческая
В репозитории Browserless распространяется по лицензии SSPL-1.0 или по коммерческой лицензии Browserless. Перед выбором обязательно прочитай актуальный файл LICENSE и официальные рекомендации по open-source-развёртыванию. В этой статье не проводился юридический анализ коммерческих продуктов, закрытого ПО, CI-систем, хостинговых сервисов или внутренних развёртываний, поэтому конкретные сценарии к лицензии здесь не привязываются. Пусть юрист или тот, кто отвечает за лицензирование ПО, оценит модель поставки и распространения.
Browserless также продаёт облачные планы. Цены и определение единиц использования могут меняться, и в этом self-hosted-тесте они не участвовали, так что проверяй их на официальном сайте, а не используй устаревшую таблицу как доказательство для закупки.
Как работает модель сессий внутри
Измеренный REST-путь вёл себя как браузерная работа на каждый запрос, но этот стенд не заглядывал достаточно глубоко во внутренности Browserless, чтобы отличить новый процесс браузера от любой стратегии повторного использования контекста. Однако удалось установить более простую вещь: 0 процессов Chrome в простое, 11 процессов семейства chrome во время активного запроса и снова 0 после последовательного прогона. В этой конфигурации не было признаков заранее прогретого пула браузеров.
Долго живущий Node-сервис пропускает ограниченное число браузерных задач, ставит в очередь ещё ограниченное число и всё остальное отклоняет. Считай эту модель доступа архитектурным контрактом, который проверяется ниже. Не делай вывод о повторном использовании процессов или контекстов только из слова «pool»; данный стенд не может этого доказать.
У контроля доступа есть две ручки:
CONCURRENT— сколько сессий выполняется одновременно.QUEUED— сколько дополнительных запросов может ждать слот.
Эндпоинт контейнера /config показывал значения по умолчанию: CONCURRENT=10, QUEUED=10, TIMEOUT=30000. Всё, что выходит за пределы CONCURRENT + QUEUED, отклоняется сразу.
Аутентификация обязательна. Browserless v2 всегда требует токен — если не задать TOKEN, он сгенерирует случайный и выведет его в stdout при запуске. Каждый REST-вызов должен содержать ?token=.
Для наблюдаемости доступны /pressure (running, queued, CPU, memory, recently rejected), /sessions и /config. Есть ещё JSON-экспорт /metrics, но он требует переменную METRICS_JSON_PATH, а я её не использовал. Кроме того, образ запускает dumb-init как PID 1 — это и есть документированный ответ на жалобы о zombie-процессах, которые уже много лет сопровождают контейнерный Chrome.
Реалии настройки: одна команда и четыре вещи, которые в одну команду обычно не помещают
Та самая команда установки, которую все цитируют, действительно сводится к одному docker run. Но всё, что вокруг, тоже важно учесть.
Размер образа — 4,34 ГБ. Вот эта цифра должна задавать ожидания, а не время старта. Манифест содержит и linux/arm64, и linux/amd64; на моём arm64-хосте Docker скачал нативный arm64-вариант. (User-Agent Chrome внутри контейнера всё равно выглядит как X11; Linux x86_64 — это обычный косметический UA Chrome на Linux, а не эмуляция. uname -m показывает aarch64. На это люди часто жалуются как на баг.)
Для всех измерений я использовал --shm-size=2g. В стенде не было контрольного прогона на стандартном /dev/shm Docker, поэтому эта статья не может утверждать, что 2 ГБ абсолютно обязательны, или точно назвать точку отказа. Размер нужно подбирать под число браузеров и характер нагрузки.
Токен — это не формальность, а вопрос безопасности развёртывания. Без него любой, кто может достучаться до порта 3000, фактически получает браузер в твоей сети.
Сетевое взаимодействие контейнера — твоя зона ответственности. Мой стенд работал на хосте, поэтому контейнер обращался к нему через host.docker.internal (colima подставляет это через --add-host host.docker.internal:host-gateway). Перед тем как доверять измерениям, я отдельно проверил обычным curl, что контейнер действительно видит стенд.
Моя среда: colima 0.10.3 (6 CPU / 11.6 GiB) с Docker 29.2.1 на macOS 26.5.2 arm64. Стенд был только на стандартной библиотеке Python 3. Для PNG и PDF проверялись сигнатуры файлов, а не корректность декодирования, размеры, число страниц, полнота или визуальная точность.
Минимально эквивалентный запуск использует зафиксированный образ, явный токен и то выделение shared memory, которое применялось здесь:
docker run --rm -p 3000:3000 --shm-size=2g \
-e TOKEN=replace-with-a-secret \
ghcr.io/browserless/chromium:v2.55.0
После ответа /pressure?token=... аутентифицированный POST /content?token=... с JSON-телом, содержащим целевой URL, проверяет REST-путь. В продакшене клиентам также нужен ограниченный retry с jitter для ответов 429; если повторять сразу, ты просто снова врезаешься в ту же заполненную очередь.
Стоимость запуска, разложенная по этапам

Три свежих запуска docker run, медиана и диапазон min–max:
| Этап | Медиана | Диапазон | Что это на самом деле |
|---|---|---|---|
docker run → /pressure возвращает 200 | 0,78 с | 0,70–0,87 с | HTTP-эндпоинт уже отвечает; запуск браузера этим шагом не подтверждается |
готовность → первый рендер /content | 0,32 с | 0,28–0,41 с | первый наблюдаемый запрос: работа браузера + переход + возврат HTML |
последующие вызовы /content | 0,15 с | 0,147–0,154 с | задержка последующих запросов в том же контейнере |
Среднюю строку легко неправильно интерпретировать. Она не измеряет запуск браузера изолированно и не показывает, что Browserless стартует Chrome быстрее, чем in-process библиотека. Это HTTP-круговой путь в контейнер плюс работа браузера, навигация и передача ответа. Разница примерно в 0,17 секунды между первым и последующими запросами может включать влияние файловой системы, ОС, Chrome, Node или кэша контейнера. Поскольку в простое процессов Chrome не было, а этот стенд не снимал CDP-трейс и таймлайн процессов для этих вызовов, приписать этот зазор повторному использованию браузера или «амортизированному» запуску нельзя.
И ещё: это цифры из colima VM на macOS. На bare-metal Linux будет иначе. Не цитируй 0,78 с своему SRE как переносимую универсальную метрику.
Практика: как найти потолок с обеих сторон
Контракт CONCURRENT + QUEUED → 429 повторяется везде, но почти нигде не демонстрируется.
Схема теста: страница-стенд намеренно спит на сервере 5 секунд, чтобы каждый запрос гарантированно занимал одну сессию известное время. Затем одновременно отправляется CONCURRENT + QUEUED + 4 запросов, и смотрится, что вернётся, — пока отдельный поток-датчик опрашивает /pressure, чтобы читать внутренний учёт контейнера.
| Конфигурация (CONCURRENT, QUEUED) | Отправлено | HTTP 200 | HTTP 429 | Пик по /pressure на сервере (running / queued / recentlyRejected) |
|---|---|---|---|---|
| (2, 2) | 8 | 4 | 4 | 2 / 2 / 4 |
| (3, 5) | 12 | 8 | 4 | 3 / 5 / 4 |
| (5, 5) | 14 | 10 | 4 | 5 / 5 / 4 |
Из этого следуют три вещи.
Потолок каждый раз равен ровно CONCURRENT + QUEUED. Успешных ответов было 4, 8 и 10 — то есть сумма настроек в каждом случае. Количество отказов совпадало с избыточным объёмом, а он во всех трёх прогонах был 4.
Потолок меняется. Он не зашит в образ; он такой, как ты его настроил. Переход 4 → 8 → 10 только за счёт переменных окружения — вот что делает это полезным, а не просто любопытным.
И ещё: два сигнала независимы. Статус-коды моего клиента приходили из реальных HTTP-ответов; /pressure — из внутреннего учёта контейнера, который опрашивался другим потоком. В этих трёх коротких прогонах они совпали. Это делает /pressure кандидатом на продакшен-сигнал, но не полноценным контрактом для автоскейлинга: нужно ещё проверять частоту опроса, семантику сброса, агрегацию по нескольким репликам и поведение на более длинных смешанных нагрузках.
Есть один нюанс, который скрывают только counts pass/fail. Запрос в очереди не падает — он ждёт, и иногда довольно долго. При (2, 2) и 5-секундной работе успешные ответы пришли в диапазоне от 5,7 до 11,0 секунды, медиана — 8,3 секунды. Значит, полная задержка доходила примерно до двух длительностей сессии. Стенд не снимал отдельные метки времени для момента допуска и момента выполнения, поэтому полностью отнести задержку именно к ожиданию в очереди нельзя.
Как это выглядит на реальной задаче
Допустим, ты ночью рендеришь в PDF 4 000 карточек товаров, и на каждую уходит около 5 секунд. Ты ставишь CONCURRENT=5, QUEUED=5. Верхний предел пропускной способности — 5 страниц за 5 секунд, то есть одна страница в секунду, а значит вся задача займёт примерно 67 минут, если держать поток ровно заполненным. Это арифметика на основе измеренного поведения, а не бенчмарк, но именно такую арифметику стоит делать до развёртывания.
Любой запрос, который приходит после того, как все рабочие и очередные слоты заняты, может сразу получить 429; одновременная отправка не гарантирует, какой по счёту запрос проиграет гонку. Исполнитель задач должен воспринимать такой ответ как backpressure и делать ограниченный retry с jitter. Иначе можно потерять страницы, пока верхнеуровневый учёт задач продолжит жить как ни в чём не бывало — это операционный риск, а не сценарий сбоя, продемонстрированный этим стендом.
Практика: что на самом деле видят эндпоинты
Чтобы честно проверить точность рендера, тестовая страница прячет маркерный текст от любого, кто не запускает настоящий браузер. Видимая строка Runtime Injected Marker 88 собирается из JavaScript-фрагментов во время загрузки, так что непрерывного литерала для неё нет ни в одном байте, отправляемом сервером. Обычный статический fetch этой страницы возвращает 702 байта, в которых нет ни одного из маркеров.
| Эндпоинт | Результат | Байт |
|---|---|---|
/content | runtime-вставленный маркер присутствует, плюс оба статических маркера | 811 |
/scrape на #scrape-me (узел, вставленный JS) | вернул SCRAPE_TARGET_VALUE_CC | 422 |
/screenshot | ответ с PNG-сигнатурой 89 50 4E 47 | 18 621 |
/pdf | ответ с PDF-сигнатурой %PDF- | 40 974 |
| все четыре без токена | HTTP 401 (не 403) | — |
То, что /content возвращает 811 байт с внедрённым маркером, означает: страницу реально отрендерил Chromium, прежде чем HTML вернулся обратно. /scrape вытащил значение из узла, которого не существует до выполнения JavaScript. Оба сценария сработали без клиентского automation-кода — достаточно одного аутентифицированного POST.
В этом и есть суть. В той же серии проверок статический crawler полностью пропустил такой класс контента, а in-process браузерные библиотеки (chromedp, rod, Selenium) справились только после того, как я явно добавил ожидание. Browserless справился запросом формата curl. Ты меняешь automation-код на вес развёртывания.
Две оговорки к этому тезису. Доказательства относятся к классам контента моего стенда, а не ко всему современному вебу. И /unblock, антидетект-эндпоинт, я сознательно не трогал — ни один из результатов не следует трактовать как подтверждение антибот-возможностей. /function, /download и /performance тоже не тестировались.
Практика: короткая проверка на остатки
У контейнерного Chrome есть репутация оставлять трупы процессов, поэтому я прогнал 30 последовательных сессий с CONCURRENT=3 и посчитал процессы внутри контейнера.
Прежде чем доверять результатам, я откалибровал детектор. Пока сессия была активна, перечислитель /proc видел 11 процессов семейства chrome (браузер, zygote, GPU, рендереры, утилиты). Это важно: инструмент действительно видит Chrome, значит ноль после прогона — это измерение, а не слепота. Тест на утечку, который просто пишет «0 процессов» без доказательства, что он вообще умеет считать, бесполезен.
После 30 сессий: 0 процессов chrome, 0 zombie-процессов. Единственными оставшимися были dumb-init, node, Xvfb, start.sh и sh. /sessions в простое показывал 0.
Память контейнера по данным docker stats — это число, видимое оператору, а не RSS одного процесса:
| После N сессий | 0 | 5 | 10 | 15 | 20 | 25 | 30 |
|---|---|---|---|---|---|---|---|
| Память контейнера (MiB) | 294 | 300 | 301 | 302 | 302 | 303 | 303 |
Чистый рост за 30 сессий — около 9,5 МБ, а кривая на выборке плато после 10-й сессии. Это не похоже на простой линейный leak на коротком отрезке. Одно из правдоподобных объяснений — прогрев Node, но эти счётчики процессов и памяти не могут это доказать.
Ограничение по масштабу: 30 последовательных сессий — это небольшой soak, а не endurance и не параллельный прогон. Давние предупреждения EventEmitter listener в issue tracker — как раз тот тип проблем, который может проявиться через часы и тысячи сессий, а я такого теста не делал. Подтверждённый вывод только один: в этом окне на v2.55.0 накопления процессов Chrome или zombie-процессов не наблюдалось.
Граница таймаута
TIMEOUT документирован как настраиваемый параметр. Мне хотелось увидеть, как он срабатывает.
| Случай | Страница удерживалась | Статус | Время |
|---|---|---|---|
| В пределах бюджета | 2 000 мс | 200 | 2,406 с |
| За пределами бюджета | 15 000 мс | 408 | 5,007 с |
При TIMEOUT=5000 сессия, которая пыталась удерживать страницу 15 секунд, вернула HTTP 408 ровно на 5,007 секунды, а не зависла. Это единичное наблюдение подтверждает, что ограничение работает рядом с заданной границей. Оно не раскрывает реализацию таймера и не доказывает освобождение слота; более сильный тест повторил бы попытку, проверил бы возврат /sessions и /pressure в idle и затем подтвердил бы, что следующий запрос забирает освободившийся слот.
Ловушка при миграции: PREBOOT молча ничего не делает, но не сообщает об этом
Из всего, что я измерил, это тот результат, который я бы сам хотел получить до апгрейда.
В Browserless 2.0.0 были удалены PREBOOT и KEEP_ALIVE — в changelog сказано, что их убрали, потому что они путали, мало что давали и создавали баги. Решение разумное. Проблема начинается, когда конфигурацию v1 просто копируют в v2 — а это, пожалуй, самый распространённый путь обновления.
Я запускал контейнер с -e PREBOOT=true и сравнивал его с настройками по умолчанию:
| Сигнал | PREBOOT=true | По умолчанию, флаг не задан |
|---|---|---|
| Время готовности | 0,716 с | 0,776 с |
| Cold render | 0,314 с | 0,318 с |
| Warm render | 0,163 с | 0,150 с |
| Процессов Chrome в простое | 0 | 0 |
Все тайминги лежат внутри собственного диапазона min–max у базового варианта — это шум, а не эффект. И ничего не было прогрето: контейнер с PREBOOT=true в простое держит ноль браузеров, ровно как и контейнер без этого флага. Ещё два сигнала, но не цифры:
/configвообще не содержит ключаpreboot. Там естьconcurrent,queued,timeout,token,maxCPU,maxMemory,retriesи т. д.- Нет ошибки. Нет предупреждения. В логах контейнера — тоже ничего.
То есть конфигурация v1 с PREBOOT на v2 превращается в тихий no-op при обычном старте и проверке логов. Отсутствие ключа в /config плюс неизменившееся поведение — это и есть обнаруживаемый сигнал; Browserless не выдаёт явного отказа или предупреждения. При миграции нужно проверять, что конфигурация действительно применилась, а не считать зелёный старт доказательством того, что каждая переменная окружения сработала.
KEEP_ALIVE — обратный случай, и смешивать его с PREBOOT нельзя. В той же версии его тоже удалили, но он не молчит: точечная проверка контейнера показывает строку Environment variable of "KEEP_ALIVE" is deprecated and ignored. прямо в stdout. Это уже нормальное предупреждение для оператора. Я не прогонял KEEP_ALIVE через тот же измерительный стенд, что и PREBOOT, поэтому сообщаю о нём как о проверке, а не как об измерении. Но направление понятно и важно: тихий ловушкой является только PREBOOT. Browserless честнее сообщает о KEEP_ALIVE, чем это выглядело бы в упрощённой формулировке «v2 игнорирует все ваши флаги v1».
Плюсы и минусы
Плюсы
- Контроль доступа работает ровно так, как задокументировано, и меняется вместе с конфигурацией — это подтверждено на трёх разных потолках одновременно по статусам клиента и внутреннему учёту сервера.
/pressureв трёх коротких прогонах совпал с клиентски видимыми значениями running, queued и rejected; его можно рассматривать как один из входов для автоскейлинга и алертинга.- Реальный рендер Chromium без клиентского automation-кода: один аутентифицированный POST показал JS-инжектированный DOM, который статический fetch той же страницы не увидит.
- За 30 последовательных сессий не накопилось процессов Chrome; после прогона было 0 процессов Chrome и 0 zombie-процессов.
- Один тест
TIMEOUTвернул 408 на 5,007 секунды при бюджете 5,000 секунды; очистка и освобождение слота отдельно не подтверждались. - Аутентификация включена по умолчанию: все четыре REST-эндпоинта без токена возвращают 401.
- Один
docker run— и готовый сервис примерно за 0,78 с; первый рендер после этого — ещё через 0,32 с.
Минусы
- Образ 4,34 ГБ. Это честная цена входа, и она заметна в registry, в CI-кэше и во времени холодного развёртывания.
- SSPL-1.0 или коммерческая лицензия Browserless. Нужно проверять конкретные условия применительно к твоей модели поставки и распространения.
PREBOOTиз v1 на v2 принимается и молча игнорируется — без ошибки, без предупреждения, без ключа в/config.- Ты разворачиваешь сервис, а не просто подключаешь зависимость: контейнер, токен, сетевой путь, потолок доступности и ответственность за обновления.
- Запросы в очереди увеличивали end-to-end задержку примерно до двух длительностей сессии в прогоне
(2, 2); отдельное время ожидания в очереди не измерялось. - Измеренное REST-время включает HTTP-обмен и не выделяет стоимость запуска браузера и не доказывает повторное использование браузера.
Кому это подойдёт, а кому нет
Browserless оправдывает себя, когда браузер нужен не одному компоненту. Общий сервис рендеринга для нескольких приложений, команда, которой нужны скриншоты и PDF через HTTP-эндпоинт вместо зависимости на Chrome в каждом сервисе, пайплайн задач, которому нужен измеряемый потолок и backpressure — вот формат, под который это сделано. Если у тебя уже есть Docker и есть тот, кто отвечает за развёртывание, картина ясна: предсказуемый admission, наблюдаемый backpressure и отсутствие накопления процессов Chrome или zombie-процессов в проверке на 30 сессий.
Это также разумный выбор, если альтернатива — чтобы каждый сервис в стеке ставил себе собственный Chromium. Централизация этого в одном контейнере с токеном и потолком — действительно хороший архитектурный компромисс.
Не стоит брать его, если ты пишешь один скрипт. Тянуть 4,3 ГБ и поднимать контейнер ради одного Python-файла, которому нужно получить отрендеренную страницу, — это слишком много церемоний для маленькой задачи; библиотека браузера в твоём процессе делает то же самое без отдельного сервиса. Не стоит брать его, если условия SSPL не подходят твоему коммерческому продукту и ты не можешь это урегулировать. Не стоит брать его, если тебе нужен браузер, который приходит уже прогретым и без холодного старта: PREBOOT в v2 этого не даст. И не стоит брать его, если твоя настоящая задача — борьба с антиботом, потому что это относится к эндпоинту, который я сознательно не тестировал и за который не ручаюсь.
Альтернативы, и где здесь место Thunderbit
Сравнивать Browserless стоит не с другим контейнером, а с тем, где живёт браузер и кто отвечает за его постоянную работу.
Похожий обзор: обзор Browsertrix Crawler.
Похожий обзор: обзор chromedp.
| Браузерная библиотека (chromedp, rod, Selenium, Playwright) | Browserless self-hosted | Управляемое извлечение Thunderbit | |
|---|---|---|---|
| Где работает браузер | В твоём процессе | В твоём контейнере | На чужой инфраструктуре |
| Стоимость старта | Установка пакета | Образ 4,3 ГБ + контейнер + токен | API-ключ |
| Тайминг, измеренный здесь | В этой статье не измерялся | Первый рендер через 0,32 с после HTTP-ready; последующие вызовы — медиана 0,15 с | В этой статье не измерялся |
| Что ты пишешь | Automation-код с явными ожиданиями | Один аутентифицированный POST | Один HTTP-вызов |
| Что возвращается | То, что ты сам запрограммировал | HTML, PNG/PDF по сигнатурам, извлечённые узлы | Структурированный JSON или Markdown под конкретный продукт |
| Лимит мощности | Твой компьютер | CONCURRENT + QUEUED, затем 429 | План провайдера |
| Кто дежурит | Ты | Ты | Они |
Если тебе нужен браузер внутри собственного процесса и тебя не пугает писать ожидания, библиотека легче и без отдельного развёртывания. Эту сторону я разобрал в сравнении Playwright и Puppeteer и в более широком обзоре open-source-проектов для веб-скрейпинга.
Если же ты не хочешь вообще обслуживать браузер, наш Thunderbit — это один из управляемых вариантов. Browserless возвращает отрендеренный материал, который интерпретирует твой код; Thunderbit может возвращать Markdown или данные, совпадающие со схемой, а инфраструктуру рендеринга берёт на себя провайдер. В этой статье не измерялись задержка Thunderbit, пропускная способность, поведение при сбоях, качество извлечения или стоимость, поэтому таблица описывает границы ответственности, а не сравнение производительности.
Ещё одно чтение из той же серии тестов: обзор Crawl4AI описывает браузерный Markdown-пайплайн, который ты запускаешь сам, а обзор инструментов для веб-скрейпинга показывает более широкую картину категории.
Попробовать Thunderbit для извлечения веб-данных
Итог
Стоит ли запускать Browserless? Да — если браузерная работа нужна нескольким потребителям, кто-то может обслуживать контейнер, а проверка лицензии одобряет такую модель развёртывания. В трёх синтетических прогонах admission число принятых запросов совпадало с CONCURRENT + QUEUED, лишние получали 429, а /pressure совпадал с тем, что видел клиент. В отдельной проверке на 30 последовательных сессиях не накопилось ни процессов Chrome, ни zombie-процессов. Один тест на timeout вернул 408 рядом с заданной границей. Это полезные ограниченные наблюдения, но не универсальные гарантии.
Но и обязательства нужно оценивать честно. Это образ размером 4,34 ГБ и сервис, которым нужно управлять, а не просто зависимость; этот тест не доказал, что он быстрее in-process браузерной библиотеки. Его ценность в том, что браузер можно нормировать: известный потолок и измеряемый backpressure. В проверке на 30 сессий не наблюдалось накопления процессов Chrome или zombie-процессов. Цена — вес развёртывания и лицензия, которую нужно прочитать. Если ты рендеришь несколько страниц из одного скрипта, такой обмен не окупается. Если же ты строишь слой рендеринга, от которого зависят несколько сервисов, — тогда да; только проверь свои переменные окружения v1 при миграции, потому что PREBOOT будет выглядеть занятым, но ничего не делать.
Попробовать Thunderbit для извлечения веб-данных Get Started Free
Частые вопросы
Ускоряет ли Browserless headless Chrome?
Этот тест не позволяет так утверждать. HTTP-эндпоинт стал доступен через 0,78 с после docker run; первый вызов /content занял 0,32 с, а последующие вызовы в том же контейнере — около 0,15 с. Эти цифры включают HTTP-обмен, работу браузера, навигацию и передачу ответа. Стенд не выделял отдельно время запуска, не отслеживал повторное использование процессов и не публиковал сопоставимый in-process бенчмарк. Используй Browserless как сервис с общим контуром и контролем доступа, а затем измеряй именно свой путь задержки.
Что происходит при превышении лимита параллельности в Browserless?
Ты сразу получаешь HTTP 429. Потолок точно равен CONCURRENT + QUEUED, и я подтвердил это в трёх конфигурациях: (2,2) приняла 4 и отклонила 4, (3,5) приняла 8 и отклонила 4, (5,5) приняла 10 и отклонила 4. Эндпоинт /pressure на сервере каждый раз показывал согласованные значения running, queued и recentlyRejected. Важно помнить: запросы в очереди не падают, они ждут — при (2,2) и 5-секундной работе успешные ответы приходили от 5,7 до 11,0 секунды. Клиент должен трактовать 429 как backpressure и делать retry с backoff.
Работает ли PREBOOT в Browserless v2?
Нет. PREBOOT был удалён в 2.0.0, и v2 принимает -e PREBOOT=true без ошибки и предупреждения, но ничего с ним не делает. Я подтвердил это тремя способами: задержки не отличались от дефолтных, у простоявшего PREBOOT=true контейнера было 0 ожидающих процессов Chrome, а /config вообще не содержит ключа preboot. Если ты мигрировал конфигурацию v1, твои экземпляры не прогреты. Заметь, что KEEP_ALIVE, удалённый в той же версии, всё же пишет предупреждение "deprecated and ignored" — то есть проблема тихого отказа относится именно к PREBOOT.
Бесплатен ли Browserless для коммерческого использования? В репозитории доступны SSPL-1.0 или коммерческая лицензия Browserless, но эта статья не сопоставляет конкретные коммерческие или закрытые сценарии с тем или иным вариантом. Изучи текущие LICENSE и официальные рекомендации по развёртыванию, а затем пусть человек, ответственный за лицензирование ПО, оценит твою модель поставки и распространения.
Остаются ли за Browserless zombie-процессы Chrome?
В протестированном коротком окне — нет. После 30 последовательных сессий в контейнере было 0 процессов Chrome и 0 zombie-процессов; оставались только dumb-init, node, Xvfb, start.sh и sh. Детектор видел 11 процессов семейства chrome, пока сессия была активна, так что он не был «слепым». Память контейнера выросла с 294 MiB до 303 MiB и затем вышла на плато в выборке. Это не результат многчасовой, параллельной или тысячесессионной проверки на устойчивость.


