Incidentu reaģēšana

PostgreSQL "invalid page in block": kā rīkoties datu bojājuma gadījumā

Vaicājums neizdodas ar "invalid page in block" un, iespējams, kontrolsummas brīdinājumu. PostgreSQL ir atradis bojātu lapu diskā. Tas, ko darīsiet nākamās stundas laikā, izšķirs, vai nezaudēsiet neko, vienas lapas rindas vai vairāk. Lūk, soļu secība, kurai sekojam mēs.

· 12 min lasīšanai · AG Data komanda

PostgreSQL kļūda "invalid page in block" nozīmē, ka serveris nolasīja lapu (pēc noklusējuma 8 kB) no datu faila un atklāja, ka tā ir bojāta: vai nu tās galvene nav derīga lapas galvene, vai, ja ieslēgtas datu kontrolsummas, kontrolsumma nesakrīt. Tas ir īsts datu bojājums, nevis vaicājuma problēma. Labā ziņa ir tā, ka bieži tas skar vienu objektu un dažreiz vienu lapu. Sliktā ziņa ir tā, ka steidzīgi labojumi to var padarīt neatgriezenisku.

Tipisks žurnāls ar ieslēgtām kontrolsummām:

WARNING:  page verification failed, calculated checksum 21574 but expected 2207
ERROR:  invalid page in block 48213 of relation "base/16384/16529"

Ziņojumi nāk no bufpage.c, kas pārbauda katru lapu nolasīšanas brīdī, un bufmgr.c, kas izraisa kļūdu. Pirms PostgreSQL 18 ceļš tiek izdrukāts bez pēdiņām. PostgreSQL 18 var arī ziņot par vairākām bojātām lapām uzreiz kā "N invalid pages among blocks X..Y of relation".

1. solis: nepadariet sliktāk

Bojājums gandrīz vienmēr nāk no slāņa zem PostgreSQL: bojāts disks, kontroliera vai RAID problēma, krātuves slānis, kas samelojis par pabeigtu ierakstu, slikta RAM vai kļūda kodolā vai failu sistēmā. Tas, kas ierakstīja bojāto lapu, var joprojām rakstīt. Tāpēc pirms jebkāda labojuma:

# pirms JEBKĀDA labošanas mēģinājuma: apturiet serveri un nokopējiet datu direktoriju
sudo systemctl stop postgresql
sudo rsync -a /var/lib/postgresql/18/main/ /backup/main-before-repair/
dmesg -T | grep -iE 'i/o error|ext4|xfs|nvme|ata' | tail -50

2. solis: noskaidrojiet, kas ir bojāts

Ceļš base/16384/16529 nozīmē datubāzes OID 16384, relācijas failu 16529 noklusējuma tabulvietā. Funkcija pg_filenode_relation to pārvērš atpakaļ nosaukumā:

-- 16384 ir datubāzes OID, 16529 relācijas filenode
SELECT datname FROM pg_database WHERE oid = 16384;

-- pieslēdzieties šai datubāzei, tad (0 = noklusējuma tabulvieta):
SELECT pg_filenode_relation(0, 16529) AS relation,
       c.relkind
FROM pg_class c
WHERE c.oid = pg_filenode_relation(0, 16529);

Atbilde nosaka visu turpmāko incidentu:

Pārbaudiet, vai kontrolsummas ir ieslēgtas un vai citas datubāzes jau nav skartas. Skats pg_stat_database kopš PostgreSQL 12 skaita kontrolsummu kļūmes:

SHOW data_checksums;

SELECT datname, checksum_failures, checksum_last_failure
FROM pg_stat_database
WHERE checksum_failures IS NOT NULL;

3. solis: izmēriet bojājumu

Viena bojāta lapa reti ir viena. Pirms risinājuma izvēles pārbaudiet, cik tālu tas sniedzas. Paplašinājums amcheck pārbauda tabulas (verify_heapam, PostgreSQL 14+) un B-tree indeksus (bt_index_check):

CREATE EXTENSION IF NOT EXISTS amcheck;

-- tabulas lapas (PostgreSQL 14+)
SELECT blkno, offnum, msg FROM verify_heapam('public.orders') LIMIT 20;

-- B-tree indeksa struktūra
SELECT bt_index_check('public.orders_pkey');

Visam klasterim pg_amcheck (arī 14+) paralēli palaiž tās pašas pārbaudes visās datubāzēs. Ja kontrolsummas ir ieslēgtas, pg_checksums --check noskenē katru korekti apturēta klastera failu un beidzas ar nenulles kodu, ja kāda kontrolsumma nesakrīt:

pg_amcheck --all --jobs=4 --heapallindexed --install-missing
# bezsaistē, viss klasteris, tikai ja kontrolsummas ir ieslēgtas:
pg_checksums --check -D /var/lib/postgresql/18/main --progress

Ja sākotnējais serveris ir aizdomīgs, palaidiet tās uz kopijas. Ilga skenēšana uz bojāta diska var to pabeigt pavisam.

4. solis: izvēlieties risinājumu

Bojāts indekss: pārbūvējiet to

Izdzēsiet un izveidojiet indeksu no jauna vai izpildiet REINDEX. Noslogotā sistēmā REINDEX ... CONCURRENTLY neliedz rakstīšanu; kā tas uzvedas un ko darīt, ja tas neizdodas pusceļā, skatiet mūsu ceļvedī par REINDEX CONCURRENTLY. Pēc tam vēlreiz palaidiet bt_index_check.

Bojāta tabula: atjaunojiet, ja varat

Ja jums ir bāzes rezerves kopija un WAL arhīvs, atjaunošana ir vienīgais veids, kā atgūt zaudētās rindas. Nav jāatritina visa produkcijas datubāze: atjaunojiet atsevišķā serverī uz brīdi tieši pirms bojājuma, tad nokopējiet atpakaļ skartās rindas vai visu tabulu. Mūsu ceļvedis par atjaunošanu uz laika punktu to izskaidro soli pa solim. Atcerieties, ka bojājums var būt pastāvējis kādu laiku, pirms vaicājums skāra lapu, tāpēc atjaunošanas punktu izvēlieties uzmanīgi un arī atjaunoto tabulu pārbaudiet ar amcheck.

Nav izmantojamas rezerves kopijas: glābiet, kas palicis

Kad nav no kā atjaunot, PostgreSQL ir divas izstrādātāju opcijas, lai tiktu garām bojātām lapām. Abas ir bīstamas, un dokumentācija to saka tieši:

Abām noklusējums ir off, un tām vajag superlietotāju vai atbilstošu SET privilēģiju. Glābšana parasti izskatās šādi, palaista uz kopijas vai servera, ko varat atļauties pazaudēt:

-- PĒDĒJAIS LĪDZEKLIS, ja iespējams, uz kopijas: rindas bojātajās lapās tiek zaudētas
BEGIN;
SET LOCAL zero_damaged_pages = on;
CREATE TABLE public.orders_salvaged AS SELECT * FROM public.orders;
COMMIT;

SELECT count(*) FROM public.orders_salvaged;   -- salīdziniet ar gaidīto

Tad salīdziniet skaitus un atslēgu diapazonus, noskaidrojiet, kuru rindu trūkst (no lietotnes žurnāliem, eksportiem vai citas sistēmas), pārbūvējiet indeksus un ierobežojumus un nomainiet tabulu pret izglābto. Nekad neatstājiet nevienu no šīm opcijām ieslēgtu servera konfigurācijā.

Bojātā klasterī vispirms nepalaidiet VACUUM FULL, pg_resetwal vai nejaušas "labošanas" komandas. Tās maina failus, kas ir jūsu vienīgais pierādījums un vienīgā datu kopija. Vispirms kopējiet, tad mēriet, tad labojiet.

5. solis: padariet nākamo incidentu mazāku

Galvenās atziņas

PostgreSQL Datu bojājumi Kontrolsummas Atjaunošana
Sadarbība ar mums

Datu bojājums produkcijas PostgreSQL?

Datu bojājumos nepareizs pirmais solis maksā visvairāk. Mēs palīdzam steidzami: novērtējam bojājumu, saglabājam pierādījumus, atjaunojam no rezerves kopijām vai izglābjam, ko var, un atrodam cēloni.

Sazināties Vairāk no emuāra