TGViewer
Fedkin is thinking Fedkin is thinking @fedkin_thinking · 9.01K subscribers
Post #227 10K
Нагруженные счетчики на postgres

Недавно смотрел доклад и наткнулся на интересный хак

Есть классическая таблица со счетчиками


create table counters (
id int primary key,
cnt bigint
);


И обновлениями по id


update counters set cnt = cnt + 1 where id = ...


Если нагрузка небольшая или размазана по счетчикам с разными id, все будет ок. При этом если начнется массовый поток апдейтов на небольшой набор каунтеров, будут интересные спецэффекты:

• как известно, update физически не обновляет строку, а создает ее новую версию из-за MVCC

• autovacuum, который должен чистить "мертвые" версии строк, может этого не делать по куче причин

• и постгрес, чтобы сделать очередной update по id, начинает вычитывать кучу версий строк в поисках "живой" версии (похожая ситуация описывалась в этом посте)

Как следствие — серьезная деградация производительности



Решение 1 — не заставлять делать постгрес, что он не должен делать

Решение 2 — подсказать постгресу, какую именно версию строки нужно прочитать

Добавляем к счетчикам колонку last_updated — таймстемп последнего обновления


create table counters (
id int primary key,
cnt bigint,
last_updated timestamp
);

create index g1 on counters(id, last_updated);


Имея такое, мы можем попросить постгрес сделать апдейт по конкретному ctid (физическому местоположению строки), при этом внутренний селект будет выполняться быстро даже в случае серьезного блоата


update counters
set cnt = cnt + 1, last_updated = now()
where ctid = (
select ctid
from counters
where id = ...
order by last_updated desc
limit 1
);


Важный момент — если между селектом и апдейтом ctid "последней" версии строки поменялся (кто-то конкуретно обновил счетчик), то наш апдейт ничего не поменяет. Поэтому важно этот запрос обернуть в блокировку по id

Получается как-то так


select pg_advisory_lock(...)

update counters
set cnt = cnt + 1, last_updated = now()
where ctid = (
select ctid
from counters
where id = ...
order by last_updated desc
limit 1
);

select pg_advisory_unlock(...)


Это может помочь вам обезопасить базу, если вдруг у вас есть супер нагруженные счетчики и нет возможности съехать с постгреса

А вообще рекомендую посмотреть доклад полностью, помимо проблемы выше, там рассказано еще много чего интересного. Тайминг конкретно по кейсу выше - четвертая минута
YouTube Аномалии под нагрузкой в PostgreSQL 2.0 / Михаил Жилин Крупнейшая профессиональная конференция для разработчиков высоконагруженных систем Saint HighLoad++ 2026 Подробнее: https://clck.ru/3QZHTb Июнь, 2026. Санкт-Петербург, DESIGN DISTRICT DAA in SPB -------- VK (https://vk.com/vkteam) делает просвещение доступным:…
  • 👍 60
  • 🔥 19
  • 💅 1
More from @fedkin_thinking
  1. Sep 20, 2026С большинством людей все в порядке Представь, у тебя команда регулярно срывает сроки ревью…
  2. Sep 19, 2026Чему техлиду научиться у Tinder На днях стало интересно, как запускаются сервисы с "сетевы…
  3. Sep 13, 2026Почему рабочие встречи превращаются в балаган — Раскатываем эксп на 100%? — Я бы не раскат…
  4. Sep 12, 2026Перед автоматизацией выясни, существует ли процесс Нулевой шаг автоматизации абсолютно чег…
  5. Aug 31, 2026Полезно понимать, какие проблемы решает твой руководитель Повышение обычно происходит, ког…
  6. Aug 29, 2026Все заняты, а продукт не двигается — Миш, вижу у тебя десять задач по бэку, какой статус?…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →