First a tip.  Next time the server locks up, immediately do a thread dump.  

 - http://docs.oracle.com/javase/1.5.0/docs/tooldocs/share/jstack.html

Second, it sounds like this locking issue isn't a "threading" issue, but a 
transaction issue.  Accessing all your databases in the same JTA transaction is 
not advised unless you're doing something like withdrawing $100 from database A 
and putting it in database B.  This kind of work is fine to do, but you want it 
to be as focused and razor sharp as possible -- only do it with the 
understanding you're locking the referenced tables/rows on both databases while 
that transaction is open.  This can be tragic if pessimistic locking is used, 
less of a problem with more optimistic locking options.  These options are all 
database specific.  Again, this kind of thing is fine if the task requires it 
-- there's no other reliable way to solve the "transfer data from one database 
to the next problem" other then to enroll them both in a JTA transaction -- but 
such a thing must be done with full understanding of the cost.

What kind of work are you attempting to do with this job that accesses all your 
databases?


-David

On Dec 11, 2012, at 8:40 AM, "Howard W. Smith, Jr." <smithh032...@gmail.com> 
wrote:

> Okay, TomEE committers/users, I need your help/advice on this one. Please
> read what I wrote in the email below.
> 
> I am considering to use the @Asynchronous on one of the methods on
> @Stateless EJB to complete this task, but I think I still may need to do
> something on the Persistence end to avoid locking up the entire app,
> database, etc...
> 
> I guess this my first time experiencing a DEADLOCK, but I could be wrong. :)
> 
> 
> 
> On Tue, Dec 11, 2012 at 11:01 AM, Howard W. Smith, Jr. <
> smithh032...@gmail.com> wrote:
> 
>> Wow, i'm reading this now, because I just experienced an issue on my
>> production server that is TomEE 1.5.1 (Tomcat 7.0.34), and the whole server
>> locked up all because I had a @Stateless EJB inserting data into multiple
>> tables in the database, because @Schedule timed event triggered the EJB to
>> check email server for incoming (customer) requests, and it literally took
>> down the server. I was on it as well as few other endusers, and then one
>> enduser captured a LOCK error and the screen capture (photo/pic) had an
>> error message that showed a long SQL query with datatable table and column
>> names t0..., t0...
>> 
>> What I primarily saw was the word 'lock' at the top of that, and we
>> definitely experienced a lockup. I'm about to check server logs and read
>> this article.
>> 
>> The @Stateless EJB had one transaction (entitymanager / persistence
>> context) that made database updates to multiple tables in the database. I
>> am only using entitymanager.persist(), flush(), and few lookups/queries
>> during that process.
>> 
>> But other endusers (including myself) could not do simple queries against
>> the database at all. Most of my queries contain query hints (readonly,
>> statement caching).
>> 
>> Also, I never seen this behavior at all, but this is first time I added
>> @Stateless EJB along with @Schedule that does database updates 'during
>> business hours'. I thought this would be a no-brainer, but I guess it's
>> not. Again, the server is TomEE 1.5.1 (tomcat 7.0.34).
>> 
>> Any advise, then please let me know. Onto reading this post now. Thanks. :)
>> 
>> 
>> 
>> On Tue, Dec 11, 2012 at 10:49 AM, Julien Martin <bal...@gmail.com> wrote:
>> 
>>> Thank you very much for this exhaustive reply Christopher.
>>> 
>>> 2012/12/11 Christopher Schultz <ch...@christopherschultz.net>
>>> 
>>>> -----BEGIN PGP SIGNED MESSAGE-----
>>>> Hash: SHA256
>>>> 
>>>> Julien,
>>>> 
>>>> Warning: this is long. Like, André-or-Mark-Eggers long.
>>>> 
>>>> On 12/11/12 7:30 AM, Julien Martin wrote:
>>>>> I am in reference to the following blog entry: Blog
>>>>> entry<
>>>> 
>>> http://blog.springsource.org/2012/05/06/spring-mvc-3-2-preview-introducing-servlet-3-async-support
>>>>> 
>>>>> 
>>>>> 
>>>> about Spring MVC 3.2 asynchronous support.
>>>>> 
>>>>> I understand Tomcat uses a thread pool in order to serve http/web
>>>>> requests. Furthermore, the above article seems to indicate that
>>>>> Spring MVC asynchronous support relieves Tomcat's thread pool and
>>>>> allows for better concurrency in the webapp by using background
>>>>> threads for "heavy-lift" operations.
>>>> 
>>>> I believe you are misinterpreting what that post has to say. It's not
>>>> that a "background" thread itself is more efficient, it's that
>>>> processing that does not need to communicate with the client can be
>>>> de-coupled from the request-processing thread-pool that exists for
>>>> that purpose.
>>>> 
>>>> An example - right from the blog post - will make much more sense than
>>>> what I wrote above. Let's take the example of sending an email
>>>> message. First, some assumptions:
>>>> 
>>>> 1. Sending an email takes a long time (say, 5 seconds)
>>>> 2. The client does not need confirmation that the email has been sent
>>>> 
>>>> If your were to write a "classic" servlet, it would look something
>>>> like this:
>>>> 
>>>> doPost() {
>>>>  validateOrder();
>>>> 
>>>>  queueOrder();
>>>> 
>>>>  sendOrderConfirmation(); // This is the email
>>>> 
>>>>  response.sendRedirect("/order_complete.jsp");
>>>> }
>>>> 
>>>> Let's say that validation takes 500ms, queuing takes 800ms, and
>>>> emailing (as above) takes 5000ms. That means that the request, from
>>>> the client perspective, takes 6300ms (6.3 sec). That's a noticeable
>>> delay.
>>>> 
>>>> Also, during that whole time, a single request-processing thread (from
>>>> Tomcat's thread pool) is tied-up, meaning that no other requests can
>>>> be processed by that same thread.
>>>> 
>>>> If you have a thread pool of size=1 (foolish, yet instructive), it
>>>> means you can only process a single transaction every 6.3 seconds.
>>>> 
>>>> Lets re-write the servlet with a background thread -- no
>>>> "asynchronous" stuff from the servlet API, but just with a simple
>>>> background thread:
>>>> 
>>>> doPost() {
>>>>  validateOrder();
>>>> 
>>>>  queueOrder();
>>>> 
>>>>  (new Thread() {
>>>>    public void run() {
>>>>      sendOrderConfirmation();
>>>>    }
>>>>  }).start();
>>>> 
>>>>  response.sendRedirect("order_complete.jsp");
>>>> }
>>>> 
>>>> So, now the email is being sent by a background thread: the response
>>>> returns to the client after 1.3 seconds which is a significant
>>>> improvement. Now, we can handle a request once every 1.3 seconds with
>>>> a request-processing thread-pool of size=1.
>>>> 
>>>> Note that a better implementation of the above would be to use a
>>>> thread pool for this sort of thing instead of creating a new thread
>>>> for every request. This is what Spring provides. It's not that Spring
>>>> can do a better job of thread management, it's that Tomcat's thread
>>>> pool is special: it's the only one that can actually dispatch client
>>>> requests. Off-loading onto another thread pool for background
>>>> processing means more client requests can be handled with a smaller
>>>> (or same-sized) pool.
>>>> 
>>>> Looking above, you might notice that the validateOrder() and
>>>> queueOrder() processes still take some time (1.3 seconds) to complete,
>>>> and there is no interaction with the client during that time -- the
>>>> client is just sitting there waiting for a response. Work is still
>>>> getting done on the server, of course, but there's no real reason that
>>>> the request-processing thread has to be the one doing that work: we
>>>> can delegate the entire thing to a background thread so the
>>>> request-processor thread can get back to dispatching new requests.
>>>> 
>>>> This is where servlet 3.0 async comes into play.
>>>> 
>>>> Let's re-write the servlet as an asynchronous one. I've never actually
>>>> written one, so I'm sure the details are going to be wrong, but the
>>>> idea is the same. This time, we'll do everything asynchronously.
>>>> 
>>>> doPost() {
>>>>  final AsyncContext ctx = request.startAsync();
>>>> 
>>>>  (new Thread() {
>>>>    public void run() {
>>>>      validateOrder();
>>>>      queueOrder();
>>>>      sendOrderConfirmation();
>>>> 
>>>>      ctx.getResponse().sendRedirect("/order_complete.jsp");
>>>> 
>>>>      ctx.complete();
>>>>    }
>>>>  }).start();
>>>> }
>>>> 
>>>> So, how what happens? When startAsync is called, an AsyncContext is
>>>> created and basically the request and response are packaged-up for
>>>> later use. The doPost method creates a new thread and starts it (or it
>>>> may start a few ms later), then returns from doPost. At this point,
>>>> the request-processor thread has only spent a few ms (let's say 5ms)
>>>> setting up the request and then it goes back into Tomcat's thread-pool
>>>> and can accept another request. Meanwhile, the "background" thread
>>>> will process the actual transaction.
>>>> 
>>>> Let's assume that nothing in the run() method above interacts in any
>>>> way with the client. In the first example (no async), the client waits
>>>> the whole time for a response from the server, and the
>>>> request-processing thread does all the work. So, the client waits 6.3
>>>> seconds and the request-processing thread is "working" for 6.3 seconds.
>>>> 
>>>> In the async example, the client will probably still wait 6.3 seconds,
>>>> but the request-processing thread is back and ready for more client
>>>> requests after a tiny amount of time. Of course, the transaction is
>>>> not complete, yet.
>>>> 
>>>> The background thread will run and process the transaction, including
>>>> the 5-second email process. Once the email confirmation has been sent,
>>>> the background thread "sends" a redirect and completes the async
>>>> request. I'm not sure of the exact details, here, but either the
>>>> background thread itself (via getRequest().sendRedirect()) pushes the
>>>> response back to the client, or Tomcat fetches a request-processing
>>>> thread from the pool and uses that to do the same thing. I can't see
>>>> why the background-thread wouldn't do that itself, but it's up to the
>>>> container to determine who does what.
>>>> 
>>>> The point is that, when using asynchronous requests, fewer
>>>> request-processing threads can handle a whole lot of load. In the
>>>> async example, still with a thread-pool of size=1 and an async-setup
>>>> time of 5ms, that means that you can handle one client transaction
>>>> every 5ms. That's much better than every 6.3 seconds, don't you think?
>>>> 
>>>> (Note that this isn't magic: if your background threads are either
>>>> limited or your system can't handle the number of transactions you are
>>>> trying to asynchronously-process, eventually you'll still have
>>>> everyone waiting 6.3 seconds no matter what).
>>>> 
>>>> So, a recap of throughput (req/sec) of the above 3 implementations:
>>>> 
>>>> Standard:      .15873
>>>> Background:    .76923
>>>> Async:      200.00000
>>>> 
>>>> Using asynchronous dispatching can improve our throughput a huge
>>>> number of times.
>>>> 
>>>> It's worth repeating what I said earlier: if your server can't
>>>> actually handle this much load (200 emails per second, let's say),
>>>> then using asych isn't going to change anything. Honestly, this trick
>>>> only works when you have a lot of heterogeneous requests. For example,
>>>> maybe 10% of your traffic is handling orders as implemented above,
>>>> while the rest of your traffic is for much smaller sub-500ms-requests.
>>>> There's probably no reason to convert those short-running requests
>>>> into asynchronous operations. Only long-running processes with no
>>>> client interaction make any sense for this. If only 10% of your
>>>> requests are orders, that means that maybe you can process 20 orders
>>>> and 190 "small" requests per second. That's much better than, say,
>>>> waiting 6.3 seconds for a single order and then processing a single
>>>> short request, then another order and so on.
>>>> 
>>>> Just remember that once all request-processing threads are tied-up
>>>> doing something, everyone else waits in line. Asynchronous request
>>>> dispatching aims to run through the line as quickly as possible. It
>>>> does *not* improve the processing time of any one transaction.
>>>> 
>>>> - -chris
>>>> -----BEGIN PGP SIGNATURE-----
>>>> Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
>>>> Comment: GPGTools - http://gpgtools.org
>>>> Comment: Using GnuPG with undefined - http://www.enigmail.net/
>>>> 
>>>> iEYEAREIAAYFAlDHTdkACgkQ9CaO5/Lv0PDrNACgsaeHmBzr9RMSFuZX9ksX3g9d
>>>> bKYAniJzbqRjGBAjwxIYihvcyJYV5rIl
>>>> =l+ie
>>>> -----END PGP SIGNATURE-----
>>>> 
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
>>>> For additional commands, e-mail: users-h...@tomcat.apache.org
>>>> 
>>>> 
>>> 
>> 
>> 

Reply via email to