2013-03-30 21 views
-1

當針對我的本地數據庫開發應用程序時,雖然事務處理速度沒有問題,但是每秒執行多次事務時CPU使用率一直保持在30%左右,大部分時間都用於處理事務的javax方法,每個事務的平均時間爲2.6秒。因此,我使用ArrayList作爲緩衝區,並且只在緩衝區的大小超過300個實例時才發送事務,這會顯着降低CPU使用率。提高javax.persistence事務對遠程數據庫的性能

當我將persistence.xml改爲使用遠程數據庫(同時檢查RDS和個人,場外數據庫)時,持續/提交一批實例的最短時間約爲20秒,即因爲每5秒需要一次300次事務處理(平均),所以過高。

我試着將EntityManager的flushmode更改爲FlushModeType.COMMIT,但它並沒有明顯改變性能。發送之前增加緩衝區的大小導致堆棧溢出,javax.persistence庫對於某些(對我而言)未知原因。

的persistence.xml

<persistence-unit name="PU-data" transaction-type="RESOURCE_LOCAL"> 
    <mapping-file>META-INF/orm.xml</mapping-file> 
    ... // class, shared-cache-mode=none, validation-mode=none ... 
    <properties> 
     ... // Authentication ... 
     <!-- Optimization attempts --> 
     <property name="eclipselink.jdbc.bind-parameters" value="true" /> 
     <property name="eclipselink.jdbc.batch-writing" value="JDBC"/> 
     <property name="eclipselink.jdbc.batch-writing.size" value="300" /> 
     <property name="eclipselink.jdbc.cache-statements" value="true" /> 
     <property name="eclipselink.cache.shared.default" value="false" /> 
     <property name="eclipselink.persistence-context.close-on-commit" value="true" /> 
     <property name="eclipselink.persistence-context.flush-mode" value="commit" /> 
     <property name="eclipselink.persistence-context.persist-on-commit" value="false" /> 
    </properties> 
</persistence-unit> 

門面處理交易

MouseFacade.bufferSemaphore.acquireUninterruptibly(1); 
if (MouseFacade.buffer.size() >= 300) { 
    EntityManager entityManager = EMF.getEntityManager(); 
    try { 
     entityManager.getTransaction().begin(); 
     for (Mouse mouse : MouseFacade.buffer) { 
      entityManager.persist(mouse); 
     } 
     entityManager.getTransaction().commit(); 
    } finally { 
     if (entityManager.getTransaction().isActive()) { 
      entityManager.getTransaction().rollback(); 
     } 

     entityManager.close(); 
     MouseFacade.buffer.clear(); 
    } 

} 
MouseFacade.bufferSemaphore.release(1); 

ORM映射

<entity-mappings version="2.1" xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <entity class="se.my.package.Mouse"> 
     <table-generator name="ORD_SEQ" allocation-size="300"/> 
    </entity> 
</entity-mappings> 

更新

我已經通過在本頁面發現的建議了,叫如何通過1,825%http://java-persistence-performance.blogspot.se/2011/06/how-to-improve-jpa-performance-by-1825.html),以提高JPA的性能,但沒有任何區別什麼那麼這讓我不知道我是否錯過了關於批量編寫和MySQL的關鍵點。我已經將實體重寫爲不依賴關係,並將整個應用程序的讀操作最小化爲1,以便專注於寫入問題。

在瀏覽EclipseLink日誌時,它看起來不像批處理寫入正在被使用,而是爲每個似乎正確的實例編寫了2個日誌條目(300個實例* 2個連接* 24個延遲= 14.4秒)。

[EL Fine]: sql: 2013-03-31 01:35:29.249--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--SELECT LAST_INSERT_ID() 
[EL Fine]: sql: 2013-03-31 01:35:29.274--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--INSERT INTO mouse (event, posX, posY, created, uid) VALUES (?, ?, ?, ?, ?) 
    bind => [12, 241, 250, 1364690113727, 1] 
[EL Fine]: sql: 2013-03-31 01:35:29.298--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--SELECT LAST_INSERT_ID() 
[EL Fine]: sql: 2013-03-31 01:35:29.323--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--INSERT INTO mouse (event, posX, posY, created, uid) VALUES (?, ?, ?, ?, ?) 
    bind => [12, 233, 296, 1364690113443, 1] 
... 

進展

通過改變@GeneratedValue(strategy = GenerationType.TABLE)allocationSize=300我已經成功了50%,減少請求的數量,雖然檢查的EclipseLink時看起來好像綁定仍然對自己的發日誌,即使批量書寫據說是啓用的。

[EL Fine]: sql: 2013-03-31 01:35:29.323--ClientSession(1213059092)--Connection(662811604)--Thread(Thread[pool-1-thread-1,5,main])--INSERT INTO mouse (event, posX, posY, created, uid) VALUES (?, ?, ?, ?, ?) 
bind => [..., ..., ..., ..., ...] 
bind => [..., ..., ..., ..., ...] 
bind => [..., ..., ..., ..., ...] 
bind => [..., ..., ..., ..., ...] 
bind => [..., ..., ..., ..., ...] 
bind => [..., ..., ..., ..., ...] 
bind => [..., ..., ..., ..., ...] 
bind => [..., ..., ..., ..., ...] 
bind => [..., ..., ..., ..., ...] 
bind => [..., ..., ..., ..., ...] 
+0

具有高與非現場數據庫的交互性具有挑戰性,以下由David Levesque提到的jdbc批處理是一個好主意,但這是一個具有根本挑戰性的範例。無論如何,您可以重構您的系統架構以便與DB建立低延遲連接? (例如1跳千兆以太網連接?) – Taylor

+0

不,應用程序旨在收集日常使用鼠標的使用情況信息作爲實驗室環境以外的生物特徵研究。據我所知,連接可以是有線,無線或3G網絡。另一種方法是將所有內容寫入文件,並要求研究中的用戶手動發送這些內容,這是我真正希望避免的,因爲需要在數據進入時執行分析。 –

+0

@泰勒雖然我無法真正看到我發送的數據量如何可能導致這種性能下降。每個實例7個int(16)和每次300個實例應該相當於33kB的數據。使用10Mbit的上行連接,它應該需要大約30毫秒來發送原始數據,這意味着數據庫開銷是**巨大的**? –

回答

2

將您的測序更改爲使用表序列允許序號進行預分配。現在你已經強制每個插入到它自己的語句中,以便可以在後面找到id - 這可以防止批處理。如果與批次大小相匹配,允許預分配的表格和其他策略可以提供更好的性能。優化#6 http://java-persistence-performance.blogspot.se/2011/06/how-to-improve-jpa-performance-by-1825.html

+0

謝謝!改變它可以減少一半的時間(大約7.5秒),但是看EL日誌,它仍然看起來像每個綁定語句都是自己發送的,這是通過計算總延遲[(300 + 1)* 24〜= 7.2]。是否有可能將所有這些綁定作爲單個請求發送到數據庫,如bind; bind; bind; bind; ...? –

+1

日誌顯示批處理寫入將所有內容作爲單個批處理髮送給驅動程序,綁定僅分別打印到日誌中以便可讀。我的猜測是MySQL驅動程序沒有正確設置批處理,請參見下文。 – James

1

嘗試啓用JDBC batch writing。我不確定它會有什麼不同,但它可能值得嘗試。

+0

嘗試使用連接池(如c3p0或apache dbcp),看起來您可能還必須根據txn或類似協商連接。 – Taylor

+0

Re:連接池。池信息未在persistence.xml中顯示,但EclipseLink默認使用32個連接的連接池,所以這不應該成爲問題。 – James

1

對於MySQL的批量寫入了MySQL JDBC驅動程序不批的語句,除非你已經設置你的連接錯誤的網址下列財產,

?rewriteBatchedStatements=true 

jdbc:mysql://localhost:3306/db1?rewriteBatchedStatements=true