2013-03-23 13 views
6

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

+0

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. –

+0

per favore domande povide che bloccano i blocchi –

+0

@CraigRinger: aggiornato per mostrare query di blocco e risultati. Non sono sicuro che sia affatto in ibernazione a questo punto. PostgreSQL v9.2. –

risposta

0

In qualche modo hibernate-memcached sembrava essere la causa principale di questo problema . La rimozione di hibernate-memcached dai nostri sistemi ha fatto sì che tutti i nostri problemi, se non fossero andati via, almeno iniziassero a comportarsi come normali problemi di database che ci si aspetterebbe di trovare in grado di migliorare e ridimensionare un'applicazione.

Non sto cercando di dire qualcosa di negativo su hibernate-memcached. Abbiamo utilizzato con successo questo progetto per oltre un anno di produzione senza incidenti. È più probabile che ci sia un conflitto con qualcos'altro specifico del nostro sistema, e l'ibernazione-memcached è stata semplicemente la cosa più semplice da cambiare.

1

In primo luogo, ciò che serve è l'eccellente Applicazioni Scaling Hibernate con Postgres discorsi presentati da Jim mlodgenski e Bruce Momjian nel Mondo JBoss 2009 per risolvere le più problemi comuni con Hibernate e PostgreSQL (memorizzazione nella cache, replica, pool di connessioni, ecc.). Yo può trovare here:

Quindi, è possibile inviare query dirette in SQL pianura se avete qualche problema con Lazy Loading:

String SQL_QUERY = "SELECT insurance_name, id, invested_amount, avg(i... 
       + "invested_amount - avg(invested_amount) OVER(PARTI... 
       + "FROM insurance "; 
Query query = session.createSQLQuery(SQL_QUERY) 
        .addScalar("insurance_name", Hibernate.STRING) 
        .addScalar("id", Hibernate.LONG) 
        .addScalar("invested_amount", Hibernate.LONG) 
        .addScalar("a", Hibernate.DOUBLE) 
        .addScalar("diff", Hibernate.DOUBLE); 
+0

Grazie per i suggerimenti. Non sono davvero sicuro se questa è una cosa di Hibernate a questo punto. Sembra che la caccia ci abbia portato in profondità nel livello del database, ma questa è solo l'ipotesi del momento :) –

Problemi correlati