PostgreSQL ลบจากล้มเหลวด้วยข้อผิดพลาด: พยายามที่จะลบ tuple ที่มองไม่เห็น


25

ความผิดพลาด

กำลังพยายามลบสิ่งอันดับที่มีการประทับเวลาที่ไม่ถูกต้องด้วย

DELETE FROM comments WHERE date > '1 Jan 9999' OR date < '1 Jan 2000' OR date_found > '1 Jan 9999' OR date_found < '1 Jan 2000';

สิ้นสุดลงใน

ERROR:  attempted to delete invisible tuple

มีรายชื่อผู้รับจดหมายจากปี 2009 ที่พูดถึงข้อความแสดงข้อผิดพลาดเดียวกันที่ OP ได้แก้ไข แต่ฉันไม่พบคำอธิบายว่าเขาทำอย่างไรหรือสิ่งที่อาจนำไปสู่ข้อผิดพลาดนี้

ฉันหมดหนทางเนื่องจากขาดความนิยมใน Google และความรู้ จำกัด ของฉันเกี่ยวกับ PostgreSQL

สิ่งที่นำไปสู่การทุจริต

ฉันมีเซิร์ฟเวอร์ PostgreSQL 9.5.5 ( ข้อมูล ~ 4TB การตั้งค่าเริ่มต้นทั้งหมดยกเว้นการ จำกัด หน่วยความจำที่เพิ่มขึ้น ) ที่ทำงานบน Debian 8 เมื่อเคอร์เนลระบบปฏิบัติการตื่นตระหนก - อาจเกิดขึ้นในขณะที่สร้าง / dev / md1 ที่มีการแลกเปลี่ยน ก่อนหน้านั้น PostgreSQL กินพื้นที่ดิสก์เกือบทั้งหมดด้วยไฟล์บันทึก 400GB ระบบปฏิบัติการไม่เคยบู๊ตอีกครั้งการตรวจสอบดิสก์ก็โอเคดังนั้นฉันจึงบูตจาก LiveCD และสำรองข้อมูลอุปกรณ์บล็อกแต่ละภาพในกรณี ฉันได้สร้างใหม่ / ไดเรกทอรีจาก / dev / md2 เรียบร้อยแล้ว fsck แสดงให้เห็นว่าระบบไฟล์สะอาดและฉันได้สำรองโฟลเดอร์ PGDATA ไปยัง HDD ภายนอก

สิ่งที่ฉันทำเพื่อพยายามกู้คืน

หลังจากที่ฉันได้ฟอร์แมตอุปกรณ์ md และติดตั้งระบบปฏิบัติการใหม่พร้อม postgresql-9.5 ใหม่ฉันได้หยุดเซิร์ฟเวอร์ PostgreSQL ย้ายและส่งต่อไฟล์ PGDATA ไปยังผู้ใช้ postgres และเริ่มเซิร์ฟเวอร์ - ทุกอย่างดูดีไม่มีข้อผิดพลาด

ทันทีที่ฉันเริ่มpg_dumpallมันก็เสียชีวิตด้วย

Error message from server: ERROR:  timestamp out of range

ฉันพยายามลบ tuples ที่กระทำผิดโดยธรรมชาติเพียงเพื่อจบลงด้วยinvisible tupleข้อผิดพลาดเดิมซ้ำแล้วซ้ำอีก

สิ่งที่ฉันพยายาม

ก่อนอื่นแบบสอบถาม DELETE ล้มเหลวเนื่องจากหน้าเสียหายดังนั้นฉันจึงตั้งค่าการตั้งค่าต่อไปนี้:

zero_damaged_pages = on
ignore_system_indexes = on
enable_indexscan = off
enable_bitmapscan = off
enable_indexonlyscan = off

ตอนนี้ฉันสังเกตเห็นว่าเมื่อฉันเรียกใช้แบบสอบถามเดียวกันอีกครั้งเซิร์ฟเวอร์ศูนย์หน้าเดียวกันซ้ำแล้วซ้ำอีกไม่แน่ใจว่ามันหมายถึง:

invalid page in block 92800 of relation base/16385/16443; zeroing out page

ฉันได้ลองทำตามคำสั่งที่ไม่ได้กำหนด:

  • pg_resetxlog -D $PGDATA ทำงานได้โดยไม่มีข้อผิดพลาดหรือข้อความใด ๆ
  • ลบดัชนีทั้งหมดรวมถึงข้อ จำกัด pkey
  • CREATE TABLE aaa AS (SELECT * FROM comments);นำไปสู่Segmentation faultบน

    heap_deform_tuple (tuple=tuple@entry=0x7f0d1be29b08, tupleDesc=tupleDesc@entry=0x7f0d1a35abe0, values=values@entry=0x7ffd57a5beb0, isnull=isnull@entry=0x7ffd57a65af0 "\001\001") สามารถทำซ้ำได้และทิ้งการถ่ายโอนข้อมูลหลัก ~ 9GB

  • SELECT COUNT(*) from comments;อนุญาตVACUUM comments;ให้ทำจนเสร็จสิ้นเคล็ดลับเดียวกันไม่สามารถใช้กับตารางอื่นได้
  • SELECT COUNT(*) from photos;และVACUUM photos;ตอนนี้ตายด้วยERROR: MultiXactId 302740528 has not been created yet -- apparent wraparound- อันนี้หลอกหลอนทุกโต๊ะที่มีข้อผิดพลาดอื่น ๆ ไม่ปรากฏขึ้นอีกต่อไป

ความคิด

  • DB ได้รับการตอกด้วยจำนวนมาก ( อาจซ้ำกัน ) เขียนด้วยON CONFLICTข้อ DB กำลังทำVACUUMเมื่อเคอร์เนลตกใจเกิดขึ้นฉันเชื่อว่ามันเป็นสิ่งที่เหลือของมันที่ทำให้เกิดปัญหากับnonexistent MultiXactIdsและinvisible tuple
  • ข้อมูลถูกรวบรวมกับซอฟต์แวร์รวบรวมข้อมูลตลอดระยะเวลา 2 ปีและฉันก็โอเคกับการสูญเสียบางส่วน
  • ตอนนี้ฉันสำรองข้อมูลแล้ว
  • ไม่มีข้อ จำกัด ด้านความสัมพันธ์ระหว่างตารางหรือทริกเกอร์ใด ๆ

นี่คือเอาต์พุต pg_controldata ณ ตอนนี้:

pg_control version number:            942
Catalog version number:               201510051
Database system identifier:           6330224129664261958
Database cluster state:               in production
pg_control last modified:             Thu 08 Dec 2016 01:06:22 AM EET
Latest checkpoint location:           1562/8F9F8A8
Prior checkpoint location:            1562/8F7F460
Latest checkpoint's REDO location:    1562/8F9F8A8
Latest checkpoint's REDO WAL file:    000000010000156200000008
Latest checkpoint's TimeLineID:       1
Latest checkpoint's PrevTimeLineID:   1
Latest checkpoint's full_page_writes: on
Latest checkpoint's NextXID:          0/40781255
Latest checkpoint's NextOID:          67798231
Latest checkpoint's NextMultiXactId:  1
Latest checkpoint's NextMultiOffset:  0
Latest checkpoint's oldestXID:        615
Latest checkpoint's oldestXID's DB:   1
Latest checkpoint's oldestActiveXID:  0
Latest checkpoint's oldestMultiXid:   1
Latest checkpoint's oldestMulti's DB: 1
Latest checkpoint's oldestCommitTsXid:0
Latest checkpoint's newestCommitTsXid:0
Time of latest checkpoint:            Thu 08 Dec 2016 01:06:22 AM EET
Fake LSN counter for unlogged rels:   0/1
Minimum recovery ending location:     0/0
Min recovery ending loc's timeline:   0
Backup start location:                0/0
Backup end location:                  0/0
End-of-backup record required:        no
wal_level setting:                    minimal
wal_log_hints setting:                off
max_connections setting:              100
max_worker_processes setting:         8
max_prepared_xacts setting:           0
max_locks_per_xact setting:           64
track_commit_timestamp setting:       off
Maximum data alignment:               8
Database block size:                  8192
Blocks per segment of large relation: 131072
WAL block size:                       8192
Bytes per WAL segment:                16777216
Maximum length of identifiers:        64
Maximum columns in an index:          32
Maximum size of a TOAST chunk:        1996
Size of a large-object chunk:         2048
Date/time type storage:               64-bit integers
Float4 argument passing:              by value
Float8 argument passing:              by value
Data page checksum version:           0

อัพเดท

  • ( 9 ธันวาคม 2559 ) ในขณะที่อ่านเกี่ยวกับMultiXactIds ที่ไม่มีอยู่ฉันจำได้ว่าฐานข้อมูลของฉันไม่ได้ทำงานภายใต้ภาระงานในขณะที่เกิดการขัดข้อง แต่มันกำลังประมวลผลVACUUMคำขอด้วยตนเอง ฉันใช้เว็บเซิร์ฟเวอร์และซอฟต์แวร์รวบรวมข้อมูลออฟไลน์หลังจากฉันรู้ว่ามีพื้นที่เหลือเพียง 3% ในดิสก์ ฉันควรตรวจสอบ/var/logไฟล์ขนาดใหญ่แล้ว แต่ฉันตำหนิ PostgreSQL อย่างผิดพลาดและพยายามVACUUM FULLเพียงเพื่อจะพบว่ามีการยกเลิกเนื่องจากมีพื้นที่เหลือเพียงเล็กน้อยบนอุปกรณ์ ดังนั้นฉันจึงเริ่มสูญญากาศธรรมดาและทิ้งไว้ที่นั้น
  • ( 14 ธันวาคม 2559 ) ดาวน์โหลดสาขา PostgreSQL 9.5 สาขาจาก Github แสดงความคิดเห็นบล็อกในheapam.cและmultixact.cและรวบรวมด้วยหวังว่าจะไม่ทำให้เกิดข้อผิดพลาดเหล่านี้ แต่เซิร์ฟเวอร์จะไม่เริ่มทำงานเพราะต้องมีการกำหนดค่าด้วยค่าสถานะเดียวกันกับที่ใช้ในเซิร์ฟเวอร์ที่ฉันได้รับจาก APT มีธงอยู่ประมาณ 47 แห่งแต่ละแห่งต้องการชื่อที่ไม่ชัดเจนดังนั้นฉันจึงละทิ้งความคิดนั้น
  • ( 16 ธันวาคม 2559 ) ฉันได้พบวิธีที่จะกำจัดสิ่งอันดับด้วยการประทับเวลาที่ไม่ถูกต้องโดย zeroing out หน้าเว็บที่เกี่ยวข้อง ฉันตั้งค่าตัวเลือกต่อไปนี้เป็นครั้งแรกในpsql:

    \set FETCH_COUNT 1
    \pset pager off
    

    SELECT ctid, * FROM comments;จากนั้นผมก็ทำ ด้วยวิธีนี้มันจะแยกออกจากctidtuple ที่ไม่ดีก่อนที่เคียวรีจะตาย จากนั้นฉันก็เติมเต็มหน้านั้นด้วยเลขศูนย์: dd if=/dev/zero of=/var/lib/postgresql/9.5/main/base/16385/16443 bs=8K seek=92803 count=1 conv=notruncแต่แต่ละหน้า, zeroed out ด้วยวิธีนี้, แบ่งหน้าก่อนหน้า, ทำให้หน้า16442มี tuple ที่มีการประทับเวลาไม่ถูกต้อง. ไม่แน่ใจว่าฉันทำอะไรผิดที่นี่

  • ( 16 ธันวาคม 2559 ) การพยายามpg_dump -Fc --table photos vw > photos.bakส่งผลให้เกิดข้อผิดพลาดในการแบ่งกลุ่มหลังจากเขียน 1.3GB ( อาจเป็น 800GB ) นี่คือบันทึกของเซิร์ฟเวอร์:

    2016-12-16 18:48:05 EET [19337-2] LOG:  server process (PID 29088) was terminated by signal 11: Segmentation fault
    2016-12-16 18:48:05 EET [19337-3] DETAIL:  Failed process was running: COPY public.photos (id, owner_id, width, height, text, date, link, thumb, album_id, time_found, user_id, lat, long) TO stdout;
    2016-12-16 18:48:05 EET [19337-4] LOG:  terminating any other active server processes
    2016-12-16 18:48:05 EET [19342-2] WARNING:  terminating connection because of crash of another server process
    2016-12-16 18:48:05 EET [19342-3] 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.
    2016-12-16 18:48:05 EET [19342-4] HINT:  In a moment you should be able to reconnect to the database and repeat your command.
    2016-12-16 18:48:05 EET [19337-5] LOG:  all server processes terminated; reinitializing
    2016-12-16 18:48:06 EET [29135-1] LOG:  database system was interrupted; last known up at 2016-12-14 22:58:59 EET
    2016-12-16 18:48:07 EET [29135-2] LOG:  database system was not properly shut down; automatic recovery in progress
    2016-12-16 18:48:07 EET [29135-3] LOG:  invalid record length at 1562/A302F878
    2016-12-16 18:48:07 EET [29135-4] LOG:  redo is not required
    2016-12-16 18:48:07 EET [29135-5] LOG:  MultiXact member wraparound protections are now enabled
    2016-12-16 18:48:07 EET [19337-6] LOG:  database system is ready to accept connections
    2016-12-16 18:48:07 EET [29139-1] LOG:  autovacuum launcher started
    

    นี่คือ stacktrace สั้น ๆ :

    #0  pglz_decompress (source=source@entry=0x7fbfb6b99b13 "32;00/0ag4d/Jnz\027QI\003Jh3A.jpg", slen=<optimized out>,
        dest=dest@entry=0x7fbf74a0b044 "", rawsize=926905132)
    #1  0x00007fc1bf120c12 in toast_decompress_datum (attr=0x7fbfb6b99b0b)
    #2  0x00007fc1bf423c83 in text_to_cstring (t=0x7fbfb6b99b0b)
    

    ฉันไม่รู้ว่าจะแก้ไขอย่างไร

  • ( 29 ธันวาคม 2016 ) ฉันได้เขียนโปรแกรมอรรถประโยชน์ที่ทำSELECT * FROM tablename LIMIT 10000 OFFSET 0ขึ้นเพิ่มออฟเซ็ตและแคบลงรอบ tuples ที่ตายแล้วและมีการทำซ้ำข้อมูลบนเครื่องท้องถิ่นของฉันยกเว้น tuples ( ฉันหวังว่าสิ่งเดียว ) ฉันเสียหายด้วยตนเอง มันควรจะรอถ้าเซิร์ฟเวอร์รีสตาร์ท อย่างไรก็ตามฉันมีพื้นที่ว่างไม่เพียงพอบน RAID ของฉันและฉันได้สร้างพื้นที่ตารางslowdiskบน HDD ขนาด 8TB เมื่อฉันพยายามCREATE DATABASE vwslow WITH TABLESPACE slowdiskมันจะไม่ทำเช่นนั้นกับข้อผิดพลาด:

    2016-12-29 02:34:13 EET [29983-1] LOG:  request to flush past end of generated WAL; request 950412DE/114D59, currpos 1562/A3030C70
    2016-12-29 02:34:13 EET [29983-2] CONTEXT:  writing block 58368001 of relation base/16385/16473
    2016-12-29 02:34:13 EET [29983-3] ERROR:  xlog flush request 950412DE/114D59 is not satisfied --- flushed only to 1562/A3030C70
    2016-12-29 02:34:13 EET [29983-4] CONTEXT:  writing block 58368001 of relation base/16385/16473
    2016-12-29 02:34:13 EET [30005-44212] postgres@vw ERROR:  checkpoint request failed
    2016-12-29 02:34:13 EET [30005-44213] postgres@vw HINT:  Consult recent messages in the server log for details.
    2016-12-29 02:34:13 EET [30005-44214] postgres@vw STATEMENT:  CREATE DATABASE vwslow WITH TABLESPACE slowdisk;
    

    ด้วยตนเองCHECKPOINTทำให้เกิดข้อผิดพลาดเดียวกัน

    การรีสตาร์ทเซิร์ฟเวอร์ทำให้ข้อผิดพลาดของจุดตรวจสอบหายไปและให้ฉันเรียกใช้เครื่องมือของฉัน จะตอบคำถามของฉันและเผยแพร่รหัสหากใช้งานได้


อ่านนี้และดำเนินการกับมันก่อนที่จะพยายามที่จะทำอะไรก็ได้ที่: wiki.postgresql.org/wiki/Corruption แม้ว่ามันจะดูเหมือนว่าจะสายไปสักหน่อย ฉันสงสัยอย่างมากว่าปัญหาของดิสก์ / การสร้าง RAID ใหม่เป็นสาเหตุหลักที่นี่
Craig Ringer

คุณเก็บสำเนาของไดเรคทอรีข้อมูลไว้ก่อนที่จะรีเซ็ต resetxlog หรือไม่?
Craig Ringer

ไม่ใช่ datadir แต่ฉันได้ย้ายอิมเมจดิสก์ดิบนอกสถานที่ซึ่งปลอดภัยกว่า พวกมันใช้ได้เพราะฉันสร้าง RAID ของฉันขึ้นมาใหม่
Kai

1
@CraigRinger คุณจะเขียนคำตอบเกี่ยวกับเรื่องนี้หรือไม่? คุณอาจเป็นหนึ่งในผู้ใช้ไม่กี่คนที่ตอบแท็ก Postgres และอาจพูดบางอย่างที่มีประโยชน์ในเรื่องนี้ ดูเหมือนว่าน้อยมากที่สามารถทำได้
ypercubeᵀᴹ

4
คุณจะไม่พบคำตอบในอันนี้ เออร์วินอาจช่วยคุณได้ อายแล้วมองหา David Fetter หรือ AndrewSW / RhodiumToad บน irc.freenode.net/#postgresql บอกเรา (dba.se) สิ่งที่พวกเขาพบ ฉันมีความรู้สึกว่านี่จะเป็นงานให้คำปรึกษาที่มีค่าใช้จ่ายซึ่งจะต้องเข้าถึงฐานข้อมูลของคุณทั้งหมด developer.postgresql.org/~adunstan linkedin.com/in/davidfetter ฉันไม่มีส่วนเกี่ยวข้องกับบุคคลเหล่านี้หรือ บริษัท ของพวกเขา แต่พวกเขาเป็นเพียงคนเดียวที่ฉันเชื่อใจว่าจะได้รับจากอุปสรรค์นั้น
Evan Carroll

คำตอบ:


2

ฉันจัดการเพื่อทำให้กระบวนการกู้คืนเป็นอัตโนมัติSELECTและINSERT INTOข้ามช่วงและรอว่าเซิร์ฟเวอร์ขัดข้องหรือไม่ ฉันเขียนรหัสเป็นครั้งแรกในโหนด - มันฉีกข้อมูลที่ไม่เสียหายcommentsและยังคงดำเนินต่อไป

เมื่อวานนี้ฉันตัดสินใจลอง Golang และนี่คือ repo ที่มีรหัส Go: https://github.com/kaivi/pg_ripperฉันจะอัปเดตเร็ว ๆ นี้เพื่อให้ใช้งานได้จริงกับ tuples ที่ไม่ดีและไม่ยอมแพ้ทั้งหมด ช่วงที่มีหนึ่ง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.