Incidentu reaģēšana

PostgreSQL "terminated by signal 9: Killed": OOM killer un ko mainīt

Viens backend tiek nogalināts, visas pārējās sesijas tiek izmestas, un serveris atskaņo WAL. Kā pārliecināties, ka vainīgs ir Linux OOM killer, kāpēc viens vaicājums apstādina visu instanci un kuri iestatījumi to tiešām novērš.

· 14 min lasīšanai · AG Data komanda

PostgreSQL "terminated by signal 9: Killed" servera žurnālā gandrīz vienmēr nozīmē, ka Linux kodolam beidzās atmiņa un tā OOM killer izvēlējās kādu postgres procesu. PostgreSQL pats nenokrita; kaut kas ārpus tā nosūtīja SIGKILL. Šo incidentu sāpīgu padara tas, kas notiek pēc tam: viena miruša backend dēļ postmaster izmet visas pārējās sesijas un palaiž avārijas atjaunošanu.

Kā izskatās žurnāli

Servera pusē redzēsiet šādu secību. PostgreSQL 17 un vecākās versijās pirmajā rindā ir server process; PostgreSQL 18 tā vietā nosauc procesa tipu, piemēram, client backend (PID ...).

LOG:  server process (PID 48213) was terminated by signal 9: Killed
DETAIL:  Failed process was running: SELECT c.region, count(DISTINCT o.customer_id) ...
LOG:  terminating any other active server processes
LOG:  all server processes terminated; reinitializing
LOG:  database system was interrupted; last known up at ...
LOG:  database system was not properly shut down; automatic recovery in progress
LOG:  redo starts at ...
LOG:  database system is ready to accept connections

Rinda DETAIL: Failed process was running ir visa incidenta noderīgākā: tā parāda vaicājumu, kas izpildījās nogalinātajā procesā. Lietotnes katrā tajā brīdī atvērtajā sesijā redz citu ziņojumu:

FATAL:  terminating connection because of crash of another server process
DETAIL:  The postmaster has commanded this server process to roll back the current
         transaction and exit, because another server process exited abnormally and
         possibly corrupted shared memory.
HINT:  In a moment you should be able to reconnect to the database and repeat your command.

Nākamās sekundes vai minūtes jauni savienojumi tiek noraidīti ar FATAL: the database system is in recovery mode. Ja vēlaties detalizētāk izprast starta fāzi un "redo in progress" rindas, par to rakstījām rakstā PostgreSQL "Connection refused".

Kāpēc viens nogalināts vaicājums apstādina visu

PostgreSQL backend procesi koplieto atmiņu: shared_buffers, slēdzeņu tabulas, WAL buferus. Ar signālu 9 nogalinātam procesam nav iespējas atbrīvot slēdzenes vai pabeigt rakstīšanu šajā koplietotajā apgabalā, tāpēc postmaster tam vairs nevar uzticēties. Tas liek visiem pārējiem procesiem beigt darbu, no jauna inicializē koplietoto atmiņu un atskaņo WAL no pēdējā kontrolpunkta. Tā ir apzināta rīcība. Tā ir cena par to, lai neriskētu ar bojātiem datiem.

Vai serveris restartējas automātiski, nosaka restart_after_crash, kas pēc noklusējuma ir on. Dokumentācijā norādīts, ka to var būt lietderīgi izslēgt, ja PostgreSQL darbojas klasterprogrammatūras pārvaldībā, lai tālāko rīcību izlemtu HA rīks.

Ja OOM killer izvēlas pašu postmaster, automātiskas atjaunošanas nav: instance paliek izslēgta, līdz to palaiž no jauna. Tāpēc dokumentācija iesaka aizsargāt postmaster (skatīt zemāk).

1. solis: pierādiet, ka tas bija OOM killer

Signālu 9 var nosūtīt arī cilvēks ar kill -9, watchdog vai orķestrators. Pirms maināt iestatījumus, pārbaudiet kodola žurnālu:

# kas nosūtīja signālu 9? kodola žurnāls parāda, vai tas bija OOM killer
journalctl -k --since "2 hours ago" | grep -i -E "out of memory|oom"
dmesg -T | grep -i -E "killed process|oom"

# vai postgres darbojas cgroup ar atmiņas limitu (systemd, docker, k8s)?
systemctl show postgresql -p MemoryMax -p MemoryHigh
cat /sys/fs/cgroup/$(cut -d: -f3 /proc/$(pgrep -o postgres)/cgroup)/memory.max

# pašreizējais overcommit režīms un postmaster aizsardzība pret OOM
sysctl vm.overcommit_memory vm.overcommit_ratio
cat /proc/$(pgrep -o postgres)/oom_score_adj

PostgreSQL dokumentācija kodola ziņojumu parāda kā Out of Memory: Killed process 12345 (postgres); precīzs formulējums atkarīgs no kodola versijas. Ja nogalināšana notika cgroup ietvaros (systemd MemoryMax, Docker vai Kubernetes atmiņas limits), kodola žurnālā būs minēta atmiņas cgroup. Tas maina risinājumu: hostā var būt daudz brīvas RAM, bet jūs atduraties pret konteinera limitu.

2. solis: atrodiet, kas izmantoja atmiņu

Kamēr aizdomīgā sesija vēl darbojas, superlietotājs var izsaukt pg_log_backend_memory_contexts(pid) (PostgreSQL 14+). Tā ieraksta šī backend atmiņas kontekstus servera žurnālā, un var redzēt, kura izpildītāja daļa aug. Savas sesijas kontekstus var redzēt skatā pg_backend_memory_contexts.

3. solis: novērsiet, lai neatkārtotos

  1. Godīgi saplānojiet atmiņu. Saskaitiet shared_buffers, reālo vienlaicīgumu × operācijas vaicājumā × work_mem, uzturēšanas darbus, OS un visu pārējo hostā. Ja summa neietilpst, samaziniet work_mem globāli un palieliniet to tikai tām lomām vai sesijām, kurām tas vajadzīgs (SET work_mem atskaišu darbā).
  2. Samaziniet backend skaitu. Dokumentācija pati iesaka samazināt max_connections un tā vietā izmantot savienojumu pūlu. Transakciju pūls PostgreSQL priekšā ierobežo, cik backend pastāv vienlaikus; skatiet mūsu PgBouncer ceļvedi.
  3. Pārejiet uz stingru overcommit. Ar vm.overcommit_memory=2 kodols atsaka piešķīrumus virs commit limita, tāpēc PostgreSQL vienā vaicājumā saņem parastu ERROR: out of memory, nevis SIGKILL, kas atiestata visas sesijas. Dokumentācijā teikts, ka tas pilnībā nenovērš OOM killer, bet ievērojami samazina iespējamību. Uzmanieties ar limitu: saskaņā ar kodola dokumentāciju 2. režīmā commit limits ir swap plus vm.overcommit_ratio no fiziskās RAM, un šī attiecība pēc noklusējuma ir 50%. Lielā serverī ar mazu swap tas var būt daudz mazāk, nekā gaidāt, tāpēc iestatiet vm.overcommit_ratio (vai vm.overcommit_kbytes) apzināti un pārbaudiet zem slodzes, pirms uz to paļaujaties.
  4. Aizsargājiet postmaster. Dokumentētā pieeja ir palaist postmaster ar OOM score korekciju -1000 un ļaut bērnu procesiem atgriezties pie 0:
    # root lietotāja palaišanas skripts / systemd unit, pirms postgres starta
    echo -1000 > /proc/self/oom_score_adj
    export PG_OOM_ADJUST_FILE=/proc/self/oom_score_adj
    export PG_OOM_ADJUST_VALUE=0
    Tas neaptur backend nogalināšanu, bet uztur dzīvu uzraugošo procesu, tāpēc instance atjaunojas pati, nevis paliek izslēgta. Dažas distribūciju pakotnes to jau iestata savos systemd unit failos; pārbaudiet, pirms pievienojat.
  5. Labojiet konteinera limitu, ne tikai PostgreSQL. Ja tika sasniegts cgroup limits, vai nu palieliniet to, vai dimensionējiet shared_buffers un work_mem pēc limita, nevis pēc hosta RAM.
Unlogged tabulas tiek iztukšotas. Avārijas atjaunošana pēc signāla 9 PostgreSQL ir īsta avārija. Unlogged tabula pēc avārijas tiek automātiski iztukšota, tāpēc starpposma vai kešatmiņas dati unlogged tabulās pēc viena OOM kill ir zuduši.

Lielās datubāzēs tas sāp vairāk

Galvenās atziņas

PostgreSQL OOM Killer Atmiņa Problēmu novēršana
Sadarbība ar mums

PostgreSQL atkārtoti nogalina OOM killer?

Mēs pārskatām atmiņas iestatījumus, savienojumu skaitu un vaicājumus, kas izraisa nogalināšanu, un padarām instanci stabilu reālā produkcijas slodzē.

Sazināties Vairāk no emuāra