2012-05-18 18 views
3

我需要能夠以每秒5000次以上的速度寫入我的數據庫。目前,我無法管理該數字的10%以上。使用Hibernate 2nd Level Cache和HSQL令人失望的插入/更新率

我使用Spring將我的數據源(HSQL)和Hibernate配置爲我的Jpa提供程序。

我的實體都是平坦的(沒有複雜的對象樹),我採用了Hibernate Second Level Caching(EhCache),併發策略設置爲ConcurrencyStrategy.READ-WRITE。

這裏是我的數據源豆我的春節 - 語境:

<bean id="commandsTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" 
p:entityManagerFactory-ref="commandEmf"/> 

<tx:annotation-driven transaction-manager="commandsTransactionManager" /> 

<!-- Commmands Data Source Configuration --> 
<bean id="commandsDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
    <property name="driverClassName" value="${jdbc-commands.driverClassName}"/> 
    <property name="url" value="${jdbc-commands.url}"/> 
    <property name="username" value="${jdbc-commands.username}"/> 
    <property name="password" value="${jdbc-commands.password}"/> 
    <property name="initialSize" value="10"/> 
    <property name="maxActive" value="100"/> 
    <property name="maxWait" value="-1"/> 
</bean> 

<bean name="lazyConnectionDataSourceProxy" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy"> 
    <property name="targetDataSource" ref="commandsDataSource" /> 
</bean> 

<!-- Commands Container Managed JPA Entity Manager Factory --> 
<bean id="commandEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="commandsDataSource"/> 
    <property name="persistenceUnitName" value="commands"/> 
    <property name="jpaPropertyMap" ref="jpaPropertyMap"/> 
    <property name="jpaVendorAdapter"> 
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" 
        p:showSql="false" p:generateDdl="true" p:database="HSQL" p:databasePlatform="org.hibernate.dialect.HSQLDialect"> 
      </bean> 
    </property> 
</bean> 

<util:map id="jpaPropertyMap" key-type="java.lang.String" value-type="java.lang.Object"> 
    <entry key="hibernate.hbm2ddl.auto" value="${jdbc-commands.ddlmode}" /> 
     <entry key="hibernate.cache.use_second_level_cache" value="true" /> 
     <entry key="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory"/> 
</util:map> 

這裏是我的實體類的一個示例。 'AbstractAnnotatedAggregateRoot'是來自Axon Framework的Abstract Entity類,它提供了Aggregate和Repository實現框架。聚合實質上是必須實現他們自己的Jpa才能持久化的實體。

@Entity 
@Table(name = "users") 
@Cache(region="usersCache", usage= CacheConcurrencyStrategy.READ_WRITE) 
public class User extends AbstractAnnotatedAggregateRoot { 

    private static final long serialVersionUID = -6536766172448063298L; 

    private String username; 

    private String password; 

    private Integer subscription; 

    private String firstName; 

    private String lastName; 

    private Calendar subscriptionDate; 

    private Date lastAccessTime; 

    public User(){} 

    public User(StringAggregateIdentifier email){ 
     super(email); 
     registerEvent(new UserCreatedEvent(email.asString())); 
    } 

    @Column(unique = true) 
    public String getUsername() { 
     return username; 
    } 

    public void setUsername(String username) { 
     this.username = username; 
     registerEvent(new UserNameUpdatedEvent(this.username)); 
    } 

    @Column(nullable = false) 
    public String getPassword() { 
     return password; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
     registerEvent(new UserPasswordUpdatedEvent(this.password)); 
    } 

    public String getFirstName() { 
     return firstName; 
    } 

    public void setFirstName(String firstName) { 
     this.firstName = firstName; 
     registerEvent(new UserFirstNameUpdatedEvent(this.firstName)); 
    } 

    public String getLastName() { 
     return lastName; 
    } 

    public void setLastName(String lastName) { 
     this.lastName = lastName; 
     registerEvent(new UserLastNameUpdatedEvent(this.lastName)); 
    } 

    public String getEmail() { 
     return getIdentifier().asString(); 
    } 

    @Temporal(TemporalType.DATE) 
    public Calendar getSubscriptionDate() { 
     return subscriptionDate; 
    } 

    public void setSubscriptionDate(Calendar subscriptionDate) { 
     this.subscriptionDate = subscriptionDate; 
     registerEvent(new UserSubscriptionDateUpdatedEvent(this.subscriptionDate)); 
    } 

    @Temporal(TemporalType.TIMESTAMP) 
    public Date getLastAccessTime() { 
     return lastAccessTime; 
    } 

    public void setLastAccessTime(Date lastAccessTime) { 
     this.lastAccessTime = lastAccessTime; 
     registerEvent(new UserLastAccessTimeUpdatedEvent(this.lastAccessTime)); 

    } 

    public Integer getSubscription() { 
     return subscription; 
    } 

    public void setSubscription(Integer subscription) { 
     this.subscription = subscription; 
     registerEvent(new UserSubscriptionUpdatedEvent(this.subscription)); 
    } 

} 

爲了完整起見,這裏是我ehcache.xml中的文件緩存區域配置:

<cache name="usersCache" maxElementsInMemory="10000" 
    maxElementsOnDisk="10000" eternal="false" overflowToDisk="false" 
    diskSpoolBufferSizeMB="20" timeToIdleSeconds="300" 
    timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU" 
    statistics = "true"> 
    </cache> 

在軸突框架,我派遣命令,試圖改變總的狀態。這些命令在由Spring的PlatformTransactionManager管理的事務的範圍內。

Command Dispatch同步發生,我需要每秒處理5,000條命令。每個命令都會從緩存中獲取聚合,在其上更改一個值,然後在分派下一個Command之前保持更改。問題是在獲取/更新/插入行時需要時間,考慮到由HYSQL和H2這樣的插入速度所帶來的INSERT速度,我認爲這會更快。

任何想法,以加快速度,我將不勝感激。

感謝

+0

您是否嘗試過不使用緩存?只是爲了看看它是否真的有所作爲?我有類似的東西,並且緩存實際上是在隨時都被刷新的情況下。我刪除了它,並獲得了很多改進的性能。這不是一個答案,只是一個問題:) – Ewald

+0

有趣的 - 刪除緩存沒有任何區別。我仍然在管理500次寫入,沒有緩存。 – totalcruise

+0

這很有趣,不是嗎?也許這個問題也應該是爲什麼緩存沒有什麼區別。這不幸超出了我的專業知識。 – Ewald

回答

0

如果這個實體是典型的數據(即沒有長字符串的列很少),並且數據庫操作是UPDATE,那麼數據庫性能應該與這裏描述的每秒5000個事務多個更新,每個事務一個選擇和一個插入)與基於磁盤的表。

http://hsqldb.org/web/hsqlPerformanceTests.html

數據庫有400萬隻記錄在一個表中。對於較大的表,性能會下降,尤其是數據庫大小超過使用Java nio內存映射文件的預設限制時。

您還應該檢查中的數據庫模式。腳本文件,並查看是否創建了不必要的索引,這可以減慢速度。

+0

Wowsers - 不是說55,000 TPS?如果是這樣,那麼我實際上運行的可用容量的1%左右。一些非常錯誤的東西。對於這樣簡單的對象,我可能會將Hibernate取出並查看是否有任何影響。感謝您的評論。 – totalcruise

+0

它具有全內存非持久性表的55000 TPS,但是具有基於磁盤的CACHED表的5000個TPS。 – fredt

0

我認爲你是在什麼可以與你的數據庫和JDBC和個人的INSERT語句來完成的極限。休眠不是緩存的問題。但是您的數據庫可能無法處理通過JDBC發送的更多插入。

但是,如果您設法使用bulk insert operations,則可以快得多。散裝我的意思是風格insert into your_table select ... from ...。您從表中讀取數據,修改一下,然後插入結果。有一個批量插入可能是可能的。

+0

真的嗎? 500插入/秒是關於極限? HSQL網站擁有更多(我知道它取決於對象大小/複雜度/變量類型),但我認爲我可以得到更多的數量級至少 – totalcruise