Устройство
Буферный кеш - область разделяемой памяти размером shared_buffers,
нарезанная на слоты по 8 КБ (страница). PostgreSQL никогда не работает с
данными на диске напрямую: страница сначала поднимается в буфер, дальше
чтение и изменение идут в памяти. Все процессы видят один кеш - если
страницу поднял один бэкенд, остальные найдут её там же.
Clock-sweep вместо LRU
Когда нужен новый буфер, а все заняты, кого-то выселяют. Честный LRU дорого поддерживать под конкуренцией, поэтому используется приближённый clock-sweep:
- у каждого буфера есть счётчик
usage_count, растущий при обращении; - «стрелка» ходит по буферам по кругу;
- если
usage_count > 0- уменьшает его и идёт дальше; - если
usage_count = 0и буфер не «прибит» (pinned) - выселяет его.
Часто используемые страницы переживают много кругов, одноразовые быстро вылетают. Грязный буфер перед выселением записывается на диск.
Кто пишет грязные буферы
- bgwriter - заранее, фоном, чтобы бэкендам было куда селить страницы;
- checkpointer - все грязные буферы в контрольной точке (см. checkpoint);
- сам бэкенд - если нет свободных буферов; тормозит запрос, плохой признак.
Заглянуть в кеш
CREATE EXTENSION IF NOT EXISTS pg_buffercache;
SELECT count(*), count(*) FILTER (WHERE isdirty) AS dirty
FROM pg_buffercache
WHERE relfilenode = pg_relation_filenode('flights');pg_buffercache показывает каждый буфер; pg_buffercache_summary (PG16)
отдаёт дешёвый агрегат без построчного скана. Состояния обращения
разбирает buffer-states, а кольцо для больших сканов - buffer-ring.