PgPool Load balancing for Java/JDBC application - java

After setting up all the possible settings of PgPool on CentOS, when I tested it using my Java application, I found that it is not working.
After reading manual on internet (you can find here), I found that it will not work for JDBC statements if they have been set to false (for auto commit).
Since I am using Hibernate, I am quiet sure that it is using transaction to set the values.
My question is, if this is true, which method of is useful to replicate my databases. I hear about parallel mode, but I am not sure whether it will work for Java application. Can anybody guide and provide me samples for it?

Modification transactions at the end of business methods work as you describe: a BEGIN/END block is created containing all modification queries that are either all committed or rolled back.
This is done by setting autocommit to false, but this does not mean that all queries made by Hibernate are done in this mode. The same query depending on the required isolation mode might be executed either in auto-commit or non auto-commit mode.
For the usual case of a transaction in READ_COMMITED mode, queries like find by Id or named queries will run in it's own database transaction with auto-commit true ( and so without a BEGIN/END block).
Find by Ids and other read queries will only trigger a BEGIN block if they are run in at least REPEATABLE_READ isolation mode.
This mean that if you use the default REPEATABLE_READ isolation mode, the load balancing will work fine because most select queries will run with in auto-commit = true.
You can confirm this by logging all SQL queries sent to the database using for example log4jdbc. This will print all the SQL actually sent to the database.

If by parallel mode what you meant is the transaction isolation level, from this page you can see that PostgreSQL supports 4 level of isolations, and it is configurable from hibernate by setting the property: hibernate.connection.isolation to 1, 2, 4, or 8, from lower level to the highest.
Read committed is the default isolation level in PostgreSQL, one level above dirty read.
Serialization is the highest level and it is very expensive, because if 2 transactions are to be made on the same table, there will be a lock, if locking happens more than the time out that was set on the Database/Hibernate, then it will throw a time out exception.
Not sure if you have heard about them but following are frameworks that can be used with hibernate to improve performance:
C3P0 for a more advanced connection pooling
Ehcache for boosting performance by enabling cache
They are easy to configure and do not depends on OS. I did not have any experience with PgPool so I can't give comments on performance comparison.
Following are the sample hibernate settings that you might want to try:
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.connection.isolation">4</prop>
<prop key="hibernate.connection.autocommit">false</prop>
<prop key="hibernate.c3p0.min_size">5</prop>
<prop key="hibernate.c3p0.max_size">20</prop>
<prop key="hibernate.c3p0.timeout">1800</prop>
<prop key="hibernate.c3p0.max_statements">50</prop>
<prop key="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider</prop>
<prop key="net.sf.ehcache.configurationResourceName">WEB-INF/ehcache.xml</prop>
I hope this can help you in optimizing your application in regards of database transactions. There are a lot more that you can actually check e.g. table indexing, or using a profiler to find out which transactions cost the most.

Related

share hibernate-search indexes across multiple servers

currently we are aiming to do load balance 2 active servers 50/50.
Java application uses hibernate search locally, I have centralized this directory so both server uses the same directory.
I want to share hibernate indexing with multiple servers
I have set following so there is no locking between read/writefrom the servers
property name="hibernate.search.default.locking_strategy" value="none"
Does anyone know if this will be an issue?
I can't really answer your question but I'd like to share some considerations.
We used this kind of configuration during years in production (no custom lock strategy) and we experimented so much problem (stale nfs file handle, dead lock and index corruption).
We tried to defer all the index updates operation to a single server using JMS but even in this mode we experimented some problems (much less than in the mode where update operation occurs on many servers however)
Note also that putting the index files on NFS is strongly discouraged
We finally gave up hibernate search, for distributed indexes I'll personally advise to use elastic search.
However this is theoretically possible as stated there : https://docs.jboss.org/hibernate/search/5.1/reference/en-US/html/search-architecture.html#_lucene
This mode targets non clustered applications, or clustered applications where the Directory is taking care of the locking strategy.
I don't really know how the "Directory" is expected to handle the locking strategy
The previously used datasource configuration regarding hibernate search :
<!-- hibernate search configuration -->
<!-- index root folder location -->
<prop key="hibernate.search.default.indexBase">${env.ftindex.location.root}/${datasource.database}/${ftindex.folder}</prop>
<!-- global analyzer -->
<prop key="hibernate.search.analyzer">custom_analyzer</prop>
<!-- asynchronous indexing for performance considerations -->
<prop key="org.hibernate.worker.execution">async</prop>
<!-- max number of indexing operation to be processed asynchronously (before session flush) to avoid OutOfMemoryException -->
<prop key="hibernate.search.worker.buffer_queue.max">100</prop>

Configure Query Cache in Hibernate4

I'm trying enable query cache in our application. As per the documentation I have given
hibernate.cache.use_query_cache as true and givent setCacheable() in my queries. But I'm getting below exception.
org.hibernate.cache.NoCacheRegionFactoryAvailableException: Second-level cache is used in the application, but property hibernate.cache.region.factory_class is not given, please either disable second level cache or set correct region factory class name to property hibernate.cache.region.factory_class (and make sure the second level cache provider, hibernate-infinispan, for example, is available in the classpath).
Should I specify cache region for query cache, I'm using Hibernate 4. Please help me in this regard
Use Following for hibernate 4.
I am using this with hibernate 4.3
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property>

DB use an excessive amount of CPU - 95%

I am using Spring MVC + hibernate in my application. Application server is IBM WebSphere v7. While restarting and after restart application, Db2syscs process makes CPU usage 99% and consumes memory usage about 1,034,352K. This goes about 10~15 minutes. I tried increasing the heap size allocated to DB2, which made no difference.
EDIT
These are my hibernate properties in spring configuration file. Will adding cache, pool properties make any affect?
<prop key="hibernate.dialect">org.hibernate.dialect.DB2Dialect</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.connection.datasource">jdbc/logincfg</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory
</prop>
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.WebSphereExtendedJTATransactionLookup
</prop>
If you're running on linux, try a monitor such as db2top to determine which query is churning your CPU.
db2top -d <your database name>
WebSphere itself handles all pooling and cache level for its Data sources. All JDBC related configurations can be performed through WebSphere administrative console. Try using connection pool datasource instead of XA datasource. Also check heuristic hazard in server configuration. These will decrease load on CPU.

"Local transaction already has 1 non-XA Resource: cannot add more resources" error

After reading previous questions about this error, it seems like all of them conclude that you need to enable XA on all of the data sources. But:
What if I don't want a distributed
transaction? What would I do if I want to
start transactions on two different
databases at the same time, but
commit the transaction on one database
and roll back the transaction on
the other?
I'm wondering how my code
actually initiated a distributed
transaction. It looks to me like I'm
starting completely separate
transactions on each of the
databases.
Info about the application:
The application is an EJB running on a Sun Java Application Server 9.1
I use something like the following spring context to set up the hibernate session factories:
<bean id="dbADatasource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/dbA"/>
</bean>
<bean id="dbASessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dbADatasource" />
<property name="hibernateProperties">
hibernate.dialect=org.hibernate.dialect.Oracle9Dialect
hibernate.default_schema=schemaA
</property>
<property name="mappingResources">
[mapping resources...]
</property>
</bean>
<bean id="dbBDatasource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/dbB"/>
</bean>
<bean id="dbBSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dbBDatasource" />
<property name="hibernateProperties">
hibernate.dialect=org.hibernate.dialect.Oracle9Dialect
hibernate.default_schema=schemaB
</property>
<property name="mappingResources">
[mapping resources...]
</property>
</bean>
Both of the JNDI resources are javax.sql.ConnectionPoolDatasoure's. They actually both point to the same connection pool, but we have two different JNDI resources because there's the possibility that the two, completely separate, groups of tables will move to different databases in the future.
Then in code, I do:
sessionA = dbASessionFactory.openSession();
sessionB = dbBSessionFactory.openSession();
sessionA.beginTransaction();
sessionB.beginTransaction();
The sessionB.beginTransaction() line produces the error in the title of this post - sometimes. I ran the app on two different sun application servers. On one runs it fine, the other throws the error. I don't see any difference in how the two servers are configured although they do connect to different, but equivalent databases.
So the question is
Why doesn't the above code start
completely independent transactions?
How can I force it to start
independent transactions rather than
a distributed transaction?
What configuration could cause the difference in
behavior between the two application
servers?
Thanks.
P.S. the stack trace is:
Local transaction already has 1 non-XA Resource: cannot add more resources.
at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.enlistResource(J2EETransactionManagerOpt.java:124)
at com.sun.enterprise.resource.ResourceManagerImpl.registerResource(ResourceManagerImpl.java:144)
at com.sun.enterprise.resource.ResourceManagerImpl.enlistResource(ResourceManagerImpl.java:102)
at com.sun.enterprise.resource.PoolManagerImpl.getResource(PoolManagerImpl.java:216)
at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:327)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:189)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:165)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:158)
at com.sun.gjc.spi.base.DataSource.getConnection(DataSource.java:108)
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:82)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
at org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:142)
at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:85)
at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1354)
at [application code ...]
1 Why doesn't the above code start completely independent transactions?
The app. server manages the transaction for you which can, if necessary, be a distributed transaction. It enlists all the participants automatically. When there's only one participant, you don't notice any difference with a plain JDBC transaction, but if there are more than one, a distributed transaction is really needed, hence the error.
2 How can I force it to start independent transactions rather than a
distributed transaction?
You can configure the datasource to be XA or Local. The transactional behavior of Spring/Hibernate can also be configured to use either regular JDBC transactions or delegate the management of transactions to the JTA distributed transaction manager.
I suggest you switch the datasource to non-XA and try to configure Spring/Hibernate to use the JDBC transactions. You should find the relevant information in the documentation, here what I suspect is the line to change:
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager" />
This should essentially means that you are not using the app. server distributed transaction manager.
3 What configuration could cause the difference in behavior between the
two application servers?
If you have really exactly the same app and configuration, this means that in one case only one participant is enlisted in the dist. transaction, while there are two in the 2nd case. One participant corresponds to one physical connection to a database usually. Could it be that in one case, you use two schema on two different databases, while in the 2nd case you use two schema on the same physical database? A more probable explanation would be that the datasource were configured differently on the two app. server.
PS: If you use JTA distributed transactions, you should use UserTransaction.{begin,commit,rollback} rather than their equivalent on the Session.
After reading previous questions about this error, it seems like all of them conclude that you need to enable XA on all of the data sources.
No, not all, all except one (as the exception is saying) if your application server supports Logging Last Resource (LLR) optimization (which allows to enlist one non-XA resource in a global transaction).
Why doesn't the above code start completely independent transactions?
Because you aren't. When using beginTransaction() behind EJB Session Beans, Hibernate will join the JTA transaction (refer to the documentation for full details). So the first call just works but the second call means enlisting another transactional resource in the current transaction. And since none of your resources are XA, you get an exception.
How can I force it to start independent transactions rather than a distributed transaction?
See #ewernli answer.
What configuration could cause the difference in behavior between the two application servers?
No idea. Maybe one of them is using at least one XA datasource.

How I can disable the second-level cache of some certain entities in Hibernate without changing annotations

I'm using Hibernate second level cache in my application, for certain business reason I can't change the entity annotation any more.
In my project, apart from changing the Database from Hibernate, there exist also other native SQL that do not go through Hibernate. Therefore, the Hibernate second-level cache data could be stale after database being updated from native SQL. That's why I want to disable the second-level cache for certain entities (programmatically or other way than changing annotation).
Thanks in advance!
WARNING: As Jens Schauder noted, it is impossible to configure Ehcache to store 0 elements in memory by setting maxElementsInMemory="0" as it effectively causes opposite effect - sets unlimited size for the cache. This behaviour is not mentioned on the Hibernate Caching page but is documented on Cache Configuration page.
I have quickly reviewed the documentation and haven't found alternative approach yet. I am unable to delete this answer by myself. :-(
My original suggestion:
You can configure the implementation provider of second level cache to short TTL times and/or to store 0 entries of particular entity type.
E.g. if you are using the Ehcache, you can configure it in ehcache.xml:*
<cache
name="com.problematic.cache.EntityName"
maxElementsInMemory="0" <<== this should effectively disable caching for EntityName
overflowToDisk="false" <<== Do not overflow any entries to disk
/>
See Hibernate Caching in Ehcache documentation.
In Terracotta 3.1 and above, you can enable/disable Hibernate 2nd Level Caches on a per region basis, both in the configuration (statically) and at runtime, using the Terracotta Developer Console.
You can also monitor in realtime statistics about the cache and Hibernate, for individual nodes in a cluster or cluster-wide.
Terracotta is open source. For more details, check out Terracotta for Hibernate.

Categories