2013-03-23 38 views
6

一直在我的頭髮上拖了幾天。我們在獨佔數據庫鎖方面遇到了一些麻煩,導致我們的生產系統出現性能問題一段時間。我能夠仔細看看它,並且注意到持有排他鎖的查詢是由Hibernate的延遲加載生成的選擇。Hibernate + PostgreSQL:使用獨家鎖定延遲加載

我們使用Spring事務管理,在服務入口點定義了@Transactional(readOnly= "true")。我們使用會話每請求模型和映射到傳輸對象的實體。數據庫的默認隔離級別被讀取提交。 JDBC驅動程序配置爲讀取已提交。我已經檢查了使用的實際交易的隔離級別:

select current_setting('transaction_isolation') 

其中返回讀提交。我們使用JPA來配置Hibernate映射。我們沒有明確的升級交易。在這個特定的事務中,我們只運行select語句。打開Hibernate SQL日誌記錄我沒有看到任何這些:

select ... for update 

只有簡單的select語句正在被記錄。

這似乎是兩件事情之一在這裏。要麼我對讀取提交的理解完全關閉,並且提交的隔離級別應該導致在執行選擇的事務期間保持獨佔的行級鎖。或者其他事情正在進行,並且錯誤地升級了交易所持有的鎖。

任何幫助,將不勝感激。

編輯1

確定,一直在這一個長的卷繞路徑中。原來,這與鎖定無關。我用來檢測鎖的查詢已過時,並顯示「virtualxid」的鎖定類型。一些挖掘告訴我們,virtualxid是每個事務本身取出的鎖,因爲PostgreSQL的內部原因與本次討論沒有密切關係。我們對另一個監測查詢測試真正的排他鎖,並且還沒有看到。

下面是我們用來監控查詢「virtualxid」鎖,這更像是在這一點上長時間運行的查詢顯示器:

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; 

下面是一些輸出我們得到:

<redacted> | ExclusiveLock | virtualxid | t  | <redacted> | SELECT current_timestamp | 01:03:51.809594 | 22578 

一個簡單的選擇current_timestamp運行一個多小時!!!

無論如何,對於那些感興趣的人,它開始看起來像這些神祕的長時間運行的查詢偶爾會耗盡我們的數據庫連接池。所以我們提高了連接池限制,現場網站又回來了。我們已經獲得了應用程序超時,並在關鍵流程上重試邏輯以處理偶爾的打嗝。而現在我們通常至少有一個數據庫線程停止服務其中一個奇怪執行的查詢。絕對不理想:(

我們將嘗試打開基於成本的自動真空,看看這是否有助於解決問題。

編輯2

這一次竟然是一個非常漫長的旅途,這可能是在它的結束。爲了迴應這種行爲,除了我們在上面提到的數據庫查詢監控之外,我們還加強了批處理錯誤報告。再加上一些智能超時,這使我們能夠將特定的應用程序用例與長時間運行的數據庫查詢關聯起來。這使我們能夠對生產中出現的錯誤做出反應,以防止特定用法掛起JVM節點。

我們還能夠解決爲什麼一個進程中長時間運行的只讀TX會掛起連接到同一數據庫的其他進程的問題。這是事情變得有點奇怪的地方。我們使用hibernate-memcached將hibernate的二級緩存移動到共享的memcached服務器上,以便連接到同一數據庫的所有Java進程。每當我們遇到奇怪的懸掛行爲時,JVM進程中就會有大量的memcached客戶端線程。

刪除hibernate-memcached模塊後,移回ehcache進行第二級緩存,我們注意到奇怪的多JVM虛弱的掛起消失了。我們仍然偶爾收到一封電子郵件,告訴我們在德克薩斯州內部發生的事情應該多一點。我們仍然偶爾會遇到單個JVM進程掛起,因爲它們有太多這樣長的TX大規模進行。但是我們不再看到某個JVM中的進程以某種方式影響其他JVM。而之前我們會看到額外的節點無響應,直到我們殺死顯示不良TX行爲的初始節點。

這是沒有意義的。但後來這個問題從來沒有:)

蒂姆 -

+0

你真的需要看看'pg_locks'來看看發生了什麼。請參閱http://wiki.postgresql.org/wiki/Lock_Monitoring。還請指定您的Hibernate版本和PostgreSQL版本。 – 2013-03-23 03:02:25

+0

請提供持有鎖的查詢 – 2013-03-23 09:40:57

+0

@CraigRinger:已更新以顯示鎖查詢和結果。在這一點上,我不確定它是否是Hibernate。 PostgreSQL v9.2。 – 2013-05-21 00:13:33

回答

0

莫名其妙的Hibernate的memcached似乎是這個問題的根本原因。從我們的系統中刪除hibernate-memcached使得我們所有的問題(如果不會消失的話)至少開始像正常的數據庫問題那樣行事,您希望找到增強和擴展應用程序的方法。

我不想對hibernate-memcached說任何壞話。我們成功地使用了這個項目一年以上,沒有發生任何事情。它更可能與我們的系統特有的其他內容發生衝突,而hibernate-memcached是我們改變的最簡單的事情。

1

首先,你需要的是優秀的縮放Hibernate的應用程序與Postgres的談話在JBoss World大會2009年由Jim mlodgenski和Bruce Momjian提出解決最Hibernate和PostgreSQL的常見問題(緩存,複製,連接池等)。喲可以找到它here

然後,您可以在普通的SQL直接發送查詢,如果你有一些麻煩與延遲加載:

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

感謝您的建議。我真的不確定在這一點上這是否是一個Hibernate的東西。看起來狩獵已經讓我們深入到數據庫層,但這只是當下的假設:) – 2013-05-21 00:16:38