Polling (периодический опрос)

10 октября 2026 · ~17 мин чтения

концепция сеть интеграция api асинхронность

Polling (периодический опрос)

Polling — способ следить за изменениями, при котором клиент сам через равные промежутки времени спрашивает сервер: «ну что, поменялось?». Сервер ничего не сообщает по своей инициативе, он только отвечает на вопросы. Вся нагрузка и вся задержка обнаружения лежат на стороне спрашивающего.

История

Опрос — ровно настолько же старая идея, насколько стара сама связь между двумя машинами. Как только появились два компьютера, соединённых каналом, возник вопрос: как один узнаёт, что у другого что-то произошло? Самый простой ответ — спрашивать.

Что это такое

Формально опрос — это модель взаимодействия, в которой инициатива всегда на клиенте. Клиент хранит у себя расписание («спросить в 12:00:00, 12:00:10, 12:00:20…»), а сервер хранит только текущее состояние. Сервер не знает, кто его слушает, и не обязан никого уведомлять.

Из этого единственного свойства вытекает почти всё остальное.

Задержка обнаружения равна интервалу опроса. Если спрашивать раз в десять минут, то в среднем вы узнаете об изменении через пять минут, а в худшем случае — через десять. Хочешь узнавать быстрее — спрашивай чаще. Другого рычага нет: частота опроса и есть точность обнаружения.

Нагрузка пропорциональна числу клиентов, а не числу событий. Один клиент раз в десять минут — это 144 запроса в сутки, ерунда. Тысяча клиентов с тем же интервалом — 144 тысячи запросов в сутки, и почти все они отвечают «ничего не изменилось». Сервер платит за каждый.

Сервер ничего не помнит. Ему не нужны открытые соединения, списки подписчиков, буферы недоставленного. Он живёт по принципу «спросили — ответил». Это делает опрос невероятно устойчивым: упал клиент, упал сервер, между ними порвалась сеть — при следующем тике всё просто продолжается. Нет состояния — нет проблемы с его восстановлением.

Пропуск события не фатален. При push-модели потерянное сообщение — это дыра, которую надо догонять. При опросе клиент каждый раз получает абсолютное состояние, а не дельту (приращение). Сравнил с прошлым — увидел расхождение. Догонять нечего: последний ответ и есть истина.

Отсюда и главные пары для сравнения.

Аналогии из жизни

Чайник на кухне. Ты поставил чайник и каждые полминуты подходишь проверить, закипел ли. Работает: чайник не обязан быть умным — ни свистка, ни датчика, ни связи с тобой. Ты знаешь только его текущее состояние, забыл посмотреть — посмотришь в следующий раз, ничего не потеряется. Где ломается: если ты ушёл в другую комнату и вернулся через двадцать минут, все эти двадцать минут вода кипела и выкипала, а ты об этом не знал. Ровно так же система, опрашивающая раз в час, узнаёт о ночном сбое только утром. И второе: если к одному чайнику по очереди подбегают десять человек, они мешают друг другу, хотя воды в чайнике от этого не прибавляется.

Диспетчер и водители. Диспетчер обзванивает машины: «где ты?» — и записывает ответ. Работает: в машинах не нужна телеметрия, диспетчер сам задаёт ритм, а если связь пропала — при следующем звонке картина восстановится целиком, не нужно догонять пропущенные координаты. Где ломается: при тысяче машин и звонке раз в десять секунд диспетчер занят только звонками — он не может делать ничего другого, и именно он, а не дорога, становится узким местом. Причём 999 из 1000 ответов будут «еду по тому же адресу», то есть почти вся работа — впустую. Это и есть главный аргумент против частого опроса: цена платится за каждый тик, а не за каждое изменение.

Тесто под полотенцем. Повар каждые пять минут приподнимает полотенце и смотрит, поднялось ли тесто. Работает: не нужен никакой прибор, всё видно глазами, и в любой момент известно точное состояние — «поднялось на треть». Где ломается: каждый подъём полотенца выпускает тепло, и слишком частое любопытство замедляет то самое, за чем ты наблюдаешь. У этого есть прямой аналог в технике: опрос тяжёлого эндпоинта, который сам ходит в базу или пересчитывает данные, заметно нагружает систему. Есть даже отдельное правило в мониторинге: проверка здоровья должна быть дешёвой и не трогать тяжёлые зависимости.

Как это работает

Разберём на примере, который легко представить: скрипт следит за настройками внешнего сервиса и должен сообщить, когда там что-то поменялось в интересном поле.

Шаг 1. Задать расписание. Клиент вычисляет момент следующего опроса: сейчас плюс интервал. Интервал выбирается из компромисса «скорость обнаружения против нагрузки». Десять минут, минута, тридцать секунд — универсального ответа нет, есть только требования задачи.

Шаг 2. Сделать запрос. Обычный запрос за текущим состоянием: GET /api/object?key=.... Ничего специального в нём нет — именно поэтому опрос работает везде, где работает HTTP.

Шаг 3. Снять слепок. Из ответа вырезаются только те поля, за которыми следим. Не весь JSON, а конкретные значения: адрес, статус, счётчик, дата изменения. Это важная деталь, о ней ниже.

Шаг 4. Сравнить с предыдущим слепком.

слепок_новый = {поле: значение из ответа}
если слепок_новый != слепок_старый:
    сообщить о различии
    слепок_старый = слепок_новый
# если равно — молча ждём следующего тика

Шаг 5. Заснуть до следующего тика. Не «подождать ровно десять минут от начала работы», а «десять минут от конца предыдущего запроса». Разница принципиальна: если запрос шёл две секунды, то при первом варианте расписание постепенно съезжает, а при медленном ответе тики могут наложиться друг на друга.

Шаг 6. Пережить сбой. Запрос не ответил, вернул 500, порвалось соединение. Правильное поведение: не считать это изменением, не сбрасывать слепок, не заканчивать работу. Записать в лог и продолжить по расписанию.

Три ошибки, которые встречаются чаще всего

Первая: считать ошибку сети изменением состояния и разослать тревогу «всё сломалось». Второе: включить в слепок поля, которые меняются сами по себе (время последнего обращения, счётчик запросов, случайный идентификатор запроса) — тогда сравнение срабатывает на каждом тике, и опрос превращается в генератор ложных срабатываний. Третье: опрашивать быстрее, чем разрешает провайдер, и получить блокировку по лимиту запросов.

Разберём тик подробнее, потому что именно здесь ломается большинство самодельных мониторов.

Сравнивать надо нормализованное значение, а не сырой ответ. Ответ сервера почти всегда содержит что-то изменчивое: идентификатор запроса, время генерации, порядок ключей в JSON. Если сравнивать целиком, монитор будет «срабатывать» каждый раз. Поэтому слепок делается вручную и узко: перечислите поля, которые действительно означают изменение. Правило простое — если поле меняется между двумя запросами подряд, когда ничего не происходило, оно в слепок не попадает.

Слепок должен жить в файле, а не в памяти. Монитор, который перезапустился и потерял предыдущее состояние, на первом же тике решит, что «всё изменилось». Поэтому слепок пишется на диск рядом с логами, и при старте читается обратно. Тот же файл полезен как история: видно, когда значение стало другим.

Интервал лучше выбирать с разбросом. Если сто клиентов запускаются одновременно по расписанию ровно в 12:00:00, они ударят по серверу одной волной. Добавка случайных секунд (jitter, «дрожание») размазывает волну и заодно делает поведение менее похожим на бота. Ровный ритм метронома — характерная сигнатура автоматизации.

Считайте стоимость тика. Один запрос раз в минуту кажется бесплатным, пока не посчитаешь: 1440 запросов в сутки на один монитор, 43 тысячи в месяц. Умножьте на число мониторов и на то, что каждый запрос может тянуть данные из базы. Отсюда практика: чем чаще опрос, тем дешевле должен быть эндпоинт. Идеальный вариант — отдельная «облегчённая» ручка, которая отдаёт только искомое поле.

Опрос не бесплатен даже когда «ничего не произошло»

В push-модели цена пропорциональна числу событий: нет событий — нет трафика. В опросе цена пропорциональна времени: платить приходится за тишину. Поэтому главный вопрос при выборе интервала звучит не «как часто мне нужно узнавать», а «сколько я готов платить за то, что ничего не происходит». Ответ на него обычно и задаёт интервал.

Где встречается в обычной жизни

Где встречается в IT и бизнесе

Кто пользуется

Альтернативы и конкуренты

Webhook (обратный вызов).
Плюсы: задержка — секунды, нагрузка пропорциональна событиям, а не времени; экономит запросы в тишине.
Минусы: нужен публично доступный адрес, обработчик должен отвечать быстро, придётся проверять подпись и разбираться с повторными доставками; если получатель лежит — событие надо где-то хранить и досылать.

Long polling (длинный опрос).
Плюсы: задержка после события — миллисекунды, число пустых запросов падает в разы, работает на обычном HTTP и обычно проходит через прокси.
Минусы: каждое ожидание держит соединение и в браузере, и на сервере; таймауты прокси надо подгонять, а сервер вынужден помнить ожидающих — состояние вернулось.

WebSocket.
Плюсы: настоящий двусторонний обмен, минимальная задержка, одно соединение вместо тысяч запросов.
Минусы: соединение с состоянием, нужны переподключение и контроль живости; часть прокси и корпоративных сетей его режет; тестировать и отлаживать сложнее.

Server-Sent Events (SSE).
Плюсы: односторонний поток от сервера, работающий поверх обычного HTTP, автоматическое переподключение из коробки, простой текстовый формат.
Минусы: только от сервера к клиенту, исторические ограничения на число соединений в браузере (в HTTP/1.1), а серверу всё равно нужно удерживать открытые соединения.

Брокер сообщений (Kafka, RabbitMQ, NATS, MQTT).
Плюсы: доставка с гарантиями, буферизация, развязка производителя и потребителя, горизонтальное масштабирование читателей.
Минусы: отдельная инфраструктура, которую надо эксплуатировать; избыточно для «проверить одно поле в чужом API».

Когда НЕ стоит использовать

Связанные понятия

Литература и источники

Где встретилось у меня

На этой неделе я разбирался с одной интеграцией: нужно было понять, поменялось ли конкретное поле в настройках внешнего сервиса — там, где я инициировал изменение через поддержку. Прямого вебхука у сервиса нет, API отдаёт только текущий конфиг, поэтому вопрос «поменялось или нет» сводился ровно к опросу: запрашивать конфиг по расписанию, вырезать из него интересующие поля, сравнивать со слепком.

Попутно всплыли все три типовые грабли. Первая: подозрение на кэширование — пришлось проверять, не отдаёт ли сервер устаревший ответ (смотрел заголовки кэширования, запрашивал с обходным параметром и без cookies). Вторая: соблазн сравнивать ответ целиком, хотя в нём есть изменчивые поля. Третья: выбор интервала — при опросе раз в десять минут и получасовом окне ожидания выяснилось, что проверять чаще смысла нет, а тишина в логах выглядит ровно как «всё хорошо», хотя означает лишь «ничего не поменялось».

Практическая привычка

Если делаете мониторинг сами, заведите два файла: слепок состояния и журнал тиков. Первый даёт корректное сравнение после перезапуска, второй — ответ на вопрос «а он вообще работал?». Без журнала молчащий монитор неотличим от сломанного.

Краткое резюме