Коллеги всем привет, меня зовут Дмитрий Тыльный, я автор проекта gde‑benzin.ru
Народная карта наличия бензина на АЗС, где водители в реальном времени отмечают, на каких заправках сейчас есть топливо, где очередь, где скоро будет, а где уже все...Сразу скажу про спорный момент. На волне топливного дефицита появилось сразу несколько похожих карт, и в комментариях других статей уже считают, «кто у кого скопипастил». Мы с «гдебенз» запустились примерно в одно время, если я не путаю, зарегистрировал даже на день раньше домен, но к разработке приступил позже, по личным причинам). Читать далее
Коллеги, всем привет, меня зовут Дмитрий Тыльный, и я автор проекта: Где бензин
Народная карта наличия бензина на АЗС, где водители в реальном времени отмечают,
на каких заправках сейчас есть топливо, где очередь, где скоро будет, а где уже все...
Сразу скажу про спорный момент. На волне топливного дефицита появилось сразу несколько похожих карт, и в комментариях других статей уже считают, «кто у кого скопипастил».
Мы с «гдебенз» запустились примерно в одно время, если я не путаю, зарегистрировал даже на день раньше домен, но к разработке приступил позже, по личным причинам).
Оба проекта это вайбкодинг с Claude, поэтому визуально и по логике они неизбежно похожи...
В основе у всех одно и то же — карта, на ней заправки, несколько статусов. Утверждать, что кто‑то кого‑то намеренно копирует, я не буду — это некрасиво и, скорее всего, неправда.
Идея простая, время одно, инструмент один.
А вот на что действительно стоит обратить внимание: среди похожих карт появились сайты, которые распространяют вирусы, просят скачать приложение или ввести данные банковской карты. Думаю что тут будет лишним говорить, что это вирусы, скам, фейки и прочая лабуда.
Не буду мериться миллионами, покажу что вижу в своей админке на момент публикации

сейчас на сайте: 1 128 человек
уникальных за сегодня: 28 764
всего АЗС в базе: 27 558 (вся Россия)
АЗС со свежими данными прямо сейчас: 3 276
отметок за сегодня: 4 382, за трое суток: 12 847
добавили на экран: 18 642
Отметки за трое суток по статусам:
есть — 5 142
скоро будет — 3 287
очередь — 2 814
закончился — 1 604
Цифры скромнее, чем 1,8 млн за трое суток у соседей.
Но это ровно то, что я могу показать по факту...
Для нишевого сервиса, результат за три дня — огонь)
Стек намеренно простой и дешёвый в эксплуатации:
Бэкенд — FastAPI (async), PostgreSQL + PostGIS для геозапросов, Redis (кэш выдачи по видимой области, rate‑limit, pub/sub → WebSocket).
Фронт — статика + Яндекс Карты (JS API), mobile‑first, тёмная тема.
Работает прямо в браузере: без приложения, регистрации, разрешений.
Реалтайм — как только кто‑то ставит отметку, она через WebSocket прилетает всем открытым картам; плюс карта раз в минуту сама подтягивает свежие данные.
Всё живёт в Docker Compose, статику отдаёт системный nginx,
мониторинг — Prometheus + node‑exporter + cAdvisor + Grafana.
Моменты, которые оказались важнее, чем кажется:
Концепция «последний прав» ломается от одного тролля, который натыкает «нет бензина». Поэтому статус АЗС — это большинство среди отметок, где один человек (по анонимному идентификатору) = один голос, а при равенстве побеждает более свежая.
Идентификатор анонимный, client_id из localStorage, если его нет то хэш IP.
Натыкать десять отметок подряд смысла нет, от одного человека считается только последняя. И один человек свежей отметкой большинство не перебьет, если ситуация на заправке реально поменялась, отметки других водителей быстро перевесят и статус сам скорректируется.
Донат‑кластеры. При отдалении заправки схлопываются в кластер, и кластер закрашен кольцом по долям статусов: одна зелёная и одна красная рядом — кольцо ровно пополам. Рисуется как SVG‑иконка на лету, без сторонних библиотек кластеризации.
Только Россия, со всеми регионами. Точки берём из OpenStreetMap, но в выдаче нужна строго РФ. Границу собираем из OSM (osm2geojson + shapely) и режем по ней — включая Крым, Севастополь, ДНР, ЛНР, Херсонскую и Запорожскую области.
И вот на этой самой границе прод упал)
И пара решений под капотом, которые оказались неочевидными...
Инвалидация кэша одним INCR, а не удалением ключей.
Кэш выдачи по видимой области лежит в Redis, но ключ построен хитро в него зашита версия данных:
grid = round(south,2),round(west,2),round(north,2),round(east,2)
cache_key = f"bbox:{redis.get('stations:ver')}:{grid}"Когда прилетает новая отметка, не нужно чистить сотни bbox‑ключей в Redis, только одна операция INCR stations:ver. Версия сменилась → все старые ключи bbox:41
разом становятся недоступны и просто протухают по TTL сами. Новые запросы идут уже на bbox:42. Глобальная инвалидация всего кэша карты в один атомарный инкремент, без гонок. Плюс округление bbox до сотых долей градуса склеивает близкие вьюпорты в один ключ.
Статус заправки считается на чтении
Крон джоб, которые бы отключали заправки по таймеру, нет, при запросе обращаемся к
now() — last_report_at, если самый свежий отчёт старше окна таймаута (2 часа),
То просто отдается серый цвет заправки, без мутаций бд и блокировок при таком количестве.
Там же на чтении считается freshness_seconds, это сколько минут назад была отметка, expires_in_seconds это обратный отсчет до того как заправка снова станет серой,
и confirmations, сколько разных людей подтвердили статус.
Плюс разбивка по каждому топливу отдельно, 92й может быть, а 95го уже нет.
Rate‑limit и грабли на ровном месте
Спам отметками режется скользящим окном на Redis ZSET, при каждом запросе одним pipeline выкидываю из ZSET все что старше окна, добавляю текущий запрос, считаю ZCARD и сравниваю с лимитом. Четыре команды, атомарно, по IP.
pipe.zremrangebyscore(key, 0, now - window_sec)
pipe.zadd(key, {member: now})
pipe.zcard(key)
pipe.expire(key, window_sec)И тут я успел наступить на грабли, сначала уникальным членом ZSET был id(now).
А id у флоата в питоне это адрес объекта, который переиспользуется. Два запроса в одну микросекунду получали один member, один перезаписывал другой и счетчик занижался, лимитер пропускал больше чем должен. Заменил на now + token_hex и стало честно.
Реалтайм тонкими событиями, WebSocket часть нарочно тупая.
В приложении один Hub, одна фоновая задача слушает канал Redis pub/sub и рассылает сообщение всем подключенным сокетам, мертвые соединения выкидываются прямо при неудачной отправке. Само событие это просто {«type»: «station_update», «station_id»: N}, без данных. Клиент получив его сам решает интересна ли ему эта станция в текущем вьюпорте и дергает API, а тот уже отвечает из свежего кэша (версия то инкрементнулась). По сокетам летают байты, а не JSONы со статусами, и не надо думать у кого какой вьюпорт открыт.
Первую версию фильтра по границе я сделал «в лоб»: на каждый запрос выдачи по видимой области — ST_Contains(граница_РФ, точка_АЗС). На практике граница России — это мультиполигон на ~147 тысяч вершин, и PostGIS честно проверял вхождение каждой из 27 тысяч станций в этот монстр‑полигон на каждый скролл карты.
На пике трафика load average сервера ушёл под 47, а postgres ел ~415% CPU.
Посыпались таймауты и недогруз карты.
Чинил так:
Убрал ST_Contains из горячего пути. Граница нужна ровно один раз — при импорте, чтобы выкинуть заграничные АЗС. В рантайме проверять её незачем: в базе и так только Россия.
Добавил кэш выдачи по bbox в Redis с коротким TTL и мгновенной инвалидацией при новой отметке (через инкремент версии).
После этого postgres с 415% CPU вернулся к ~1%, и сайт перестал складываться под нагрузкой. Мораль банальная, но выстраданная руками: тяжёлую геометрию нельзя дёргать на каждый запрос — предрасчитывай и выноси из горячего пути.
По классике мониторинг: Grafana + cAdvisor
Отдельно повозился с тем, чтобы карту находили не только по прямой ссылке: сгенерировал лендинги по регионам, городам, сетям АЗС и маркам топлива.
Данные для лендингов уже есть в базе, так что по сути это выгрузка из PostgreSQL в HTML плюс sitemap. Пока это самый дешевый канал, страница типа «бензин в Воронеже» индексируется и приводит людей ровно в тот момент, когда им надо.
Карта верна и релевантна ровно настолько, насколько активны водители.
Там, где сегодня никто не отметился, заправка серая и ничего не придумывает.
Достоверное «есть бензин» карта показывает там, где только что был живой человек, поэтому в карточке видно, сколько минут назад пришла отметка и сколько ей ещё жить.
Это не замена звонку на АЗС, а способ не объехать три пустые заправки подряд, как это когда‑то сделал я — собственно, поэтому проект и появился.
Раз под видом карт бензина набежали мошенники, я сразу зашил в сервис принципы: ничего не скачивать, никакой регистрации, не собираем персональные данные, не просим оплату или данные карт. Геолокация включается только по кнопке и остаётся в браузере.
Плюс отдельный раздел с дисклеймером: сервис информационно‑справочный, статусы — субъективные сообщения пользователей, наличие всегда уточняйте на самой АЗС.
Хороший вопрос, но буду развивать проект, пока в нем есть необходимость и потребность.
Карта: https://gde‑benzin.ru
Буду благодарен за любую обратную связь!
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | ГдеЗаправка: умный подбор + как нас за сутки посетило полмиллиона | 5 | 7 | 30-06-2026 |
| 2 | В России заработал сервис «ГдеБЕНЗ» для мониторинга ситуации на заправках | 0 | 5 | 30-06-2026 |
| 3 | В Карелии появилась карта АЗС, показывающая наличие бензина | 0 | 5 | 29-06-2026 |
| 4 | Как я навайбкодил каталог бесплатных парковок Петербурга и России | 5 | 7 | 07-07-2026 |
| 5 | «Яндекс» запустил карту с наличием топлива на АЗС | 0 | 7 | 08-07-2026 |
| 6 | Бензин есть! Омичи могут проверить наличие топлива на АЗС по интерактивной карте | 5 | 7 | 07-07-2026 |
| 7 | Слезаем с нефтяной иглы. В стране, которую не так давно называли «страной-бензоколонкой», кончается бензин. Что творится на заправках и как россияне реагируют на кризис от Белгорода до Владивостока | -3 | 7 | 27-06-2026 |
| 8 | Минэнерго: Информация на сервисах о наличии топлива может быть недостоверной | -1 | 3 | 01-07-2026 |
| 9 | Бензиновый коллапс: почему в России возник дефицит топлива | 0 | 7 | 26-06-2026 |
| 10 | Житель Краснодара приехал на АЗС: литр за 99, а через ... | 0 | 6 | 27-06-2026 |