| Author |
Message |
![[Post New]](/forums/templates/default/images/icon_minipost_new.gif) 08/02/2012 06:37:52
|
chrismas
journeyman
Joined: 07/27/2012 01:16:24
Messages: 27
Offline
|
Hello,
I'm new to EhCache and I built my first application under EhCache which is clustered on a Terracotta cluster.
I did a performance test on a particular point of my application.
The work is done in a local transaction in strong consistency mode.
I do (I use two caches - cache1 and cache2) :
Code:
- Begin the transaction
- Obtain a write lock on a key on cache2
- Get a cached object on cache2
- Put an object on cache1
- Put an object on cache2
- Release the write lock
- Commit the transaction
During my test, the cache is empty and the terracotta cluster is running on the same machine as the ehcache client.
This transaction takes between 20ms and 100ms to be executed.
How can I have better performances ?
Christophe.
|
|
|
 |
![[Post New]](/forums/templates/default/images/icon_minipost_new.gif) 08/07/2012 00:56:47
|
chrismas
journeyman
Joined: 07/27/2012 01:16:24
Messages: 27
Offline
|
I do more tests:
If I do this set of tasks without transaction (transactionnal mode set to "off"), the set of task is done in 5ms, whereas, in local transactionnal mode, this execution takes 30-40ms: 6 times slower.
It is normal ?
|
|
|
 |
![[Post New]](/forums/templates/default/images/icon_minipost_new.gif) 08/07/2012 07:22:40
|
lorban
master
Joined: 01/08/2010 13:09:16
Messages: 98
Location: CET
Offline
|
May I ask you why you're mixing both transactions and locking? Usually, transactions can be considered roughly like a form of automated locking so I'm puzzled by your need for manual locks.
If your use-case can be fulfilled by only using locking, I would advise to against using transactions. If not, I would advise you to avoid using locks with transactions.
Regarding the performance, it's very hard to answer you with so little details. I suppose that since you're doing so little work in your transaction, the commit time dominates but that's only a guess. A code sample would help giving a more tangible answer.
|
Ludovic Orban (Terracotta engineer) |
|
|
 |
![[Post New]](/forums/templates/default/images/icon_minipost_new.gif) 08/08/2012 02:11:25
|
chrismas
journeyman
Joined: 07/27/2012 01:16:24
Messages: 27
Offline
|
I may be wrong but I mixing both transaction and locking because:
- the transaction guarantee me that the operation is not partially done on JVM crash between the begin and the commit of the transaction
- the write lock allow me to synchronized jobs done on a key
My lock is done on a value that I not manipulate (retrieves or updates) in my transaction. I just do a lock on a key but not call cache.get or cache.put on this key.
This is done because I need to block actions on this particular key when I do my set of tasks.
So, if mixing transaction and locking is not optimized, do I need to call to cache.get() instead of locking in the transaction to force an automated lock ?
|
|
|
 |
![[Post New]](/forums/templates/default/images/icon_minipost_new.gif) 08/08/2012 04:34:25
|
lorban
master
Joined: 01/08/2010 13:09:16
Messages: 98
Location: CET
Offline
|
Mixing locks and transactions isn't recommended as they both use different forms of locking and if you're not super careful, you can very easily case deadlocks especially since you cannot control the transactions' locks.
Transactions give you read-committed isolation and the guarantee that all changes are 'published' atomically so I don't see a reason why you'd want to block readers as you can be sure all other threads will see consistent data.
I wonder why you need to block actions on a particular key as once again, while the transaction is running, its changes aren't visible until after it is committed.
|
Ludovic Orban (Terracotta engineer) |
|
|
 |
![[Post New]](/forums/templates/default/images/icon_minipost_new.gif) 08/08/2012 06:16:49
|
chrismas
journeyman
Joined: 07/27/2012 01:16:24
Messages: 27
Offline
|
I wonder why you need to block actions on a particular key as once again, while the transaction is running, its changes aren't visible until after it is committed.
I must guarantee that no other concurrent transaction can read and work on the same key concurrently.
With read-committed isolation, I think that concurrent transactions read the last commited value (maybe the same value if it is done concurrently) and can do concurrent operations on this value before commiting. So, the same operation can be done concurrently.
Maybe, I don't understand read-commited isolation in transactions.
I wrote a little example, I hope to be as clear as possible:
Code:
class Job {
long id;
boolean jobDone = false;
}
final TransactionController transactionController = CacheManager.getInstance().getTransactionController();
transactionController.begin();
Job job = (Job) cache.get(jobId);
if( ! job.isDone() ){
doJob(job);
job.setJobDone(true);
cache.replace(new Element(job.getId(), job));
}
transactionController.commit();
In this example, can I guarantee that the job will be done once in case of two concurrent transactions (working on the same job id) with read-commited isolation level ?
|
|
|
 |
![[Post New]](/forums/templates/default/images/icon_minipost_new.gif) 08/08/2012 06:23:06
|
lorban
master
Joined: 01/08/2010 13:09:16
Messages: 98
Location: CET
Offline
|
Transactions would not prevent two or more threads to run the same job in parallel.
On the other hand, I don't see what they buy you here as you only modify one element.
|
Ludovic Orban (Terracotta engineer) |
|
|
 |
![[Post New]](/forums/templates/default/images/icon_minipost_new.gif) 08/08/2012 06:57:01
|
chrismas
journeyman
Joined: 07/27/2012 01:16:24
Messages: 27
Offline
|
Transactions would not prevent two or more threads to run the same job in parallel.
Thanks for the precision. The read-commit isolation level was not clear for me.
In transaction, does a commited value is obtained on every get call in the transaction of all commited values are pre-calculated at the beginning of the transaction ?
I think that the last commited value is obtained on every call to cache.get().
On the other hand, I don't see what they buy you here as you only modify one element.
The problem is that I don't want to do the business job twice, it is a business constraint. So, I think that I need a kind of locking; this is why I did write-locking isolation on the job key.
|
|
|
 |
![[Post New]](/forums/templates/default/images/icon_minipost_new.gif) 08/08/2012 07:12:40
|
lorban
master
Joined: 01/08/2010 13:09:16
Messages: 98
Location: CET
Offline
|
In transaction, does a commited value is obtained on every get call in the transaction of all commited values are pre-calculated at the beginning of the transaction ?
You always get the latest committed value when you call cache.get(). This means that if you call cache.get() multiple time within a transaction you could very well get different values.
The problem is that I don't want to do the business job twice, it is a business constraint. So, I think that I need a kind of locking; this is why I did write-locking isolation on the job key.
I understand your use of write-locking, but not of transactions as you only modify a single element.
By the way, did you notice that if your application crashes after the job is done but before cache.replace() is executed, you job could be executed twice?
|
Ludovic Orban (Terracotta engineer) |
|
|
 |
![[Post New]](/forums/templates/default/images/icon_minipost_new.gif) 08/08/2012 07:26:25
|
chrismas
journeyman
Joined: 07/27/2012 01:16:24
Messages: 27
Offline
|
I understand your use of write-locking, but not of transactions as you only modify a single element.
You're right on my little example; but in my code I manipulate two Elements in two different caches. This is why I used transactions to guarantee the coherence between the two caches.
By the way, did you notice that if your application crashes after the job is done but before cache.replace() is executed, you job could be executed twice?
You're right too, this may occur. I can just minimize it by using synchronization mecanisms.
|
|
|
 |
![[Post New]](/forums/templates/default/images/icon_minipost_new.gif) 08/08/2012 07:32:15
|
chrismas
journeyman
Joined: 07/27/2012 01:16:24
Messages: 27
Offline
|
By the way, I will follow as possible your first advice: trying to not use transactions.
I will try to modify my use-case in this way.
|
|
|
 |
![[Post New]](/forums/templates/default/images/icon_minipost_new.gif) 08/09/2012 08:27:38
|
chrismas
journeyman
Joined: 07/27/2012 01:16:24
Messages: 27
Offline
|
So I modified my use-case in order to not use transactions.
For this use-case, I now use one cache.
The use-case do:
Code:
- Test if a key exists
- write-lock a key
- put a new element in cache
- release write-lock
The cache configuration is:
<cache name="A"
maxEntriesLocalHeap="100"
eternal="true"
transactionalMode="off"
overflowToDisk="false">
<searchable keys="false" values="false">
<!-- I use 5 search attributes -->
</searchable>
<terracotta clustered="true" consistency="strong" synchronousWrites="true" />
</cache>
For my test, I run a sequential loop of this use-case (1000 times). The Terracotta cluster is freshly created.
The time cost for the use-case is 4ms/use-case (4000ms for the total test) with terracotta server launched on the same machine of the ehcache client.
If I move the Terracotta server on a different machine, the time cost is 10ms/use-case.
If I turn off synchronousWrites, performances are almost the same.
I was hoping for shorter processing time. How can I optimize my configuration ?
|
|
|
 |
|
|