You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by hernan <hb...@gmail.com> on 2012/02/27 21:04:30 UTC

Limiting concurrent requests by user

Hi,

I'm looking for ideas/suggestions/patterns about limiting concurrent
requests by user. May be you have tackled this kind of problem
previously and I'd like to heard your opinions.


I've a web service. In order to do a request, a user specifies a username
and password via web service parameters along with web service
parameters. The web service server, checks user and password and if it is
correct, then process the request (else response "access denied").

The process may take some seconds or a few minutes to be completed. I'd
like to limit the number of client requests per user.

I'm thinking to mantain some data structure in memory (shared by all tomcat
threads, I don't know how to do that) or in some table in the database to
count the number of requests per user. For each received request, if
accepted, increments the counter, and when the process finishes (or if the
process fails) decrements the counter. In order to do that, I think I need
to have a singleton class and a synchronized method to check and modify the
counter. Sincerely, I don't think it's a good idea, because I'll have a
bottleneck using synchronized methods. In other hand, I don't know and I'd
like:
- how to or where to place and access an object shared by all tomcat threads
- define a singleton class in tomcat

And I'd like to have a solution that can be extended to many tomcat
instances (in different servers).

I'm using:
Tomcat 7.0.14
Metro 2.0 (jax-ws)
MySQL + Hibernate

Do you have any suggestion?

Thanks in advance

Hernán

Re: Limiting concurrent requests by user

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hernán,

On 2/27/12 3:04 PM, hernan wrote:
> I've a web service. In order to do a request, a user specifies a
> username and password via web service parameters along with web
> service parameters. The web service server, checks user and
> password and if it is correct, then process the request (else
> response "access denied").
> 
> The process may take some seconds or a few minutes to be completed.
> I'd like to limit the number of client requests per user.

Does the username/password check take some seconds, or the operation
that follows it? I'm asking because if you want to avoid the
username/password check, then you'll have to assume that a username
presented by a user is accurate -- that can open you up to
denial-of-service attacks.

Are you using sessions for users, or is everything stateless?

> I'm thinking to mantain some data structure in memory (shared by
> all tomcat threads, I don't know how to do that) or in some table
> in the database to count the number of requests per user.

An in-memory structure would be far faster, but of course you have to
keep it in memory. The best place for something like this is probably
in the ServletContext (aka "application"), unless you are going to put
it into something outside of the JVM (memcached, db, etc.).

> For each received request, if accepted, increments the counter, and
> when the process finishes (or if the process fails) decrements the
> counter. In order to do that, I think I need to have a singleton
> class and a synchronized method to check and modify the counter.
> Sincerely, I don't think it's a good idea, because I'll have a 
> bottleneck using synchronized methods. In other hand, I don't know
> and I'd like: - how to or where to place and access an object
> shared by all tomcat threads - define a singleton class in tomcat

You won't be doing anything with "Tomcat" per se: everything will be
in your own webapp so you don't need to know how to do it "in Tomcat".

You also don't need a singleton: just a place to store the data. If
you use the ServletContext, you can get to it from any servlet during
the request. If you need to pass that data into some business logic
controller, you can easily do that eve if it's just stored in the
ServletContext.

I wouldn't worry too much about synchronized access to such a
structure, since the operations will be so short (perform a (hash?)
lookup, perform an increment/decrement operation).

You'll have to worry about your in-memory structure growing too large
(huge username cache, for instance), so I would actually recommend
scrapping the counter idea and instead using a simpler user "in use"
flag -- something like a hash table with username keys and Boolean
values: if a user is doing something, the hash table contains
Boolean.TRUE for that username. If the user is not doing anything,
then the username does not appear in the structure at all.

Of course, that only works if you want to serialize all access on a
per-user basis. If you instead want to limit things to, say, 5
simultaneous requests, then you'll have to use counters.

Don't forget to release the user-lock in a finally block or you'll end
up locking everyone out and/or running out of memory at some point (or
both) :)

> And I'd like to have a solution that can be extended to many
> tomcat instances (in different servers).

Do you want to have a cluster-wide lock-out mechanism so that a user
may only make a single request to the cluster at a time, or do you
want to just limit the user on a single machine? If you want to limit
the user to one-request-per-cluster, then you'll definitely have to go
outside the container for a decent solution. I would recommend looking
into something like memcached for such a thing.

> 
> I'm using: Tomcat 7.0.14

Upgrade.

- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk9MAvcACgkQ9CaO5/Lv0PDfOQCfZAIAU4SeuqasbTvpP7t4dqL8
kDIAmgI3N1ZyMhwbNcwzkZTH83l/WbDN
=UyLk
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Limiting concurrent requests by user

Posted by Chema <de...@gmail.com>.
2012/2/27 hernan <hb...@gmail.com>

>
>
> The process may take some seconds or a few minutes to be completed. I'd
> like to limit the number of client requests per user.
>

Why not do you use Tomcat's valves mechanism ?
You can implement a request filter on a Context scope

Where store the counter of requests ?
Memory looks the better option ... except if you application runs on a
clustered enviroment. In this case, you can try a database

Re: Limiting concurrent requests by user

Posted by Pid * <pi...@pidster.com>.
On 27 Feb 2012, at 22:18, Hassan Schroeder <ha...@gmail.com> wrote:

> On Mon, Feb 27, 2012 at 12:04 PM, hernan <hb...@gmail.com> wrote:
>
>> - how to or where to place and access an object shared by all tomcat threads
>>
>> And I'd like to have a solution that can be extended to many tomcat
>> instances (in different servers).
>
> Why not just keep counters in an in-memory store like e.g. Redis,
> MongoDB, Cassandra, etc. etc.?

Or queue the work requests in a per user queue.

This is better for long running jobs, better for user/resource
management and could make your app more responsive.


p


>
> --
> Hassan Schroeder ------------------------ hassan.schroeder@gmail.com
> http://about.me/hassanschroeder
> twitter: @hassan
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Limiting concurrent requests by user

Posted by Hassan Schroeder <ha...@gmail.com>.
On Mon, Feb 27, 2012 at 12:04 PM, hernan <hb...@gmail.com> wrote:

> - how to or where to place and access an object shared by all tomcat threads
>
> And I'd like to have a solution that can be extended to many tomcat
> instances (in different servers).

Why not just keep counters in an in-memory store like e.g. Redis,
MongoDB, Cassandra, etc. etc.?

-- 
Hassan Schroeder ------------------------ hassan.schroeder@gmail.com
http://about.me/hassanschroeder
twitter: @hassan

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Limiting concurrent requests by user

Posted by Pid * <pi...@pidster.com>.
On 27 Feb 2012, at 22:26, Christopher Schultz
<ch...@christopherschultz.net> wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hernán,
>
> On 2/27/12 3:04 PM, hernan wrote:
>> I've a web service. In order to do a request, a user specifies a
>> username and password via web service parameters along with web
>> service parameters. The web service server, checks user and
>> password and if it is correct, then process the request (else
>> response "access denied").
>>
>> The process may take some seconds or a few minutes to be completed.
>> I'd like to limit the number of client requests per user.
>
> Does the username/password check take some seconds, or the operation
> that follows it? I'm asking because if you want to avoid the
> username/password check, then you'll have to assume that a username
> presented by a user is accurate -- that can open you up to
> denial-of-service attacks.
>
> Are you using sessions for users, or is everything stateless?
>
>> I'm thinking to mantain some data structure in memory (shared by
>> all tomcat threads, I don't know how to do that) or in some table
>> in the database to count the number of requests per user.
>
> An in-memory structure would be far faster, but of course you have to
> keep it in memory. The best place for something like this is probably
> in the ServletContext (aka "application"), unless you are going to put
> it into something outside of the JVM (memcached, db, etc.).



>
>> For each received request, if accepted, increments the counter, and
>> when the process finishes (or if the process fails) decrements the
>> counter. In order to do that, I think I need to have a singleton
>> class and a synchronized method to check and modify the counter.
>> Sincerely, I don't think it's a good idea, because I'll have a
>> bottleneck using synchronized methods. In other hand, I don't know
>> and I'd like: - how to or where to place and access an object
>> shared by all tomcat threads - define a singleton class in tomcat
>
> You won't be doing anything with "Tomcat" per se: everything will be
> in your own webapp so you don't need to know how to do it "in Tomcat".
>
> You also don't need a singleton: just a place to store the data. If
> you use the ServletContext, you can get to it from any servlet during
> the request. If you need to pass that data into some business logic
> controller, you can easily do that eve if it's just stored in the
> ServletContext.
>
> I wouldn't worry too much about synchronized access to such a
> structure, since the operations will be so short (perform a (hash?)
> lookup, perform an increment/decrement operation).
>
> You'll have to worry about your in-memory structure growing too large
> (huge username cache, for instance), so I would actually recommend
> scrapping the counter idea and instead using a simpler user "in use"
> flag -- something like a hash table with username keys and Boolean
> values: if a user is doing something, the hash table contains
> Boolean.TRUE for that username. If the user is not doing anything,
> then the username does not appear in the structure at all.
>
> Of course, that only works if you want to serialize all access on a
> per-user basis. If you instead want to limit things to, say, 5
> simultaneous requests, then you'll have to use counters.
>
> Don't forget to release the user-lock in a finally block or you'll end
> up locking everyone out and/or running out of memory at some point (or
> both) :)
>
>> And I'd like to have a solution that can be extended to many
>> tomcat instances (in different servers).
>
> Do you want to have a cluster-wide lock-out mechanism so that a user
> may only make a single request to the cluster at a time, or do you
> want to just limit the user on a single machine? If you want to limit
> the user to one-request-per-cluster, then you'll definitely have to go
> outside the container for a decent solution. I would recommend looking
> into something like memcached for such a thing.

Or a message broker.


p


>
>>
>> I'm using: Tomcat 7.0.14
>
> Upgrade.
>
> - -chris
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
> Comment: GPGTools - http://gpgtools.org
> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
>
> iEYEARECAAYFAk9MAvcACgkQ9CaO5/Lv0PDfOQCfZAIAU4SeuqasbTvpP7t4dqL8
> kDIAmgI3N1ZyMhwbNcwzkZTH83l/WbDN
> =UyLk
> -----END PGP SIGNATURE-----
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org