د ناکامۍ وروسته د پوسټګریس ډیټابیس بیرته ترلاسه کولو زما لومړۍ تجربه (د ریلټون بیس / 4123007 بلاک 16490 کې ناسمه پاڼه)

زه غواړم تاسو سره د پوسټګریس ډیټابیس بشپړ فعالیت ته د بحالولو زما لومړۍ بریا تجربه شریکه کړم. زه یو نیم کال دمخه د Postgres DBMS سره آشنا شوم؛ له دې دمخه ما په ډیټابیس اداره کې هیڅ تجربه نه درلوده.

د ناکامۍ وروسته د پوسټګریس ډیټابیس بیرته ترلاسه کولو زما لومړۍ تجربه (د ریلټون بیس / 4123007 بلاک 16490 کې ناسمه پاڼه)

زه په یوه لوی IT شرکت کې د نیمه DevOps انجینر په توګه کار کوم. زموږ شرکت د لوړ بار خدماتو لپاره سافټویر رامینځته کوي ، او زه د فعالیت ، ساتنې او ګمارنې مسؤل یم. ما ته یو معیاري دنده راکړل شوه: په یو سرور کې د غوښتنلیک تازه کول. غوښتنلیک په جینګو کې لیکل شوی ، د تازه کولو پرمهال مهاجرتونه ترسره کیږي (د ډیټابیس جوړښت کې بدلونونه) ، او د دې پروسې دمخه موږ د معیاري pg_dump برنامې له لارې بشپړ ډیټابیس ډمپ اخلو ، یوازې په قضیه کې.

د ډمپ اخیستلو پر مهال یوه ناڅاپي تېروتنه رامنځته شوه (د پوسټګریس نسخه 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

تېروتنه "په بلاک کې ناسمه پاڼه" د فایل سیسټم په کچه د ستونزو په اړه خبرې کوي، کوم چې خورا خراب دی. په مختلفو فورمونو کې د دې کولو وړاندیز شوی بشپړ خلا د اختیار سره صفر_خراب شوي_پاڼې د دې ستونزې د حل لپاره. ښه، راځئ هڅه وکړو ...

د بیا رغونې لپاره چمتو کول

توجه! ډاډ ترلاسه کړئ چې د خپل ډیټابیس د بحالولو هرې هڅې دمخه د Postgres بیک اپ واخلئ. که تاسو مجازی ماشین لرئ، ډیټابیس بند کړئ او یو سنیپ شاټ واخلئ. که چیرې دا ممکنه نه وي چې یو سنیپ شاټ واخلئ، ډیټابیس ودروئ او د پوسټګریس لارښود (د وال فایلونو په شمول) خوندي ځای ته کاپي کړئ. زموږ په سوداګرۍ کې اصلي شی دا نه دی چې شیان خراب کړي. لوستل دا.

څرنګه چې ډیټابیس عموما زما لپاره کار کاوه، ما خپل ځان د منظم ډیټابیس ډمپ پورې محدود کړ، مګر د خراب شوي ډاټا سره جدول خارج کړ (اختیار -T، --exclude-table=Table په pg_dump کې).

سرور فزیکي و، د سنیپ شاټ اخیستل ناممکن وو. بیک اپ لرې شوی ، راځئ چې پرمخ لاړ شو.

د فایل سیسټم چک کول

مخکې له دې چې د ډیټابیس بیرته راګرځولو هڅه وکړو، موږ باید ډاډ ترلاسه کړو چې هرڅه پخپله د فایل سیسټم سره سم دي. او د غلطیو په صورت کې، دوی سم کړئ، ځکه چې که نه نو تاسو کولی شئ یوازې شیان خراب کړئ.

زما په قضیه کې، د ډیټابیس سره د فایل سیسټم نصب شوی و "/srv" او ډول یې ext4 وو.

د ډیټابیس بندول: systemctl stop [ایمیل خوندي شوی] او وګورئ چې د فایل سیسټم د هیچا لخوا نه کارول کیږي او د کمانډ په کارولو سره غیر نصب کیدی شي lsof:
lsof +D /srv

ما باید د ریډیس ډیټابیس هم ودروي، ځکه چې دا هم کارول کیږي "/srv". بیا مې بې ځایه کړه / srv (اومونټ).

د فایل سیسټم د کارونې په کارولو سره چک شوی e2fsck د سویچ سره -f (په زور سره چک کول حتی که د فایل سیسټم پاک په نښه شوی وي):

د ناکامۍ وروسته د پوسټګریس ډیټابیس بیرته ترلاسه کولو زما لومړۍ تجربه (د ریلټون بیس / 4123007 بلاک 16490 کې ناسمه پاڼه)

بیا، د اسانتیا په کارولو سره dumpe2fs (sudo dumpe2fs /dev/mapper/gu2—sys-srv | grep چک شوی) تاسو کولی شئ تصدیق کړئ چې چیک واقعیا ترسره شوی و:

د ناکامۍ وروسته د پوسټګریس ډیټابیس بیرته ترلاسه کولو زما لومړۍ تجربه (د ریلټون بیس / 4123007 بلاک 16490 کې ناسمه پاڼه)

e2fsck وايي چې د ext4 فایل سیسټم په کچه کومه ستونزه ونه موندل شوه، دا پدې مانا ده چې تاسو کولی شئ د ډیټابیس بیا رغولو هڅو ته دوام ورکړئ، یا بیرته راستانه شئ. خلا ډکه (البته، تاسو اړتیا لرئ د فایل سیسټم بیرته نصب کړئ او ډیټابیس پیل کړئ).

که تاسو فزیکي سرور لرئ، ډاډ ترلاسه کړئ چې د ډیسکونو حالت وګورئ (له لارې smartctl -a /dev/XXX) یا د RAID کنټرولر ترڅو ډاډ ترلاسه کړي چې ستونزه د هارډویر په کچه نه ده. زما په قضیه کې، RAID د "هارډویر" په توګه وګرځید، نو ما د محلي مدیر څخه وغوښتل چې د RAID وضعیت وګوري (سرور زما څخه څو سوه کیلومتره لرې و). هغه وویل چې هیڅ غلطی شتون نلري، پدې معنی چې موږ یقینا د بیا رغونې پیل کولی شو.

هڅه 1: صفر خراب شوي_پاڼې

موږ د psql له لارې ډیټابیس سره د یو حساب سره وصل کوو چې د سوپر کارونکي حقونه لري. موږ یو سوپر کاروونکي ته اړتیا لرو، ځکه چې ... اختیار صفر_خراب شوي_پاڼې یوازې هغه کولی شي بدلون ومومي. زما په قضیه کې دا پوسټګریس دی:

psql -h 127.0.0.1 -U postgres -s [د ډیټابیس_نوم]

غوراوي صفر_خراب شوي_پاڼې د لوستلو تېروتنې له پامه غورځولو لپاره اړین دي (د postgrespro ویب پاڼې څخه):

کله چې PostgreSQL د فاسد پاڼې سرلیک کشف کړي، دا عموما د یوې تېروتنې راپور ورکوي او اوسنی لیږد لغوه کوي. که zero_damaged_pages فعال شي، سیسټم د دې پرځای خبرداری ورکوي، په حافظه کې زیانمن شوي پاڼې صفر کوي، او پروسس ته دوام ورکوي. دا چلند ډاټا له منځه وړي، د بیلګې په توګه په خراب شوي پاڼه کې ټول قطارونه.

موږ اختیار فعالوو او هڅه کوو چې د میزونو بشپړ خلا ترسره کړو:

VACUUM FULL VERBOSE

د ناکامۍ وروسته د پوسټګریس ډیټابیس بیرته ترلاسه کولو زما لومړۍ تجربه (د ریلټون بیس / 4123007 بلاک 16490 کې ناسمه پاڼه)
له بده مرغه، بد بخت.

موږ د ورته غلطی سره مخ شو:

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 - په Poetgres کې د "اوږدو معلوماتو" ذخیره کولو میکانیزم که چیرې دا په یوه پاڼه کې مناسب نه وي (8kb په ډیفالټ کې).

2 هڅه: بیا لیست کول

د ګوګل څخه لومړۍ مشوره مرسته ونه کړه. د څو دقیقو لټون وروسته، ما دویمه لارښوونه وموندله - د جوړولو لپاره reindex خراب شوی میز ما دا مشوره په ډیری ځایونو کې لیدلې، مګر دا باور نه و هڅولی. راځئ چې بیا لیست وکړو:

reindex table ws_log_smevlog

د ناکامۍ وروسته د پوسټګریس ډیټابیس بیرته ترلاسه کولو زما لومړۍ تجربه (د ریلټون بیس / 4123007 بلاک 16490 کې ناسمه پاڼه)

reindex پرته له ستونزو بشپړ شوی.

په هرصورت، دا مرسته ونه کړه، ویکیوم ډک د ورته غلطی سره ټکر شوی. له هغه وخته چې زه د ناکامیو سره عادت شوی یم، ما په انټرنیټ کې د مشورې لپاره نوره کتنه پیل کړه او په زړه پورې توګه راغلم مقاله.

دریمه هڅه: انتخاب، محدودیت، بندول

پورته مقاله وړاندیز کړی چې د میز قطار په قطار کې وګورئ او د ستونزو ډاټا لرې کړئ. لومړی موږ اړتیا لرو چې ټولې کرښې وګورو:

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

زما په قضیه کې، میز شتون لري 1 628 991 کرښې! دا اړینه وه چې ښه پاملرنه وشي د معلوماتو ویشمګر دا د جلا بحث لپاره یوه موضوع ده. دا د شنبې ورځ وه، ما دا کمانډ په tmux کې واخیست او ویده شوم:

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

سهار ما پریکړه وکړه چې وګورم چې شیان څنګه روان دي. زما د حیرانتیا لپاره، ما وموندله چې د 20 ساعتونو وروسته، یوازې 2٪ ډاټا سکین شوي! زه نه غواړم 50 ورځې انتظار وکړم. بله بشپړه ناکامي.

خو ما تسلیم نه کړ. زه حیران وم چې ولې سکینګ دومره وخت واخیست. د اسنادو څخه (بیا په پوسټګریسپرو کې) ما وموندله:

OFFSET د قطارونو تولید پیل کولو دمخه د قطارونو ټاکل شوي شمیر پریښودو لپاره مشخص کوي.
که دواړه OFFSET او LIMIT مشخص شوي وي، سیسټم لومړی د OFFSET قطارونه پریږدي او بیا د LIMIT محدودیت لپاره د قطارونو شمیرل پیل کوي.

کله چې LIMIT وکاروئ، نو دا مهمه ده چې د ORDER BY فقره هم وکاروئ ترڅو د پایلو قطارونه په ځانګړي ترتیب کې بیرته راشي. که نه نو، د قطارونو غیر متوقع فرعي سیټونه به بیرته راستانه شي.

په ښکاره ډول، پورته حکم غلط و: لومړی، هیڅ نه و په غوښتنه د، پایله کیدای شي غلط وي. دوهم، پوسټګریس لومړی باید د آفسټ قطارونه سکین او پریږدي، او د زیاتوالي سره آفس تولیدات به نور هم کم شي.

4 هڅه: د متن بڼه کې ډمپ واخلئ

بیا زما ذهن ته یو په زړه پوری نظر راغی: د متن په شکل کې ډمپ واخلئ او وروستۍ ثبت شوې کرښه تحلیل کړئ.

مګر لومړی، راځئ چې د میز جوړښت ته یو نظر وکړو. ws_log_smevlog:

د ناکامۍ وروسته د پوسټګریس ډیټابیس بیرته ترلاسه کولو زما لومړۍ تجربه (د ریلټون بیس / 4123007 بلاک 16490 کې ناسمه پاڼه)

زموږ په قضیه کې موږ یو کالم لرو "ایډ"، کوم چې د قطار ځانګړی پیژندونکی (کاونټر) لري. پلان په دې ډول وو:

  1. موږ د متن په شکل کې ډمپ اخیستل پیل کوو (د sql کمانډونو په بڼه)
  2. په یو ټاکلي وخت کې، ډمپ به د یوې غلطۍ له امله مداخله وکړي، مګر د متن فایل به بیا هم په ډیسک کې خوندي شي
  3. موږ د متن فایل پای ته ګورو، په دې توګه موږ د وروستۍ کرښې پیژندونکی (id) پیدا کوو چې په بریالیتوب سره لرې شوی.

ما د متن په بڼه د ډمپ اخیستل پیل کړل:

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

ډمپ، لکه څنګه چې تمه کیده، د ورته غلطی سره مداخله شوې وه:

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

نور له لارې پټه ما د ډنډ پای ته وکتل (tail -5 ./my_dump.dump) وموندله چې ډمپ د id سره په لیکه کې مداخله شوې وه 186 525. "نو ستونزه د 186 526 ID سره په لیکه کې ده، دا مات شوی، او باید حذف شي!" - ما فکر وکړ. مګر، ډیټابیس ته یوه پوښتنه کول:
«د ws_log_smevlog څخه * انتخاب کړئ چیرې چې id=186529"دا معلومه شوه چې د دې کرښې سره هرڅه سم وو ... د شاخصونو سره قطارونه 186 - 530 هم پرته له کومې ستونزې کار کوي. بل "ښه نظر" ناکام شو. وروسته زه پوه شوم چې دا ولې پیښیږي: کله چې د میز څخه ډیټا حذف او بدلول ، دوی په فزیکي ډول نه حذف کیږي ، مګر د "مړ شوي ټوپلز" په توګه په نښه شوي ، بیا راځي. اوټوواکوم او دا کرښې د حذف شوي په توګه په نښه کوي او اجازه ورکوي چې دا کرښې بیا وکارول شي. د پوهیدو لپاره، که چیرې په جدول کې ډاټا بدل شي او آٹوواکوم فعال شي، نو دا په ترتیب سره نه ساتل کیږي.

5 هڅه: انتخاب کړئ، له کوم ځای څخه، چیرته id=

ناکامۍ موږ پیاوړي کوي. تاسو باید هیڅکله تسلیم نه شئ، تاسو اړتیا لرئ چې پای ته لاړ شئ او په ځان او خپلو وړتیاوو باور وکړئ. نو ما پریکړه وکړه چې یو بل انتخاب هڅه وکړم: یوازې په ډیټابیس کې ټول ریکارډونه یو له بل سره وګورئ. زما د میز د جوړښت په اړه پوهیدل (پورته وګورئ)، موږ د ID ساحه لرو کوم چې ځانګړی دی (لومړنۍ کیلي). موږ په جدول کې 1 قطارونه لرو او id په ترتیب سره دي، پدې معنی چې موږ کولی شو یوازې د دوی له لارې یو له بل سره لاړ شو:

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

که څوک نه پوهیږي، کمانډ په لاندې ډول کار کوي: دا د میز قطار په قطار کې سکین کوي ​​او stdout ته لیږي. / dev / null، مګر که د SELECT کمانډ ناکام شي ، نو بیا د خطا متن چاپ شوی (stderr کنسول ته لیږل کیږي) او یوه کرښه چې خطا پکې شامله ده چاپ کیږي (له مننه || ، پدې معنی چې انتخاب ستونزې درلودې (د قوماندې بیرته کوډ) 0 نه دی)).

زه خوشحاله وم، ما په ساحه کې شاخصونه جوړ کړل id:

د ناکامۍ وروسته د پوسټګریس ډیټابیس بیرته ترلاسه کولو زما لومړۍ تجربه (د ریلټون بیس / 4123007 بلاک 16490 کې ناسمه پاڼه)

دا پدې مانا ده چې د مطلوب ID سره د کرښې موندل باید ډیر وخت ونه نیسي. په تیوري کې دا باید کار وکړي. ښه، راځئ چې کمانډ دننه کړو ټیګس او راځئ چې بستر ته لاړ شو.

په سهار کې ما وموندله چې شاوخوا 90 ننوتل لیدل شوي، چې یوازې 000٪ دي. یوه غوره پایله کله چې د تیر میتود سره پرتله کیږي (5٪)! مګر ما نه غوښتل چې 2 ورځې انتظار وکړم ...

6 هڅه: انتخاب کړئ، له کوم ځای څخه id >= او id <

پیرودونکي یو غوره سرور درلود چې ډیټابیس ته وقف شوی: دوه ګونی پروسیسر Intel Xeon E5-2697 v2، زموږ په ځای کې تر 48 پورې تارونه وو! په سرور کې بار اوسط و؛ موږ پرته له کومې ستونزې شاوخوا 20 تارونه ډاونلوډ کولی شو. کافي رام هم شتون درلود: تر 384 ګیګابایټ پورې!

له همدې امله، امر باید موازي وي:

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

دلته دا ممکنه وه چې یو ښکلی او په زړه پوری سکریپټ ولیکئ، مګر ما د موازي کولو ترټولو ګړندۍ طریقه غوره کړه: په لاسي ډول د 0-1628991 سلسله د 100 ریکارډونو وقفو کې ویشئ او د فارم 000 کمانډونه په جلا توګه پرمخ وړئ:

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

مګر دا ټول نه دي. په تیوري کې، د ډیټابیس سره نښلول هم یو څه وخت او سیسټم سرچینې اخلي. د 1 سره نښلول خورا سمارټ نه و، تاسو به موافق یاست. له همدې امله، راځئ چې د یوې اړیکې پر ځای 628 قطارونه بیرته ترلاسه کړو. د پایلې په توګه، ټیم په دې بدل شو:

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

په tmux سیشن کې 16 وینډوز خلاص کړئ او کمانډونه پرمخ وړئ:

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

یوه ورځ وروسته ما لومړنۍ پایلې ترلاسه کړې! د مثال په توګه (د XXX او ZZZ ارزښتونه نور خوندي ندي):

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

دا پدې مانا ده چې درې کرښې یوه تېروتنه لري. د لومړۍ او دویمې ستونزې لرونکي ریکارډونو ids د 829 او 000 ترمنځ وو، د دریمې ids د 830 او 000 ترمنځ وو. بیا، موږ باید په ساده ډول د ستونزې لرونکي ریکارډونو دقیق ID ارزښت پیدا کړو. د دې کولو لپاره، موږ د 146 مرحلې سره د ستونزې لرونکي ریکارډونو سره زموږ رینج ته ګورو او 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

خوشحاله پای

موږ ستونزې لرونکې کرښې وموندلې. موږ د psql له لارې ډیټابیس ته ځو او د حذف کولو هڅه کوو:

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

زما د حیرانتیا لپاره، ننوتل پرته له کومې ستونزې حتی پرته له اختیار څخه حذف شوي صفر_خراب شوي_پاڼې.

بیا ما ډیټابیس سره وصل کړ، وکړل ویکیوم ډک (زه فکر کوم چې دا اړین نه و چې دا کار وکړي) او په پای کې ما په بریالیتوب سره د بیک اپ په کارولو سره لیرې کړ pg_dump. ډمپ پرته له کومې تېروتنې اخیستل شوی! ستونزه په داسې احمقانه توګه حل شوه. خوښۍ هیڅ حد نه پوهیده، د ډیرو ناکامیو وروسته موږ د حل لاره پیدا کړه!

اعترافونه او پایله

دا څنګه د ریښتیني پوسټګریس ډیټابیس بحالولو زما لومړۍ تجربه شوه. زه به دا تجربه د اوږدې مودې لپاره په یاد ولرم.

او په نهایت کې ، زه غواړم ووایم له پوسټګریس پرو څخه مننه چې په روسیه کې د اسنادو ژباړلو او د دې لپاره په بشپړ ډول وړیا آنلاین کورسونه، کوم چې د ستونزې د تحلیل په جریان کې ډیره مرسته کړې.

سرچینه: www.habr.com

Add a comment