skaidrojumi · 6 min · 26.07.2026

Postgres LISTEN/NOTIFY: no 2900 līdz 60 000 ierakstiem sekundē ar paziņojumu buferēšanu

DBOS inženieris Peter Kraft 24. jūlijā publicēja mērījumus, kas izskaidro, kāpēc uzņēmuma Postgres straumēšanas slānis ilgi nespēja pārkāpt 2900 ierakstus sekundē. Datubāze tajā brīdī gandrīz neko nedarīja: procesors, atmiņa un diska operācijas palika brīvas. Pēc tam, kad komanda paziņojumus sāka krāt atmiņā un izsūtīt pa paketēm, tā pati datubāze izturēja 60 000 ierakstu sekundē ar 15 līdz 100 milisekunžu aizturi.

Skaitļi attiecas uz konkrētu slodzi. Tabulā katrs straumes gabals, piemēram, viens valodas modeļa žetons, ir jauna rinda. Lasītājam grūtākais ir zināt, kad pienāks nākamais gabals. Aptaujāšana šeit strādā slikti: ja intervāls liels, aizture kļūst par lielu interaktīvai sarunai, ja mazs, vienlaicīgie aptaujātāji noslogo datubāzi. Tāpēc DBOS lasītāji gaida LISTEN paziņojumu no rakstītāja.

Kāpēc NOTIFY sarindo visus commit izsaukumus

Postgres garantē, ka paziņojumi nonāk pie klausītājiem tādā secībā, kādā transakcijas tika apstiprinātas. Visi izejošie paziņojumi glabājas vienā globālā rindā, kuras kārtībai jāsakrīt ar commit kārtību. Ķeza ir tā, ka commit kārtība nav zināma, pirms commit ir pabeigts. Postgres to risina ar globālu ekskluzīvu slēdzeni: transakcija, kas satur NOTIFY, paņem slēdzeni commit sākumā un atlaiž to tikai pēc tam, kad saturs ir izmests uz diska ar fsync().

Sekas ir tiešas. Katrs ieraksts straumē satur NOTIFY, tāpēc katrs ieraksts gaida savu kārtu pie vienas slēdzenes. Grupu commit, kas parasti vairākas transakcijas apstiprina ar vienu fsync() izsaukumu, šeit nestrādā. Caurlaidspēja apstājas pie tā, cik ātri Postgres spēj apstiprināt vienu transakciju pēc otras. Tas arī izskaidro tukšos resursu grafikus: reāla darba nav, visi stāv rindā.

Recall.ai to pašu atrada pēc trim dīkstāvēm

Sanāksmju ierakstīšanas serviss Recall.ai 2025. gada 1. jūlijā aprakstīja to pašu slēdzeni no otras puses. No 19. līdz 22. martam uzņēmuma galvenā Postgres datubāze trīs reizes apstājās. Slodze un gaidošo sesiju skaits šāvās augšā, vaicājumu caurlaidspēja krita, bet procesors, disks un tīkls tukšojās. Pēc log_lock_waits ieslēgšanas žurnālos parādījās rindas par AccessExclusiveLock on object 0 of class 1262 of database 0, kuru gaidīja vairāki simti procesu.

Vaininieks bija viens API galapunkts, kas pēc bota konfigurācijas atjaunināšanas izsauca NOTIFY. Recall.ai inženieris Elliot Levin raksta, ka šīs loģikas pārcelšana uz lietojuma slāni aizņēma mazāk nekā dienu. Viņa secinājums raksta kopsavilkumā ir skarbs.

Nelietojiet LISTEN/NOTIFY, ja vēlaties, lai jūsu datubāze mērogojas uz daudziem rakstītājiem.

Ko DBOS izdarīja citādi

DBOS pieeja balstās uz vienu novērojumu: straumēs paziņojums pats par sevi nav patiesības avots. Tas lasītājam tikai pasaka, ka tabulā jāieskatās. Tāpēc paziņojumiem nav jābūt ne globāli sakārtotiem, ne pilnībā izturīgiem. Kraft apraksta, ka paziņojumus tagad krāj atmiņā un periodiski izsūta vienā pakešu transakcijā. Globālo slēdzeni paņem reizi bufera izsūtīšanā, nevis pie katra ieraksta. Paši ieraksti tabulā atkal var izmantot grupu commit.

Cena par to ir viena. Ja process avarē, kamēr paziņojumi vēl ir buferī, tie nekad neaizies. DBOS šo caurumu aizlāpa ar rezerves aptauju: lasītāji papildus gaidīšanai laiku pa laikam pārbauda tabulu tieši. Aptaujas biežums var būt zems, jo tas ir tikai rezerves ceļš, tāpēc uz veiktspēju tas neatsaucas.

Pie 60 000 ierakstiem sekundē Postgres procesors mērījumos bija noslogots pilnībā. Ar to jaunais rezultāts atšķiras no vecā: pie 2900 datubāze stāvēja rindā, tagad tā tiešām strādā. Testu kods ir publicēts GitHub.

Postgres 19 ielāps nav tas, par ko to tur

Recall.ai raksts šogad 8. maijā papildināts ar piezīmi, ka Postgres pamatnē problēma esot salabota. Piezīme norāda uz Joel Jacobson izstrādāto commit, ko 2026. gada 15. janvārī pievienoja Tom Lane. Tas commit ievieš koplietotu kanālu karti, kura ļauj rakstītājam precīzi zināt, kuri procesi klausās konkrētajā kanālā. Ja klausītājs gaida rindas sākumā, bet jaunais paziņojums to neinteresē, Postgres to vairs nemodina un tā vietā pavirza klausītāja rādītāju uz priekšu. Commit apraksts sola vairākkārtēju NOTIFY caurlaidspējas pieaugumu, kad klausītāju ir daudz un tie sadalīti pa dažādiem kanāliem.

Kraft norāda, ka commit brīža globālā slēdzene ar to nekur nepazūd. Tā ir cita problēma nekā tā, kuru risina jaunā kanālu karte. Postgres 19 beta iznāca 4. jūnijā un stabilā versija gaidāma septembrī. Kas strādā uz 18.x vai vecākas versijas, tam slēdzene paliek tāda pati, kāda tā bija Recall.ai žurnālos pērn martā.

Kur LISTEN/NOTIFY joprojām der

  • Kad paziņojums ir signāls, nevis dati. Postgres dokumentācija payload garumu ierobežo līdz 8000 baitiem, tāpēc lietderīgā informācija tāpat glabājas tabulā.
  • Kad NOTIFY ir savā īsajā transakcijā. Ja tas karājas lielā rakstīšanas transakcijā, globālā slēdzene tiek turēta visu tās commit laiku, ieskaitot diska izmešanu.
  • Kad rakstītāju ir tūkstoši un paziņojumus var buferēt ar retu rezerves aptauju kā drošības tīklu.

Ja piegādei jābūt stingri sakārtotai un bez zaudējumiem, slēdzene ir cena, kas jāmaksā. Tad izvēle ir starp lēnāku commit un atsevišķu rindu ārpus Postgres.

Recall.ai savu ieteikumu nav mainījis. Raksta kopsavilkumā joprojām stāv brīdinājums nelietot LISTEN/NOTIFY pie daudziem vienlaicīgiem rakstītājiem. DBOS mērījumi tam nerunā pretī: bez buferēšanas arī tie apstājās pie 2900 ierakstiem sekundē.

Avoti

komentārisaruna

Komentāri

Šim rakstam vēl nav komentāru. Esi pirmais, kurš dalās ar savu viedokli.

Pievieno komentāru

Tavs e-pasts netiks publicēts. Obligātie lauki atzīmēti.

vēl no skaidrojumisaistītie