Khibradaydii ugu horreysay ee soo kabashada xogta Postgres ka dib guuldarro (bog aan sax ahayn oo ku yaal block 4123007 ee saldhiga relatton/16490)

Waxaan jeclaan lahaa inaan kula wadaago waayo-aragnimadayda guusha ugu horreysay ee dib u soo celinta xogta Postgres si ay u shaqeyso buuxda. Waxaan bartay Postgres DBMS nus sano ka hor; ka hor wax khibrad ah uma lahayn maamulka xogta gabi ahaanba.

Khibradaydii ugu horreysay ee soo kabashada xogta Postgres ka dib guuldarro (bog aan sax ahayn oo ku yaal block 4123007 ee saldhiga relatton/16490)

Waxaan u shaqeeyaa sidii Injineer-DevOps oo ah shirkad weyn oo IT ah. Shirkadeena waxay soo saartaa software loogu talagalay adeegyada rarka badan, aniguna waxaan mas'uul ka ahay waxqabadka, dayactirka iyo geynta. Waxa la i siiyay hawl caadi ah: in aan cusboonaysiiyo arji hal server ah. Codsiga wuxuu ku qoran yahay Django, inta lagu guda jiro socdaalka cusboonaysiinta ayaa la sameeyaa (isbeddelka qaab dhismeedka xogta), iyo ka hor inta aan habkan waxaan ku qaadnaa kaydinta xogta buuxda iyada oo loo marayo barnaamijka caadiga ah ee pg_dump, haddii ay dhacdo.

Khalad lama filaan ah ayaa dhacay markii qashinka la qaadayay (nooca Postgres 9.5):

pg_dump: Oumping the contents of table “ws_log_smevlog” failed: PQgetResult() failed.
pg_dump: Error message from server: ERROR: invalid page in block 4123007 of relatton base/16490/21396989
pg_dump: The command was: COPY public.ws_log_smevlog [...]
pg_dunp: [parallel archtver] a worker process dled unexpectedly

baadi "bog aan sax ahayn oo ku jira" wuxuu ka hadlayaa dhibaatooyinka heerka nidaamka faylka, taas oo aad u xun. Golayaasha kala duwan ayaa lagu soo jeediyay in la sameeyo VACUUM BUUXA oo leh ikhtiyaar eber_bogag_dhaawacan si loo xaliyo dhibaatadan. Hagaag, aan isku dayno...

U diyaargarowga soo kabashada

DARIIQ! Hubi inaad qaadato kaydka Postgres ka hor isku day kasta oo lagu soo celinayo xogtaada. Haddii aad haysatid mishiin dalwad ah, jooji kaydka xogta oo sawir sawir qaade. Haddii aysan suurtagal ahayn in la qaado sawir-qaadasho, jooji kaydka xogta oo koobi waxa ku jira tusaha Postgres (oo ay ku jiraan wal faylalka) meel ammaan ah. Waxa ugu muhiimsan ee ganacsigeena maaha inaan wax ka sii xumaanno. Akhriso waxaa.

Maadaama xog-ururinta guud ahaan ay ii shaqeysay, waxaan ku koobay kaydka kaydinta xogta caadiga ah, laakiin waxa aan ka saaray miiska xogta dhaawacan (doorasho -T, --exclude-miiska=Miiska ee pg_dump).

Seerfarku waxa uu ahaa mid jireed, waxa ay ahayd mid aan suurtogal ahayn in sawir sawir laga qaado. Kaydka waa laga saaray, aan dhaqaaqno.

Hubinta nidaamka faylka

Ka hor inta aan la isku dayin in aan soo celinno xogta, waxaan u baahannahay inaan hubinno in wax walba ay ku habboon yihiin nidaamka faylka laftiisa. Haddii ay dhacdo khaladaad, sax, sababtoo ah haddii kale waxaad wax ka sii dari kartaa.

Xaaladeyda, nidaamka faylka ee xog-ururinta ayaa lagu rakibay "/srv" oo nooca ahaa ext4.

Joojinta xogta xogta: systemctl joogso [emailka waa la ilaaliyay] oo hubi in nidaamka faylka uusan qofna isticmaalin oo laga dajin karo amarka lsof:
lsof +D/srv

Waxaan sidoo kale ku qasbanaaday in aan joojiyo redis database, maadaama ay sidoo kale isticmaalaysay "/srv". Marka xigta waan ka dajiyay / srv (cusub).

Nidaamka faylka ayaa la hubiyay iyadoo la isticmaalayo utility e2fsck leh furaha -f (Ku qasbo hubinta xitaa haddii nidaamka faylka lagu calaamadeeyay nadiif):

Khibradaydii ugu horreysay ee soo kabashada xogta Postgres ka dib guuldarro (bog aan sax ahayn oo ku yaal block 4123007 ee saldhiga relatton/16490)

Marka xigta, adoo isticmaalaya utility dumpe2fs (sudo dumpe2fs /dev/mapper/gu2—sys-srv | grep la hubiyay) waxaad xaqiijin kartaa in jeegagu dhab ahaantii la sameeyay:

Khibradaydii ugu horreysay ee soo kabashada xogta Postgres ka dib guuldarro (bog aan sax ahayn oo ku yaal block 4123007 ee saldhiga relatton/16490)

e2fsck wuxuu sheegay in wax dhibaato ah aan laga helin heerka nidaamka faylka ext4, taas oo macnaheedu yahay inaad sii wadi karto inaad isku daydo inaad dib u soo celiso xogta, ama aad ku noqoto faakuum buuxa (dabcan, waxaad u baahan tahay inaad dib u soo celiso nidaamka faylka oo aad bilowdo kaydka xogta).

Haddii aad leedahay server jireed, hubi inaad hubiso heerka saxanka (via smartctl -a /dev/XXX) ama kontaroolaha RAID si loo hubiyo in dhibaatadu aanay ahayn heerka qalabka. Kiiskeyga, RAID waxay u noqotay "hardware", sidaas darteed waxaan ka codsaday maamulka maxalliga ah inay hubiyaan xaaladda RAID (serverku wuxuu ii jiray dhowr boqol oo kiilomitir). Waxa uu sheegay in aysan jirin wax qalad ah, taas oo macnaheedu yahay in aan dhab ahaantii bilaabi karno soo celinta.

Isku dayga 1: eber_bogag_damaged

Waxa aanu ku xidhnay kaydka xogta anagoo psql anna akoon leh xuquuqaha isticmaalaha Waxaan u baahanahay superuser, sababtoo ah... doorasho eber_bogag_dhaawacan isaga kaliya ayaa bedeli kara. Xaaladdayda waa postgres:

psql -h 127.0.0.1 -U postgres -s [database_name]

Ikhtiyaar eber_bogag_dhaawacan loo baahan yahay si loo iska indho tiro khaladaadka akhrinta (laga soo bilaabo degelka postgrespro):

Marka PostgreSQL ay ogaato madaxa bogga ee musuqmaasuqa ah, waxay caadi ahaan ka warbixisaa khalad oo joojiso wax kala iibsiga hadda. Haddii eber_damaged_boggu karti yeesho, nidaamku beddelkiisa wuxuu soo saaraa digniin, wuxuu meesha ka saarayaa bogga dhaawacan ee xusuusta, wuxuuna sii wadaa habaynta. Dabeecaddani waxay burburisaa xogta, kuwaas oo ah dhammaan safafka bogga dhaawacan.

Waxaan awood u siineynaa ikhtiyaarka oo aan isku daynay inaan sameyno faaruq buuxa ee miisaska:

VACUUM FULL VERBOSE

Khibradaydii ugu horreysay ee soo kabashada xogta Postgres ka dib guuldarro (bog aan sax ahayn oo ku yaal block 4123007 ee saldhiga relatton/16490)
Nasiib darro, nasiib xumo.

Waxaan la kulannay qalad la mid ah:

INFO: vacuuming "“public.ws_log_smevlog”
WARNING: invalid page in block 4123007 of relation base/16400/21396989; zeroing out page
ERROR: unexpected chunk number 573 (expected 565) for toast value 21648541 in pg_toast_106070

pg_toast - hab lagu kaydiyo "xogta dheer" ee Poetgres haddii aysan ku habboonayn hal bog (8kb by default).

Isku dayga 2: dib u eegis

Taladii ugu horreysay ee Google ma aysan caawin. Dhowr daqiiqo ka dib raadinta, waxaan helay tilmaanta labaad - si loo sameeyo reindex miiska dhaawacan. Meelo badan ayaan ku arkay taladan, laakiin kalsooni ma dhalin. Aan dib u habaynno:

reindex table ws_log_smevlog

Khibradaydii ugu horreysay ee soo kabashada xogta Postgres ka dib guuldarro (bog aan sax ahayn oo ku yaal block 4123007 ee saldhiga relatton/16490)

reindex la dhammeeyay dhib la'aan.

Si kastaba ha ahaatee, tani ma caawin, VACUUM BUUXA ku dhacay qalad la mid ah. Tan iyo markii aan la qabsaday guuldarrooyin, waxaan bilaabay inaan raadiyo talo dheeraad ah oo ku saabsan internetka oo aan la kulmay mid xiiso leh maqaal.

Isku dayga 3: DOORASHADA, LIMIT, OFFSET

Maqaalka sare wuxuu soo jeediyay in la eego safka miiska oo laga saaro xogta dhibaatada leh. Marka hore waxaan u baahanahay inaan eegno dhammaan sadarrada:

for ((i=0; i<"Number_of_rows_in_nodes"; i++ )); do psql -U "Username" "Database Name" -c "SELECT * FROM nodes LIMIT 1 offset $i" >/dev/null || echo $i; done

Xaaladdayda, miiska ayaa ku jira 1 628 991 khadadka! Waxay ahayd lagama maarmaan in si wanaagsan loo daryeelo qaybinta xogta, laakiin tani waa mawduuc loogu talagalay dood gooni ah. Waxay ahayd Sabtidii, waxaan ku orday amarkan anigoo ku jira tmux oo aan seexday:

for ((i=0; i<1628991; i++ )); do psql -U my_user -d my_database -c "SELECT * FROM ws_log_smevlog LIMIT 1 offset $i" >/dev/null || echo $i; done

Subaxdii waxaan go'aansaday inaan hubiyo sida ay wax u socdaan. Waxaa yaab igu noqotay, waxaan ogaaday in 20 saacadood ka dib, kaliya 2% xogta la sawiray! Ma rabin inaan sugo 50 maalmood. Fashil kale oo dhamaystiran.

Laakin maan quusan. Waxaan la yaabay sababta sawir-ururinta ay u qaadatay waqti dheer. Dukumeentiga (mar kale ku yaal postgrespro) waxaan ogaaday:

OFFSET waxay qeexaysaa in laga boodo tirada safafka ee la cayimay ka hor inta aan la bilaabin soo saarida safafka.
Haddii labada OFFSET iyo LIMIT la cayimo, nidaamku marka hore waxa uu ka boodaa safafka OFFSET ka dibna waxa uu bilaabaa in uu tiriyo safafka xaddidaadda LIMIT.

Markaad isticmaalayso LIMIT, waa muhiim inaad sidoo kale isticmaasho AMAR BY faqrad si safafka natiijada loogu soo celiyo nidaam gaar ah. Haddii kale, safaf hoose oo aan la saadaalin karin ayaa la soo celin doonaa.

Sida iska cad, amarka kore wuu qaldanaa: marka hore, ma jirin dalbo by, natiijadu waxay noqon kartaa khalad. Marka labaad, Postgres marka hore waxay ahayd inay iskaan iskaan oo ka boodo safafka OFFSET, iyo iyadoo sii kordheysa OFFSET wax soo saarka ayaa hoos u dhici lahaa xitaa intaa ka sii badan.

Isku dayga 4: ku shub qaab qoraal ah

Dabadeed waxaa maskaxdayda ku soo dhacay fikrad u muuqata mid cajiib ah: u qaado qaab qoraal ah oo falanqee xariiqii ugu dambeeyay ee la duubay.

Laakiin marka hore, aan eegno qaab-dhismeedka miiska. ws_log_smevlog:

Khibradaydii ugu horreysay ee soo kabashada xogta Postgres ka dib guuldarro (bog aan sax ahayn oo ku yaal block 4123007 ee saldhiga relatton/16490)

Xaaladeena waxaan leenahay tiir "Aqoonsi", kaas oo ka koobnaa aqoonsiga gaarka ah (counter) safka. Qorshuhu wuxuu ahaa sidan:

  1. Waxaan bilaabeynaa inaan ku shubno qaab qoraal ah (qaab amarrada sql)
  2. Waqti cayiman, qashin qubka waa la joojin doonaa cilad awgeed, laakiin faylka qoraalka ayaa wali lagu kaydin doonaa saxanka
  3. Waxaan eegnaa dhamaadka faylka qoraalka, si aan u helno aqoonsiga (id) xariiqii ugu dambeeyay ee si guul leh looga saaray

Waxaan bilaabay inaan ku shubo qaab qoraal ah:

pg_dump -U my_user -d my_database -F p -t ws_log_smevlog -f ./my_dump.dump

Qashin-qubka, sidii la filayey, waxa lagu hakiyey isla khaladkii:

pg_dump: Error message from server: ERROR: invalid page in block 4123007 of relatton base/16490/21396989

Intaa ka sii dheer daboolka Waxaan eegay dhamaadka qashinka (dabada -5 ./my_dump.dump) la ogaaday in qashin qubka uu ka go'ay laynka id 186 525. "Marka dhibaatadu waxay ku xiran tahay id 186 526, way jabtay, waxayna u baahan tahay in la tirtiro!" – Waxaan u maleeyay. Laakiin, samaynta su'aal ku saabsan xogta xogta:
«ka dooro * ws_log_smevlog halka id=186529"Waxay soo baxday in wax walba ay ku fiicnaayeen khadkan... Safafka leh index 186 - 530 ayaa sidoo kale u shaqeeyay dhibaato la'aan. "Fikrad kale oo cajiib ah" ayaa ku guuldareysatay. Ka dib waxaan fahmay sababta ay tani u dhacday: marka la tirtirayo oo laga beddelayo xogta miiska, jidh ahaan looma tirtiro, laakiin waxaa lagu calaamadiyay "tuples dhintay", ka dibna way yimaadaan. autovacuum oo u calaamadiya xadadkan kuwo la tirtiray oo u ogolaanaya in dib loo isticmaalo. Si loo fahmo, haddii xogta miiska ku taal ay isbedesho oo autovacuum la furo, markaa si isku xigta looma kaydiyo.

Isku dayga 5: XUL, KA, HALKEE id=

Guuldarrooyinka ayaa naga dhigaya kuwo xoog badan. Waa inaadan waligaa quusan, waxaad u baahan tahay inaad tagto dhamaadka oo aad rumayso naftaada iyo kartidaada. Markaa waxaan go'aansaday inaan isku dayo ikhtiyaar kale: kaliya mid mid u fiiri dhammaan diiwaanada ku jira keydka macluumaadka. Anigoo og qaab dhismeedka miiskayga (eeg xagga sare), waxaan haynaa goob id oo gaar ah (furaha aasaasiga ah). Waxaan miiska ku haynaa 1 saf iyo id waa ay kala horeeyaan, taas oo macnaheedu yahay in aan mid mid u mari karno:

for ((i=1; i<1628991; i=$((i+1)) )); do psql -U my_user -d my_database  -c "SELECT * FROM ws_log_smevlog where id=$i" >/dev/null || echo $i; done

Haddii qof uusan fahmin, amarku wuxuu u shaqeeyaa sida soo socota: wuxuu sawiraa safka miiska oo wuxuu u soo diraa stdout / dev / null, laakiin haddii amarka SELECT uu guuldareysto, markaa qoraalka qaladka waa la daabacaa (stderr waxaa loo diraa konsole) waxaana la daabacay xariiq ay ku jiraan qaladka (mahadsanid ||, taas oo macnaheedu yahay in xulashada ay haysato dhibaatooyin (koodka soo celinta amarka) ma aha 0)).

Nasiib ayaan lahaa, waxaan lahaa indexes garoonka dhexdiisa id:

Khibradaydii ugu horreysay ee soo kabashada xogta Postgres ka dib guuldarro (bog aan sax ahayn oo ku yaal block 4123007 ee saldhiga relatton/16490)

Tani waxay ka dhigan tahay in helista khad leh id la doonayo waa inaysan qaadan waqti badan. Aragti ahaan waa inay shaqeyso. Hagaag, aynu ku wadno amarka tmux oo aan seexanno.

Subaxdii waxaan ogaaday in ilaa 90 oo wax la galiyay la daawaday, taas oo ka badan 000%. Natiijo aad u fiican marka la barbar dhigo qaabkii hore (5%)! Laakiin ma aanan rabin inaan sugo 2 maalmood...

Isku dayga 6: XUL, FROM, HALKE id>= iyo id

Macmiilku wuxuu lahaa server aad u wanaagsan oo u heellan kaydka xogta: dual-processor Intel Xeon E5-2697 v2, waxaa jiray ilaa 48 dunood oo goobtayaga ah! Culayska server-ku wuxuu ahaa celcelis; waxaan soo dejisan karnaa ilaa 20 dun iyada oo aan wax dhibaato ah jirin. Waxa kale oo jiray RAM ku filan: ilaa 384 gigabytes!

Sidaa darteed, amarku wuxuu u baahday in la is barbar dhigo:

for ((i=1; i<1628991; i=$((i+1)) )); do psql -U my_user -d my_database  -c "SELECT * FROM ws_log_smevlog where id=$i" >/dev/null || echo $i; done

Halkan waxaa suurtagal ah in lagu qoro qoraal qurux badan oo xarrago leh, laakiin waxaan doortay habka isbarbardhigga ugu dhaqsaha badan: gacanta ayaa u kala qaybiyay 0-1628991 oo u dhexeeya 100 oo diiwaanno oo si gooni ah u maamula 000 amar oo foomka ah:

for ((i=N; i<M; i=$((i+1)) )); do psql -U my_user -d my_database  -c "SELECT * FROM ws_log_smevlog where id=$i" >/dev/null || echo $i; done

Laakiin intaas kuma koobna. Aragti ahaan, ku xidhidhiyaha xog-ururinta waxa kale oo ay qaadataa wakhti iyo ilo nidaam. Isku xirka 1 ma ahayn mid caqli badan, waad aqbali doontaa. Sidaa darteed, aynu soo saarno 628 saf halkii aad ka heli lahayd mid ka mid ah hal xidhidh. Natiijo ahaan, kooxdu waxay isu beddeshay sidan:

for ((i=N; i<M; i=$((i+1000)) )); do psql -U my_user -d my_database  -c "SELECT * FROM ws_log_smevlog where id>=$i and id<$((i+1000))" >/dev/null || echo $i; done

Fur 16 daaqadaha fadhiga tmux oo socodsii amarada:

1) for ((i=0; i<100000; i=$((i+1000)) )); do psql -U my_user -d my_database  -c "SELECT * FROM ws_log_smevlog where id>=$i and id<$((i+1000))" >/dev/null || echo $i; done
2) for ((i=100000; i<200000; i=$((i+1000)) )); do psql -U my_user -d my_database  -c "SELECT * FROM ws_log_smevlog where id>=$i and id<$((i+1000))" >/dev/null || echo $i; done
…
15) for ((i=1400000; i<1500000; i=$((i+1000)) )); do psql -U my_user -d my_database -c "SELECT * FROM ws_log_smevlog where id>=$i and id<$((i+1000))" >/dev/null || echo $i; done
16) for ((i=1500000; i<1628991; i=$((i+1000)) )); do psql -U my_user -d my_database  -c "SELECT * FROM ws_log_smevlog where id>=$i and id<$((i+1000))" >/dev/null || echo $i; done

Maalin ka dib waxaan helay natiijadii ugu horeysay! Magac ahaan (qiyamka XXX iyo ZZZ lama sii hayo):

ERROR:  missing chunk number 0 for toast value 37837571 in pg_toast_106070
829000
ERROR:  missing chunk number 0 for toast value XXX in pg_toast_106070
829000
ERROR:  missing chunk number 0 for toast value ZZZ in pg_toast_106070
146000

Taas macnaheedu waxa weeye in saddex sadar ay ku jiraan khalad. Dhibcaha koowaad iyo labaad waxay ahaayeen inta u dhaxaysa 829 iyo 000, ids-yada saddexaad waxay ahaayeen inta u dhaxaysa 830 iyo 000. Marka xigta, waxay ahayd inaan helno qiimaha saxda ah ee diiwaanada dhibaatada. Si tan loo sameeyo, waxaanu ku eegaynaa kala duwanaanshahayaga diiwaanada dhibaatada leh oo leh tallaabo 146 oo aan aqoonsanno id:

for ((i=829000; i<830000; i=$((i+1)) )); do psql -U my_user -d my_database -c "SELECT * FROM ws_log_smevlog where id=$i" >/dev/null || echo $i; done
829417
ERROR:  unexpected chunk number 2 (expected 0) for toast value 37837843 in pg_toast_106070
829449
for ((i=146000; i<147000; i=$((i+1)) )); do psql -U my_user -d my_database -c "SELECT * FROM ws_log_smevlog where id=$i" >/dev/null || echo $i; done
829417
ERROR:  unexpected chunk number ZZZ (expected 0) for toast value XXX in pg_toast_106070
146911

Dhamaad wacan

Waxaan helnay khadadka dhibaatada leh. Waxaan galeynaa xogta anagoo adeegsanayna psql oo isku day inaan tirtirno:

my_database=# delete from ws_log_smevlog where id=829417;
DELETE 1
my_database=# delete from ws_log_smevlog where id=829449;
DELETE 1
my_database=# delete from ws_log_smevlog where id=146911;
DELETE 1

Waxaa la yaab igu noqotay, gelitaanka waa la tirtiray iyada oo aan wax dhibaato ah la kulmin xitaa iyada oo aan ikhtiyaarka lahayn eber_bogag_dhaawacan.

Kadibna waxaan ku xidhay database-ka, sameeyey VACUUM BUUXA (Waxaan u maleynayaa inaysan muhiim ahayn in tan la sameeyo), ugu dambeyntiina waxaan si guul leh u saaray kaydka anigoo isticmaalaya pg_daad. Qashin-qubka ayaa la qaaday iyada oo aan wax khalad ahi dhicin! Dhibka waxa lagu xaliyay si doqonnimo ah. Farxaddu ma ay garan xadka, guul darrooyin badan ka dib waxaan ku guuleysanay inaan xal u helno!

Mahadnaq iyo Gabagabadii

Tani waa sida waayo-aragnimadayda koowaad ee soo celinta xogta dhabta ah ee Postgres ay noqotay. Waxaan xasuusan doonaa waayo-aragnimadan muddo dheer.

Ugu dambayntii, waxaan jeclaan lahaa inaan ku idhaahdo waad ku mahadsan tahay PostgresPro inaad u turjumatay dokumentiga Ruushka iyo koorsooyin online ah oo bilaash ah, taas oo wax badan ka caawisay intii lagu jiray falanqaynta dhibaatada.

Source: www.habr.com

Add a comment