JAVA EE CONCURRENCY MISCONCEPTIONS
Haim Yadid, Performize-IT Ltd.
Daniel Pfeifer, Whistler AB
Daniel Pfeifer

‣ Founder of
Performize-IT Ltd.
‣ 18+ years in
technology
‣ Primary expertise in
performance optimization
...
JAVA EE IN THE MULTIPROCESSOR ERA
OPTIMISM

Moore’s Law:
The amount of transistors
appx. doubles every second
year
JAVA EE IN THE FUTURE

That’s why Multi core
hardware will become
mainstream for JEE servers
18"
16"
14"
12"
10"

CPUs/server"

8"

CPUs/phone"

6"

CPUs/notebook"

4"
2"
0"
2006"

2008"

2010"

2012"

IS MULTICORE ...
A FRIENDLY ADVICE

Don’t do it yourself !!
There is an App Server for that
TOOLS OF TRADE

‣ ”Local" and cluster-wide load balancing	
‣ Message driven beans for parallelization / async tasks	
‣ Asy...
6 REAL LIFE EXAMPLES
SYNCHRONIZATION IN EJB
You found yourself in need of sharing some data between calls so you
‣ Create a static constant pointing to a List (or per...
@Stateless
public class SharedStateEJB {
private static final List usedNumbers = new ArrayList();
public double fetchUnuse...
Sharing state like this will not work, because …
‣ Static constants are not shared among class loaders
‣ A lock will not i...
SYNCHRONIZATION IN ENTERPRISE BEANS

What about Java EE Singleton?
@Singleton
public class UsedNumbersBean {
private final List usedNumbers = new ArrayList();
@Lock(READ)
public boolean num...
“Backup” solutions
‣ Use the database and use locking => Potentially slow
‣ Use a cluster-aware cache (i.e. EHCache or JBo...
ASYNCHRONICITY THROUGH THREADS
•  You processed an order
•  You ask the bank for settlement confirmation
•  You can present the customer with a result wi...
@Stateless
public class OrderHandlingBean {
public String process(final Order order) {
String orderId = ...//save order to...
‣ Enough stuck Threads will eventually make your server go OOM.
‣ Difficult to get transaction management right.
‣  Some s...
1.8
1.6

Response Time

1.4
1.2
1

java.lang.OutOfMemoryError: unable to create
new native thread
Async

0.8

Sync

0.6
0....
‣ Until Java EE 6 Message Driven Beans are used for asynchronous
tasks.
‣ And if you are lucky enough to use a Java EE 6 c...
@Stateless(name = ”QueueingEJB")
public class QueueingBean {
@Resource private Queue q;
@Resource private ConnectionFactor...
@MessageDriven(name = “PayEJB”,
activationProperties = {
/* activation properties for your server */
})
public class PayBe...
@Stateless(name = ”PayEJB")
public class PayBean{
@Asynchronous
public void callBank(final String payment) {
// Hello, ......
@Stateless(name = ”AsyncCallerEJB")
public class AsyncCallerBean {
@EJB private PayBean payBean;
public String process(fin...
We mentioned transactions…
‣ True, our examples won’t use the same Transaction, but…
‣  @Asynchronous will by spec create ...
PARALLELISM WITH THREAD POOLS
Your back-office staff fires off a bunch of invoices and you want the
total as fast as possible, so you…
‣ Create a thread...
private static class OrderCallable implements Callable<Double> {
private final Order order;
public OrderCallable(Order ord...
public double processOrders(List<Order> orders) {
ExecutorService executorService =
Executors.newFixedThreadPool(10);
List...
Essentially we got the same problems as previously, but…
‣ Potential for much larger thread leaks
‣ Still not covered by t...
‣ Up to and including Java EE 5 you can use MDBs
‣  Queues can be clustered, so other servers can take some of the
load.
‣...
Using @Asynchronous (invokee)
@Stateless
@Asynchronous
public class ProcessBean {
public Future<Double> getTotals(Order or...
@Stateless public class OrderBean {
@EJB private ProcessBean processBean;
public double parallelizeCalculationAsync(List<O...
@Stateless public class OrderBean {
@Resource(mappedName = “ConnectionFactory”) private ConnectionFactory cf;
@Resource(ma...
@MessageDriven(mappedName = “RequestQ”)
public class ProcessOrderBean implements MessageListener {
@Resource(mappedName = ...
PARALLELISM WITH THREADPOOLS

A nice write up, but is it worth it?
12000
10000
8000
1 user

6000

10 users
20 users

4000
2000
0
Serial

8 parallel

PARALLELISM WITH THREADPOOLS

Response t...
FORK AND KNIVES… UHM… JOIN
‣ New to Java 7 java.util.concurrent
‣ Helps you write a parallel recursive algorithm
‣ Break a long task to Fine grained ...
ForkJoinTask

FORK JOIN

Introduction

ForkJoinPool

Worker
Worker
Worker

Worker
class PartialTask extends RecursiveAction {
protected void compute() {
PartialTask pt1 = new PartialTask(firstHalf);
Parti...
‣ Divide n points into k clusters
‣ Based on proximity

FORK JOIN

A Benchmark K-Means Clustering Algorithm
‣ This is not a formal benchmark
‣ I tried to do my best but it is not community criticized
‣ Ran on 8 core machine (no HT...
FORK JOIN

Response Time – by amount of parallelism
6000"

5000"

Time%(sec)%

4000"

3000"
Time"
2000"

1000"

0"
1"

2"
...
FORK JOIN

Speedup– by amount of parallelism
6"

5"

Time%(sec)%

4"

3"
Speedup"
2"

1"

0"
1"

2"

3"

4"

5"
#cores%use...
FORK JOIN

Single Operation Throughput

Op/sec'
1"
0.8"
0.6"
Op/sec"

0.4"
0.2"
0"
1"

2"

3"

4"

5"

6"

7"

8"
‣ Does your server need to do anything else ?
‣ Selfish Task Deplete all compute resources slows other task
‣ What about t...
FORK JOIN

What About Throughput ?
Lets check !
‣ What will be better

FORK JOIN

Throughput of 8 Concurrent Users
FORK JOIN

Throughput 8 concurrent users in parallel

Op/sec'
1.8"
1.6"
1.4"
1.2"
1"
0.8"
0.6"
0.4"
0.2"
0"

Op/sec"

Seri...
FORK JOIN

Response Time

9000"
8000"
7000"
6000"
5000"
4000"
3000"
2000"
1000"
0"

TRT"of"8"Users"
TRT"of"1"User"

Serial...
‣ Use FJ for the non common case
‣ Limit the number of cores do not starve other server tasks

FORK JOIN

Conclusion
LOAD MANAGEMENT FOR BACKEND ACCESS
You have a backend machine that can only handle 20 concurrent
requests and you have a cluster of four servers, so you…
‣ C...
‣ The backend server can be under-utilized across the cluster.
‣  First server could be full of locks while second is free...
Using the Request-Reply Pattern (EIP), using:
‣ Clustered queues (request + response)
‣ A caller (stateless session bean)
...
@Stateless public class DispatcherBean {
@Resource(mappedName = “ConnectionFactory”) private ConnectionFactory cf;
@Resour...
@MessageDriven(mappedName = “RequestQ”)
public class BackendInvokerBean implements MessageListener {
@Resource(mappedName ...
Vendor-specific, but in general:
‣ You may set an upper limit on consumers
‣  Glassfish has maxNumActiveConsumers
‣ You ma...
LOAD MANAGEMENT FOR BACKEND ACCESS

Isn’t MDB horribly slow?
12
10
8
1 user

6

5 users
10 users

4
2
0
Direct

MDB

LOAD MANAGEMENT FOR BACKEND ACCESS

Response time (in milliseconds...
INTERFERING WITH BEAN POOL
You occasionally suffer from resource depletion so to protect your
server you:
‣ Create an EJB Interceptor that
‣  checks ...
‣ Is there always equal load distribution across all tasks?
‣ Intelligent load balancers may continue to shoot at the wron...
Leave pool management to the server, pool sizes:
‣ Can be tuned on a global level
‣  Right strategy (infinite thread pools...
It can be configured through the GUI…(Glassfish example)

INTERFERING WITH BEAN POOL

Leave Management to the app server
<glassfish-ejb-jar>
<enterprise-beans>
<ejb>
<ejb-name>AnEJB</ejb-name>
<bean-pool>
<steady-pool-size>10</steady-pool-size...
CONCLUSION
CONCLUSION

‣ Most mistakes stem from misunderstanding the app server, try to
understand your app server’s OOTB-capabiliti...
QUESTIONS?
haim.yadid@gmail.com

Daniel Pfeifer
danpfe@gmail.com

CONTACT INFO

Haim Yadid
Upcoming SlideShare
Loading in …5
×

Java Enterprise Edition Concurrency Misconceptions

1,749 views

Published on

A session given by Daniel Pfeifer and myself on JavaOne 2011

Published in: Technology, Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,749
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
11
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Java Enterprise Edition Concurrency Misconceptions

  1. 1. JAVA EE CONCURRENCY MISCONCEPTIONS Haim Yadid, Performize-IT Ltd. Daniel Pfeifer, Whistler AB
  2. 2. Daniel Pfeifer ‣ Founder of Performize-IT Ltd. ‣ 18+ years in technology ‣ Primary expertise in performance optimization ‣ Founder of Whistler AB ‣ 10+ years in IT ‣ Primary expertise in missioncritical business applications WHO ARE THOSE GUYS? Haim Yadid
  3. 3. JAVA EE IN THE MULTIPROCESSOR ERA
  4. 4. OPTIMISM Moore’s Law: The amount of transistors appx. doubles every second year
  5. 5. JAVA EE IN THE FUTURE That’s why Multi core hardware will become mainstream for JEE servers
  6. 6. 18" 16" 14" 12" 10" CPUs/server" 8" CPUs/phone" 6" CPUs/notebook" 4" 2" 0" 2006" 2008" 2010" 2012" IS MULTICORE NEW TO JAVA EE? Budget machines
  7. 7. A FRIENDLY ADVICE Don’t do it yourself !!
  8. 8. There is an App Server for that
  9. 9. TOOLS OF TRADE ‣ ”Local" and cluster-wide load balancing ‣ Message driven beans for parallelization / async tasks ‣ Asynchronous annotations ‣ Automatic and bean managed concurrency ‣ Resource management
  10. 10. 6 REAL LIFE EXAMPLES
  11. 11. SYNCHRONIZATION IN EJB
  12. 12. You found yourself in need of sharing some data between calls so you ‣ Create a static constant pointing to a List (or perhaps your own singleton) ‣ Add a synchronization block for your constant ‣ You operate on your instance inside the synchronize-block SYNCHRONIZATION IN ENTERPRISE BEANS Use Case
  13. 13. @Stateless public class SharedStateEJB { private static final List usedNumbers = new ArrayList(); public double fetchUnusedRandomNumber() { double number = 0d; synchronized (usedNumbers) { while (true) { number = Math.random(); if (!usedNumbers.contains(number)) { usedNumbers.add(number); break; } } } return number; } } SYNCHRONIZATION IN ENTERPRISE BEANS Returning unused random numbers
  14. 14. Sharing state like this will not work, because … ‣ Static constants are not shared among class loaders ‣ A lock will not is not propagated across machines SYNCHRONIZATION IN ENTERPRISE BEANS Problems
  15. 15. SYNCHRONIZATION IN ENTERPRISE BEANS What about Java EE Singleton?
  16. 16. @Singleton public class UsedNumbersBean { private final List usedNumbers = new ArrayList(); @Lock(READ) public boolean numberExists(double num) { return usedNumbers.contains(num); } @Lock(WRITE) public void addNumber(double num) { usedNumbers.add(num); } } SYNCHRONIZATION IN ENTERPRISE BEANS @Singleton
  17. 17. “Backup” solutions ‣ Use the database and use locking => Potentially slow ‣ Use a cluster-aware cache (i.e. EHCache or JBoss Cache) ‣  Read the chapters on clusters and consistency! ‣ Terracotta “Creative” solutions ‣ Use a single EJB ‣ Use H/A Singleton (available on JBoss) ‣ Wait for the future… SYNCHRONIZATION IN ENTERPRISE BEANS Suggestions
  18. 18. ASYNCHRONICITY THROUGH THREADS
  19. 19. •  You processed an order •  You ask the bank for settlement confirmation •  You can present the customer with a result without waiting for the bank ASYNCHRONICITY THROUGH THREADS Use Case
  20. 20. @Stateless public class OrderHandlingBean { public String process(final Order order) { String orderId = ...//save order to database and get id final Thread t = new Thread() { @Override public void run() { // submit amount to bank } }; t.start(); // start “background” process return orderId; } } ASYNCHRONICITY THROUGH THREADS Creating a thread for async tasks
  21. 21. ‣ Enough stuck Threads will eventually make your server go OOM. ‣ Difficult to get transaction management right. ‣  Some servers will tell you it can’t check the status, some don’t. ‣  Failed tasks in the thread need difficult manual rollback. ‣ Threads do not scale out ‣  Can’t be load-balanced to other machines. ‣  Server’s automatic resource management doesn’t cover your own threads. ‣ Debugging and monitoring isn’t the joy it used to be. ASYNCHRONICITY THROUGH THREADS Problems
  22. 22. 1.8 1.6 Response Time 1.4 1.2 1 java.lang.OutOfMemoryError: unable to create new native thread Async 0.8 Sync 0.6 0.4 0.2 0 1h 4h 7h 10h 13h Runtime 16h 19h ASYNCHRONICITY THROUGH THREADS Thread bugs gone wild
  23. 23. ‣ Until Java EE 6 Message Driven Beans are used for asynchronous tasks. ‣ And if you are lucky enough to use a Java EE 6 container, you can use the new @Asynchronous. ASYNCHRONICITY THROUGH THREADS Best Practice Alternatives
  24. 24. @Stateless(name = ”QueueingEJB") public class QueueingBean { @Resource private Queue q; @Resource private ConnectionFactory cf; public String process(final Order order) { // ... saving the Order to the database and fetching id Connection cn = connectionFactory.createConnection(); Session s = cn.createSession(true, AUTO_ACKNOWLEDGE); MessageProducer producer = s.createProducer(queue); Message msg = s.createTextMessage(payment); producer.send(msg); return orderId; } } Don’t forget clean-up! We just want to conserve screen estate! ASYNCHRONICITY THROUGH THREADS Using Queues
  25. 25. @MessageDriven(name = “PayEJB”, activationProperties = { /* activation properties for your server */ }) public class PayBean implements MessageListener { public void onMessage(Message m) { // Calling bank... } } ASYNCHRONICITY THROUGH THREADS Using Queues
  26. 26. @Stateless(name = ”PayEJB") public class PayBean{ @Asynchronous public void callBank(final String payment) { // Hello, ... Bank! } } ASYNCHRONICITY THROUGH THREADS Using @Asynchronous
  27. 27. @Stateless(name = ”AsyncCallerEJB") public class AsyncCallerBean { @EJB private PayBean payBean; public String process(final Order order) { // ... saving the Order to the database and fetching id payBean.callBank(payment); return orderId; // <- Returns + transaction OK } } That’s All!!! ASYNCHRONICITY THROUGH THREADS Using @Asynchronous
  28. 28. We mentioned transactions… ‣ True, our examples won’t use the same Transaction, but… ‣  @Asynchronous will by spec create a Transaction (REQUIRES_NEW) ‣  MDBs will also create a transaction ASYNCHRONICITY THROUGH THREADS A note for the observant
  29. 29. PARALLELISM WITH THREAD POOLS
  30. 30. Your back-office staff fires off a bunch of invoices and you want the total as fast as possible, so you… ‣ Create a thread-pool ‣ Push all invoices for calculation to the thread-pool ‣ Wait for the answer and return it PARALLELISM WITH THREADPOOLS Use Case
  31. 31. private static class OrderCallable implements Callable<Double> { private final Order order; public OrderCallable(Order order) { this.order = order; } @Override public Double call() throws Exception { // return the total based on the order that’s been // provided. } } PARALLELISM WITH THREADPOOLS Parallelizing with a ThreadPool (our Callable)
  32. 32. public double processOrders(List<Order> orders) { ExecutorService executorService = Executors.newFixedThreadPool(10); List<Future<Double>> futures = new ArrayList<>(); for (Order order : orders) { OrderCallable callable = new OrderCallable (order); callables.add(callable); futures.add(executorService.invoke (callable)); } double totalValue = 0; try { for (Future<Double> future : futures) { totalValue += future.get(10, SECONDS); } } catch (TimeoutException e) { return -1; } return totalValue; } PARALLELISM WITH THREADPOOLS Parallelizing with a ThreadPool (using the Callable in an ExecutorService)
  33. 33. Essentially we got the same problems as previously, but… ‣ Potential for much larger thread leaks ‣ Still not covered by transaction ‣ Executors, just like Threads, won’t run tasks on other machines. ‣ There is nothing H/A about this. ‣  On crash, part or all of the workload is gone. ‣  Can’t be resumed on server restart, it’s just gone… PARALLELISM WITH THREADPOOLS Problems
  34. 34. ‣ Up to and including Java EE 5 you can use MDBs ‣  Queues can be clustered, so other servers can take some of the load. ‣ @Asynchronous-annotated method returning Future PARALLELISM WITH THREADPOOLS Pure Java EE alternatives
  35. 35. Using @Asynchronous (invokee) @Stateless @Asynchronous public class ProcessBean { public Future<Double> getTotals(Order order) { double value = // .. Calculate value; return new AsyncResult<Double>(value); } }
  36. 36. @Stateless public class OrderBean { @EJB private ProcessBean processBean; public double parallelizeCalculationAsync(List<Order> orders) { List<Future<Double>> futures = new ArrayList<>(); for (Order order : orders) { futures.add(processBean.getTotals(order)); } double totalValue = 0; try { for (Future<Double> future : futures) { totalValue += future.get(10, SECONDS); } } catch (Exception e) { // ignore } return totalValue; } } PARALLELISM WITH THREADPOOLS Using @Asynchronous (invoker)
  37. 37. @Stateless public class OrderBean { @Resource(mappedName = “ConnectionFactory”) private ConnectionFactory cf; @Resource(mappedName = “RequestQ”) private Destination sendQueue; @Resource(mappedName = “ResponseQ”) private Destination responseQueue; @TransactionAttribute(NOT_SUPPORTED) // or UserTransaction public double handleOrders(List<Order> orders) { try { // …create a producer for (Order o : orders) { ObjectMessage outgoing = s.createObjectMessage(); outgoing.setObject(o); outgoing.setLongProperty(“RequestID”, orders.hashCode()) mp.send(outgoing); } cn.start(); // must be started, otherwise we can't receive MessageConsumer mc = s.createConsumer(responseQueue, "JMSCorrelationID = '" + orders.hashCode() + "'"); double totalValue = 0; for (int i = 0; i < orders.length(); i++) totalValue += mc.receive(10, SECONDS).getDoubleProperty(“OrderValue”); return totalValue; } catch (JMSException e) { throw new EJBException(e); } } } Send Receive PARALLELISM WITH THREADPOOLS Using MDB (invoker)
  38. 38. @MessageDriven(mappedName = “RequestQ”) public class ProcessOrderBean implements MessageListener { @Resource(mappedName = “ConnectionFactory") private ConnectionFactory cf; @Resource(mappedName = “ResponseQ") private Queue responseQueue; public void onMessage(Message message) { double orderValue = // ... Process order try { MessageProducer mp = // … create message producer Message msg = s.createMessage(); msg.setJMSCorrelationID(message.getIntProperty(“RequestID”)); msg.setDoubleProperty(”OrderValue”, orderValue); mp.send(msg); } catch (JMSException e) { throw new EJBException(e); } } } PARALLELISM WITH THREADPOOLS Using MDB (invokee)
  39. 39. PARALLELISM WITH THREADPOOLS A nice write up, but is it worth it?
  40. 40. 12000 10000 8000 1 user 6000 10 users 20 users 4000 2000 0 Serial 8 parallel PARALLELISM WITH THREADPOOLS Response time – Compute intensive Tasks
  41. 41. FORK AND KNIVES… UHM… JOIN
  42. 42. ‣ New to Java 7 java.util.concurrent ‣ Helps you write a parallel recursive algorithm ‣ Break a long task to Fine grained tasks ‣ Very efficient for relatively short tasks FORK JOIN Introduction
  43. 43. ForkJoinTask FORK JOIN Introduction ForkJoinPool Worker Worker Worker Worker
  44. 44. class PartialTask extends RecursiveAction { protected void compute() { PartialTask pt1 = new PartialTask(firstHalf); PartialTask pt2 = new PartialTask(secondHalf); pt1.fork(); // fork pt2.exec(); // execute in new thread pt1.join(); // wait for completion } } fjPool = new ForkJoinPool(para); Para.invoke(task) FORK JOIN Example
  45. 45. ‣ Divide n points into k clusters ‣ Based on proximity FORK JOIN A Benchmark K-Means Clustering Algorithm
  46. 46. ‣ This is not a formal benchmark ‣ I tried to do my best but it is not community criticized ‣ Ran on 8 core machine (no HT) ‣ Windows OS ‣ Warm-up was taken into account J ‣ 120K points to 50 clusters FORK JOIN Disclaimer
  47. 47. FORK JOIN Response Time – by amount of parallelism 6000" 5000" Time%(sec)% 4000" 3000" Time" 2000" 1000" 0" 1" 2" 3" 4" 5" #cores%used% 6" 7" 8"
  48. 48. FORK JOIN Speedup– by amount of parallelism 6" 5" Time%(sec)% 4" 3" Speedup" 2" 1" 0" 1" 2" 3" 4" 5" #cores%used% 6" 7" 8"
  49. 49. FORK JOIN Single Operation Throughput Op/sec' 1" 0.8" 0.6" Op/sec" 0.4" 0.2" 0" 1" 2" 3" 4" 5" 6" 7" 8"
  50. 50. ‣ Does your server need to do anything else ? ‣ Selfish Task Deplete all compute resources slows other task ‣ What about throughput FORK JOIN FJ on a JEE Server
  51. 51. FORK JOIN What About Throughput ? Lets check !
  52. 52. ‣ What will be better FORK JOIN Throughput of 8 Concurrent Users
  53. 53. FORK JOIN Throughput 8 concurrent users in parallel Op/sec' 1.8" 1.6" 1.4" 1.2" 1" 0.8" 0.6" 0.4" 0.2" 0" Op/sec" Serial"Algorithm" Fork"Join" Parallelism"1" Fork"Join" Parallelism"8"
  54. 54. FORK JOIN Response Time 9000" 8000" 7000" 6000" 5000" 4000" 3000" 2000" 1000" 0" TRT"of"8"Users" TRT"of"1"User" Serial" Algorithm" Fork"Join" Fork"Join" Parallelism"1" Parallelism"8"
  55. 55. ‣ Use FJ for the non common case ‣ Limit the number of cores do not starve other server tasks FORK JOIN Conclusion
  56. 56. LOAD MANAGEMENT FOR BACKEND ACCESS
  57. 57. You have a backend machine that can only handle 20 concurrent requests and you have a cluster of four servers, so you… ‣ Create a semaphore with five permits. ‣ Acquire lock on semaphore ‣ Call server ‣ Release lock LOAD MANAGEMENT FOR BACKEND ACCESS Use Case
  58. 58. ‣ The backend server can be under-utilized across the cluster. ‣  First server could be full of locks while second is free. ‣ One server can stall unnecessarily long time. ‣ Recompile necessary if some parameter changes. LOAD MANAGEMENT FOR BACKEND ACCESS Problems With This Approach
  59. 59. Using the Request-Reply Pattern (EIP), using: ‣ Clustered queues (request + response) ‣ A caller (stateless session bean) ‣ A backend invoker bean (message-driven bean) ‣ Configuration to limit in-process messages For the advanced: ‣ Write a resource adapter (JCA) ‣  Support load balancing ‣  Support cluster LOAD MANAGEMENT FOR BACKEND ACCESS A Better Approach
  60. 60. @Stateless public class DispatcherBean { @Resource(mappedName = “ConnectionFactory”) private ConnectionFactory cf; @Resource(mappedName = “RequestQ”) private Destination sendQueue; @Resource(mappedName = “ResponseQ”) private Destination responseQueue; @TransactionAttribute(NOT_SUPPORTED) // Alternatively UserTransaction public double checkStockRate(String stockName) { try { //… create producer Message outgoing = s.createMessage(); outgoing.setStringProperty(”StockName", stockName); mp.send(outgoing); Send String correlationId = outgoing.getJMSMessageID(); cn.start(); // must be started, otherwise we can't receive MessageConsumer mc = s.createConsumer(responseQueue, "JMSCorrelationID = '" + correlationId + "'"); Message incoming = mc.receive(10000L); // wait no more than 10 seconds if (incoming != null) { return incoming.getDoubleProperty(”StockPrice"); } else { return Double.MIN_VALUE; } } catch (JMSException e) { throw new EJBException(e); } } } Receive LOAD MANAGEMENT FOR BACKEND ACCESS Request-Reply Pattern using clustered queues (Caller SLSB)
  61. 61. @MessageDriven(mappedName = “RequestQ”) public class BackendInvokerBean implements MessageListener { @Resource(mappedName = “ConnectionFactory") private ConnectionFactory cf; @Resource(mappedName = “ResponseQ") private Queue responseQueue; public void onMessage(Message message) { double stockPrice = // ... Fetch from backend service try { // … create producer Message msg = s.createMessage(); msg.setJMSCorrelationID(message.getJMSMessageID()); msg.setDoubleProperty(”StockPrice”, stockPrice); mp.send(msg); } catch (JMSException e) { throw new EJBException(e); } } } LOAD MANAGEMENT FOR BACKEND ACCESS Request-Reply Pattern using clustered queues (Invoker MDB)
  62. 62. Vendor-specific, but in general: ‣ You may set an upper limit on consumers ‣  Glassfish has maxNumActiveConsumers ‣ You may set an upper limit of MDBs in Pool ‣  Works on all servers regardless of vendor (i.e. set max-poolsize to 5 in glassfish-ejb-jar.xml) LOAD MANAGEMENT FOR BACKEND ACCESS Configuration for in-process limitation
  63. 63. LOAD MANAGEMENT FOR BACKEND ACCESS Isn’t MDB horribly slow?
  64. 64. 12 10 8 1 user 6 5 users 10 users 4 2 0 Direct MDB LOAD MANAGEMENT FOR BACKEND ACCESS Response time (in milliseconds)
  65. 65. INTERFERING WITH BEAN POOL
  66. 66. You occasionally suffer from resource depletion so to protect your server you: ‣ Create an EJB Interceptor that ‣  checks current beans in use (i.e. through counter or MBeans) ‣  throws an exception at chosen maximum size. ‣  Or wait until level go down ‣ Assign it to your EJB. INTERFERING WITH BEAN POOL Use Case
  67. 67. ‣ Is there always equal load distribution across all tasks? ‣ Intelligent load balancers may continue to shoot at the wrong target ‣  It’s just an exception… not an overload ‣ DeadLock INTERFERING WITH BEAN POOL Problems
  68. 68. Leave pool management to the server, pool sizes: ‣ Can be tuned on a global level ‣  Right strategy (infinite thread pools, incremental, fixed) ‣  Global default for min/max/timeout ‣ Can be set for each EJB ‣  XML ‣  Annotations (i.e. JBoss) INTERFERING WITH BEAN POOL Better approach
  69. 69. It can be configured through the GUI…(Glassfish example) INTERFERING WITH BEAN POOL Leave Management to the app server
  70. 70. <glassfish-ejb-jar> <enterprise-beans> <ejb> <ejb-name>AnEJB</ejb-name> <bean-pool> <steady-pool-size>10</steady-pool-size> <resize-quantity>10</resize-quantity> <max-pool-size>100</max-pool-size> <pool-idle-timeout-in-seconds> 60 </pool-idle-timeout-in-seconds> </bean-pool> </ejb> </enterprise-beans> </glassfish-ejb-jar> INTERFERING WITH BEAN POOL Through Config Files
  71. 71. CONCLUSION
  72. 72. CONCLUSION ‣ Most mistakes stem from misunderstanding the app server, try to understand your app server’s OOTB-capabilities… ‣ …and the Java EE specification. ‣ If you have a valid case for your own concurrency-related code, make sure it plays well with the container. ‣ Your app server doesn’t always know best, but it often does. And if not, you can often help it understand! ‣ Do not expect your environment to always look the same, it changes quicker than you might think.
  73. 73. QUESTIONS?
  74. 74. haim.yadid@gmail.com Daniel Pfeifer danpfe@gmail.com CONTACT INFO Haim Yadid

×