Mi sono strappato i capelli per un paio di giorni. Abbiamo avuto qualche problema con blocchi di database esclusivi che causano problemi di prestazioni nel nostro sistema di produzione per un po 'di tempo. Sono stato in grado di dare un'occhiata più da vicino, e sto notando che le query che contengono i blocchi esclusivi sono selezionate generate dal pigro caricamento di Hibernate.Hibernate + PostgreSQL: caricamento pigro con blocchi esclusivi
Stiamo utilizzando la gestione delle transazioni di primavera, @Transactional(readOnly= "true")
è definito nel punto di ingresso del servizio. Usiamo il modello sessione per richiesta con entità mappate per trasferire oggetti. Il livello di isolamento predefinito del database viene letto in lettura. Il driver JDBC è configurato con read committed. Ho controllato il livello di isolamento della transazione effettiva in questione utilizzando:
select current_setting('transaction_isolation')
Quali resi lette confermate. Stiamo usando JPA per configurare i mapping Hibernate. Da nessuna parte aggiorniamo esplicitamente la transazione. In questa particolare transazione eseguiamo solo istruzioni selezionate. L'attivazione di registrazione Hibernate SQL non vedo uno di questi:
select ... for update
Solo semplici istruzioni SELECT vengono registrati.
Sembra che una delle due cose stia succedendo qui. O la mia comprensione di read commesso è completamente off e read livelli di isolamento commessi DOVREBBE comportare blocchi esclusivi a livello di riga detenuti per la durata della transazione che esegue i select. O qualcos'altro sta succedendo e aggiornando erroneamente i blocchi trattenuti dalla transazione.
Qualsiasi aiuto sarebbe apprezzato.
Edit 1:
Ok, è stato un percorso tortuoso lungo su questo. Risulta che questo non ha nulla a che fare con il blocco. La query che stavo utilizzando per rilevare i blocchi era obsoleta e mostrava il tipo di blocco di "virtualxid". Alcuni scavi ci dicono che virtualxid è il blocco che ogni transazione prende su se stesso, per motivi interni a PostgreSQL non pertinenti a questa discussione. Abbiamo eseguito il cron di un altro test delle query di monitoraggio per veri blocchi esclusivi e non ne abbiamo ancora visto uno.
Ecco la domanda che stiamo usando per monitorare le serrature "virtualxid", che è più simile a un monitor di lunga durata domanda a questo punto:
SELECT pg_stat_activity.datname, pg_locks.mode, pg_locks.locktype, pg_locks.granted, pg_stat_activity.usename,pg_stat_activity.query,age(now(),pg_stat_activity.query_start) AS "age", pg_stat_activity.pid
FROM pg_stat_activity,pg_locks
LEFT OUTER JOIN pg_class ON (pg_locks.relation = pg_class.oid)
WHERE
age(now(),pg_stat_activity.query_start) > interval '1 minute' AND
pg_stat_activity.datname <> 'postgres' AND
pg_locks.pid=pg_stat_activity.pid AND
pg_stat_activity.query not like '%autovacuum%' AND
pg_stat_activity.query not like '%COPY%stdout%'
order by query_start;
Ed ecco qualche uscita stiamo ottenendo:
<redacted> | ExclusiveLock | virtualxid | t | <redacted> | SELECT current_timestamp | 01:03:51.809594 | 22578
Un semplice selezionare current_timestamp in esecuzione per oltre un'ora !!!
In ogni caso, per chi fosse interessato ha iniziato a sembrare che queste misteriose query a lungo termine stessero occasionalmente svuotando il nostro pool di connessione al database. Quindi abbiamo superato i limiti del pool di connessioni e il sito live è tornato a canticchiare. Abbiamo timeout sul lato app e riprovo la logica in atto sui processi critici per gestire il singhiozzo occasionale. E di questi tempi di solito abbiamo almeno un thread del database bloccato per servire una di queste query stranamente in esecuzione. Sicuramente non è l'ideale :(
Stiamo per provare a attivare il vuoto automatico basato sui costi e vedere se questo aiuta a risolvere i problemi.
Edit 2:
Questo si è rivelato essere un viaggio molto lungo, che potrebbe essere al suo fine. In risposta a questo comportamento, abbiamo implementato la segnalazione degli errori di elaborazione in batch oltre al monitoraggio delle query del database che abbiamo inserito sopra. Insieme ad alcuni timeout intelligenti, questo ci ha permesso di mettere in relazione specifici casi d'uso delle applicazioni con le query del database a lungo termine. Questo ci ha permesso di reagire agli errori osservati nella produzione per impedire che usi specifici sospendessero un nodo JVM.
Siamo stati anche in grado di risolvere il problema del perché un TX di sola lettura e in sola lettura in un unico processo avrebbe bloccato altri processi che si collegavano allo stesso database. Questo è dove le cose si fanno un po 'strane. Stavamo usando hibernate-memcached per spostare la cache di secondo livello di hibernate in un server memcached condiviso per tutti i processi Java che si connettono allo stesso database. Ogni volta che ottenevamo lo strano comportamento di sospensione ci sarebbero un sacco di thread client memcached nei processi JVM.
Dopo aver rimosso il modulo hbernate-memcached, tornando a ehcache per la cache di secondo livello, abbiamo notato che lo strano hangout debilitante multi-JVM è andato via. Riceviamo ancora le e-mail occasionali che ci dicono che un po 'di più sta accadendo all'interno di un TX di quanto dovrebbe essere. Continuiamo a riattaccare l'occasionale processo JVM singolo perché è troppo lungo il numero di questi TX lunghi in corso. Ma non vediamo più processi in una JVM che influenzano in qualche modo altri JVM. Considerando che in precedenza avremmo visto altri nodi non rispondere fino a quando non abbiamo ucciso il nodo iniziale che mostrava un cattivo comportamento del TX.
Quale non ha senso. Ma questo problema non ha mai fatto :)
- Tim
Devi davvero dare un'occhiata a 'pg_locks' per vedere cosa sta succedendo. Vedi http://wiki.postgresql.org/wiki/Lock_Monitoring. Specificare inoltre la versione di Hibernate e la versione di PostgreSQL. –
per favore domande povide che bloccano i blocchi –
@CraigRinger: aggiornato per mostrare query di blocco e risultati. Non sono sicuro che sia affatto in ibernazione a questo punto. PostgreSQL v9.2. –