Puncte:2

Cum se depanează eroarea de segmentare PostgreSQL?

drapel ng

Am o instanță PostgreSQL 13 care se prăbușește în continuare:

LOG: Procesul serverului (PID 10722) a fost încheiat de semnalul 11: Eroare de segmentare
DETALII: Rula un proces eșuat: COMMIT
Jurnal: terminarea oricăror alte procese de server active
AVERTISMENT: terminarea conexiunii din cauza blocării unui alt proces de server
DETALII: Postmasterul a comandat acestui proces de server să anuleze tranzacția curentă și să iasă, deoarece un alt proces de server a ieșit în mod anormal și posibil a deteriorat memoria partajată.

Am actualizat /etc/postgresql/13/main/pg_ctl.conf pentru a include haldele de miez

pg_ctl_options = '--core-files'

și repornit postgresql serviciu. Acum se pare că permite depozitele de miez:

$ pentru f în `pgrep postgres`; face cat /proc/$f/limits | miez grep; Terminat
Dimensiunea maximă a fișierului de bază, octeți nelimitați nelimitați 

gdb backtrace oferă următoarele rezultate

$ gdb /usr/lib/postgresql/13/bin/postgres 13/main/core.postgres.12264

Program terminat cu semnal SIGSEGV, Eroare de segmentare.
#0 slot_deform_heap_tuple (natts=5, offp=0x557cc2e60720, tuple=<optimized out>, slot=0x557cc2e606d8) la ./build/../src/backend/executor/execTuples.c:930
930 ./build/../src/backend/executor/execTuples.c: Nu există un astfel de fișier sau director.
(gdb) bt
#0 slot_deform_heap_tuple (natts=5, offp=0x557cc2e60720, tuple=<optimized out>, slot=0x557cc2e606d8) la ./build/../src/backend/executor/execTuples.c:930
#1 tts_buffer_heap_getsomeattrs (slot=0x557cc2e606d8, natts=5) la ./build/../src/backend/executor/execTuples.c:695
#2 0x0000557cc1d3998c în slot_getsomeattrs_int (slot=slot@entry=0x557cc2e606d8, attnum=5) la ./build/../src/backend/executor/execTuples.c:1912
#3 0x0000557cc1d28fba în slot_getsomeattrs (attnum=<optimized out>, slot=0x557cc2e606d8) la ./build/../src/include/executor/tuptable.h:344
#4 ExecInterpExpr (state=0x557cc2e620a8, econtext=0x557cc2ea1768, isnull=<optimized out>) la ./build/../src/backend/executor/execExprInterp.c:482
#5 0x0000557cc1d5548d în ExecEvalExprSwitchContext (isNull=0x7ffdd2599507, econtext=0x557cc2ea1768, state=0x557cc2e620a8) la ./build/executor/./executor/32/executor/srch/32
#6 ExecQual (econtext=0x557cc2ea1768, state=0x557cc2e620a8) la ./build/../src/include/executor/executor.h:391
#7 MJFillInner (node=0x557cc2ea1558) la ./build/../src/backend/executor/nodeMergejoin.c:494
#8 0x0000557cc1d55ce8 în ExecMergeJoin (pstate=0x557cc2ea1558) la ./build/../src/backend/executor/nodeMergejoin.c:1353
#9 0x0000557cc1d2cc83 în ExecProcNode (node=0x557cc2ea1558) la ./build/../src/include/executor/executor.h:248
#10 ExecutePlan (execute_once=<optimized out>, dest=0x557cc2e1a630, direction=<optimized out>, numberTuples=0, sendTuples=<optimized out>, operation=CMD_SELECT, use_parallel_mode=<optimized out>, planttate=0x557cc8e,a 
    estate=0x557cc2ea12f8) la ./build/../src/backend/executor/execMain.c:1632
#11 standard_ExecutorRun (queryDesc=0x557cc2e1a5a0, direction=<optimized out>, count=0, execute_once=<optimized out>) la ./build/../src/backend/executor/execMain.c:350
#12 0x00007f0ec05ae09d în pgss_ExecutorRun (queryDesc=0x557cc2e1a5a0, direction=ForwardScanDirection, count=0, execute_once=<optimized out>) la ./build/../contrib/pg/statments_statg5_statments_statg5_statments4
#13 0x0000557cc1cdbcd4 în PersistHoldablePortal (portal=portal@entry=0x557cc2d44b78) la ./build/../src/backend/commands/portalcmds.c:407
#14 0x0000557cc1ff95f9 în HoldPortal (portal=portal@entry=0x557cc2d44b78) la ./build/../src/backend/utils/mmgr/portalmem.c:642
#15 0x0000557cc1ff9e7d în PreCommit_Portals (isPrepare=isPrepare@entry=false) la ./build/../src/backend/utils/mmgr/portalmem.c:738
#16 0x0000557cc1c001c4 în CommitTransaction () la ./build/../src/backend/access/transam/xact.c:2087
#17 0x0000557cc1c015d5 în CommitTransactionCommand () la ./build/../src/backend/access/transam/xact.c:3085
#18 0x0000557cc1ea211d în finish_xact_command () la ./build/../src/backend/tcop/postgres.c:2662
#19 0x0000557cc1ea4703 în exec_simple_query (query_string=0x557cc2c9cd28 „COMMIT”) la ./build/../src/backend/tcop/postgres.c:1264
#20 0x0000557cc1ea6143 în PostgresMain (argc=<optimized out>, argv=argv@entry=0x557cc2cf6c68, dbname=<optimized out>, username=<optimized out>) la ./build/../src/backend/tcop .c:4339
#21 0x0000557cc1e25bcd în BackendRun (port=0x557cc2ce94d0, port=0x557cc2ce94d0) la ./build/../src/backend/postmaster/postmaster.c:4526
#22 BackendStartup (port=0x557cc2ce94d0) la ./build/../src/backend/postmaster/postmaster.c:4210
#23 ServerLoop () la ./build/../src/backend/postmaster/postmaster.c:1739
#24 0x0000557cc1e26b41 în PostmasterMain (argc=5, argv=<optimized out>) la ./build/../src/backend/postmaster/postmaster.c:1412
#25 0x0000557cc1b70f4f în principal (argc=5, argv=0x557cc2c96c30) la ./build/../src/backend/main/main.c:210

Adăugând log_statement = 'toate' la /etc/postgresql/13/main/postgresql.conf nu prea ajută, așa cum director de poştă termină imediat toate procesele și interogarea nu este scrisă în jurnalele.

iată strace ieșire după rulare COMMIT

[pid 20006] pwrite64(29, „COMMIT”, 6, 15936) = 6
[pid 20006] pwrite64(29, "\0", 1, 15942) = 1
[pid 20006] close(29) = 0
[pid 20006] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x10} ---
[pid 20006] +++ ucis de SIGSEGV (core dumping) +++
<... selectați reluat> ) = ? ERESTARTNOHAND (De repornit dacă nu există un handler)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_DUMPED, si_pid=20006, si_uid=108, si_status=SIGSEGV, si_utime=0, si_stime=0} ---
wait4(-1, [{WIFSIGNALED(e) && WTERMSIG(e) == SIGSEGV && WCOREDUMP(e)}], WNOHANG, NULL) = 20006
scrie(2, "2021-09-08 13:38:51.853 UTC [299"..., 198) = 198
scrie(2, "2021-09-08 13:38:51.853 UTC [299"..., 88) = 88
kill(19324, SIGQUIT) = 0
kill(-19324, SIGQUIT) = 0
kill(19331, SIGQUIT) = 0
kill(-19331, SIGQUIT) = 0
kill(19320, SIGQUIT) = 0
kill(-19320, SIGQUIT) = 0
kill(19319, SIGQUIT) = 0
kill(-19319, SIGQUIT) = 0
kill(19321, SIGQUIT) = 0
kill(-19321, SIGQUIT) = 0
kill(19322, SIGQUIT) = 0
kill(-19322, SIGQUIT) = 0
kill(19323, SIGQUIT) = 0
kill(-19323, SIGQUIT) = 0
wait4(-1, 0x7ffe90814374, WNOHANG, NULL) = 0
rt_sigreturn({mask=[]}) = -1 EINTR (apel de sistem întrerupt)
rt_sigprocmask(SIG_SETMASK, ~[ILL TRAP ABRT BUS FPE SEGV CONT SYS RTMIN RT_1], NULL, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
select(7, [5 6], NULL, NULL, {tv_sec=5, tv_usec=0}) = ? ERESTARTNOHAND (De repornit dacă nu există un handler)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=19320, si_uid=108, si_status=2, si_utime=14, si_stime=3} ---

Există o modalitate de a urmări exact interogarea SQL care a fost executată?

Michael Hampton avatar
drapel cz
Dacă se întâmplă în continuare în același loc, cel mai probabil ați întâlnit un fel de eroare și ar trebui să depuneți un raport de eroare.
drapel cn
Pe lângă cele de mai sus, te-ai uitat la jurnalele?
drapel ng
@MichaelHampton Da, voi încerca să fac asta, între timp trebuie să găsesc o soluție pentru a evita prăbușirea întregului postgres
drapel ng
@NasirRiley Nu există nimic interesant în jurnale, cu excepția liniilor deja afișate.
Puncte:2
drapel ng

Mai întâi, instalați simboluri de depanare pentru distribuția dvs., pentru distribuțiile Debian:

apt install gdb postgresql-13-dbgsym

Salt la un cadru care conține unele interogareDesc variabilă, de ex 12:

(gdb) cadrul 12
#12 0x00007f0ec05ae09d în pgss_ExecutorRun (queryDesc=0x557cc302b7d0, direction=ForwardScanDirection, count=0, execute_once=<optimized out>) la ./build/../contrib/pg/statments_statg5_statments_statg5_statments4
1045 în ./build/../contrib/pg_stat_statements/pg_stat_statements.c

imprimați acea variabilă:

(gdb) p interogareDesc
$1 = (QueryDesc *) 0x557cc302b7d0

acum copiați linia de mai sus după semnul egal și dereferiți-o folosind *

(gdb) p *(QueryDesc *) 0x557cc302b7d0
$6 = {operațiune = CMD_SELECT, plannedstmt = 0x557cc300e218, 
  sourceText = 0x557cc302b370 "\n", ' ' <se repetă de 12 ori>, "DECLARE \"categoryPagePhotoUrl_image_urls\" CURSORUL ȚINUT PENTRU\n", ' ' <se repetă de 12 ori>, "SELECT di.itemId, imagine_number, SELECT *\n", ' ' <se repetă de 12 ori>, "FROM downl"..., instantaneu = 0x557cc2e9b188, crosscheck_snapshot = 0x0, dest = 0x557cc302b860, params = 0x0, queryEnv = 0x55desc70ff = 0x557cc302b860, instrument = 0x557cc302b860 
  estate = 0x557cc2cf8d08, plantstate = 0x557cc2cf8f68, already_executed = true, totaltime = 0x0}

Nu vă oferă întreaga interogare, ci măcar o idee pe ce tabel este executată interogarea.

Bazat pe gdb ieșire Am reușit să izolez clienții care executau o astfel de interogare.

Am încercat să alerg VACUUM PLIN pe tabelul afectat, reconstruirea tabelului și a indecșilor, trecerea la replica, copierea întregii baze de date folosind pg_dump. Cu toate acestea, problema a persistat și pe copiile bazei de date.

În sfârșit am reușit să izolez un cod SQL minim pentru a reproduce problema.

$ pg_createcluster 13 principal
$ createb testdb
$ psql -d testdb -f postgresql-segfault.sql
CREAȚI SCHEMA
CREAȚI TABEL
COPIE 1
ALTER TABLE
ÎNCEPE
CREAȚI TABEL
DECLARE CURSOR
 ID-ul itemului  
---------
 1190300
(1 rând)

psql:postgresql-segfault:34: serverul a închis conexiunea în mod neașteptat
        Aceasta înseamnă probabil că serverul sa terminat anormal
        înainte sau în timpul procesării cererii.
psql:postgresql-segfault:34: fatal: conexiunea la server a fost pierdută

Cu un cod pentru a replica acest lucru a fost suficient pentru a raporteaza o eroare la pgsql-bugs listă de corespondență (există și un formular web). Sa dovedit a fi o eroare cu reexecuția unui plan care a ajuns deja la finalizare pe un cursor instabil care a fost inclus în PostgreSQL 13.4, 12.8 (și eventual alte versiuni).

Miles avatar
drapel kr
Mi-ai scutit de multe probleme la depanarea acestuia, mulțumesc.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.