PostgreSQL ВИДАЛИТИ З помилки "Помилка: спроба видалити невидимий кортеж"


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 року, в якому обговорюється саме таке повідомлення про помилку, де це було виправлено ОП, але я не знаходжу пояснення того, як він це зробив або що може призвести до цієї помилки.

Я безпорадний через відсутність звернень до Google і через моє обмежене знання PostgreSQL.

Що призвело до корупції

У мене був сервер PostgreSQL 9.5.5 ( ~ 4TB, усі параметри за замовчуванням, за винятком збільшених лімітів пам'яті ), який працює на Debian 8, коли ядро ​​ОС панікувало - ймовірно, під час перебудови / dev / md1, де знаходився swap. До цього PostgreSQL з’їв майже весь дисковий простір з файлом журналу на 400 ГБ. ОС ніколи не завантажувався знову, перевірка диска була в порядку, тому я завантажився з LiveCD і створив резервну копію кожного блокового пристрою на зображення, про всяк випадок. Я успішно відновив / каталог з / dev / md2, fsck показав чисту файлову систему, і я створив резервну копію папки PGDATA на зовнішній жорсткий диск.

Що я зробив для спроби відновлення

Після того, як я відформатував пристрої md та перевстановив ОС разом із свіжим postgresql-9.5, я зупинив сервер PostgreSQL, перемістив і порушив папку PGDATA користувачеві postgres і запустив сервер - все здавалося нормально, помилок не було.

Як тільки я почав pg_dumpall, він помер разом із

Error message from server: ERROR:  timestamp out of range

Я, природно, намагався видалити кривдні кортежі, лише в кінці кінців з тією ж 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") Він відтворюється і залишає основний відвал ~ 9 ГБ.

  • SELECT COUNT(*) from comments; дозволено VACUUM comments; виконати, той самий трюк не працює в інших таблицях.
  • SELECT COUNT(*) from photos;а VACUUM photos;тепер помирає ERROR: MultiXactId 302740528 has not been created yet -- apparent wraparound- цей переслідує кожну таблицю, де інші помилки більше не з’являються.

Думки

  • БД забито великою кількістю ( можливо, дублікатів ) записів із ON CONFLICTпунктом БД робив, 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 грудня 2016 р. ) Читаючи про неіснуючі MultiXactIds , я пам’ятав, що моя база даних на момент аварії не піддавалася операційному навантаженню, але вона обробляла VACUUMзапит вручну . Я взяв веб-сервери та сканери в автономному режимі після того, як зрозумів, що на дисках залишилось лише 3% місця. Я повинен був перевірити /var/logнаявність великих файлів, але я помилково звинувачував PostgreSQL і намагався VACUUM FULLлише знайти його перерваним через мало місця на пристрої. Тож я почав звичайний ВАКУУМ і залишив його.
  • ( 14 грудня 2016 р. ) Завантажено 9,5 гілки джерел PostgreSQL з Github, прокоментував блоки в heapam.c та multixact.c та склали його з надією, що він не викине ці помилки. Але сервер не запускався, оскільки його потрібно було налаштувати з тими ж прапорами, які використовувались в одному з APT. Налічувалося близько 47 прапорів, кожен з яких потребував залежності з не очевидною назвою, тому я відмовився від цієї ідеї.
  • ( 16 грудня 2016 р. ) Я знайшов спосіб позбутися кортежів з недійсними часовими позначками, обнуляючи відповідні сторінки. Я спершу встановив такі параметри в psql:

    \set FETCH_COUNT 1
    \pset pager off

    Я тоді роблю SELECT ctid, * FROM comments;. Таким чином, він випльовує ctidпоганий кортеж до вмирання запиту. Потім я переходжу до заповнення цієї сторінки нулями: dd if=/dev/zero of=/var/lib/postgresql/9.5/main/base/16385/16443 bs=8K seek=92803 count=1 conv=notruncАле кожна сторона, нульова таким чином, розбиває попередню сторінку, в результаті чого на сторінці 16442зараз є кортеж з недійсною міткою часу. Не впевнений, що я тут роблю неправильно.

  • ( 16 грудня 2016 р. ) Спроба pg_dump -Fc --table photos vw > photos.bakпризводить до помилки сегментації після написання 1,3 ГБ ( з, мабуть, 800 ГБ ). Ось журнал сервера:

    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

    Ось короткий стек:

    #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, збільшуючи зміщення та звуження навколо мертвих кортежів, і вона успішно копіювала дані на моїй локальній машині, за винятком кортежів ( сподіваюся, єдиних ), які я вручну пошкодив. Також слід почекати, якщо сервер перезапуститься. Однак у мене не вистачало місця на моєму RAID, і я створив простір таблиць slowdiskна 8TB HDD. Коли я намагаюся 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/Corrup . Хоча, схоже, трохи пізно. Я напевно підозрюю, що основна причина тут - проблеми з диском / перебудова RAID.
Крейг Рінгер

Чи зберігали ви копію каталогу даних до того, як ви зробили resetxlog тощо?
Крейг Рінгер

Не сам datadir, але я перемістив неочищені образи диска на те місце, де вони безпечніші. Вони прекрасні, тому що я відновив з них свій RAID.
Кай

1
@CraigRinger ви напишете відповідь на це? Ви, напевно, один з небагатьох користувачів, які відповідають у тезі Postgres і можуть сказати щось корисне у питанні. Здається, дуже мало можна зробити.
ypercubeᵀᴹ

4
Ви не збираєтесь знайти відповідь на це. Ервін може вам допомогти. Соромлячись цього, шукайте Девіда Феттера або AndrewSW / RhodiumToad на irc.freenode.net/#postgresql. Розкажіть нам (dba.se), що вони знаходять. У мене таке відчуття, що це буде платною консультаційною роботою, яка потребує повного доступу до вашої бази даних. developer.postgresql.org/~adunstan linkedin.com/in/davidfetter Я не маю приналежності ні до тих хлопців, ні до їхніх компаній. Але вони єдині, кому я особисто би довірився вийти з цього корчу.
Еван Керролл

Відповіді:


2

Ну, мені вдалося автоматизувати процес відновлення SELECTі INSERT INTO, пропускаючи діапазони і чекаючи, якщо сервер вийде з ладу. Я вперше зашифрував це в Node - він видобув непошкоджені дані commentsі продовжує працювати.

Вчора я вирішив спробувати Golang, і ось репо з Go-кодом: https://github.com/kaivi/pg_ripper Я скоро його оновлю, щоб він справді працював навколо поганих кортежів, а не просто здавався в цілому. діапазон, що містить один.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.