My application makes Web Service requests; there is a max rate of requests the provider will handle, so I need to throttle them down.
When the app ran on a single server, I used to do it at the application level: an object that keeps track of how many requests have been made so far, and waits if the current request makes it exceeds the maximum allowed load.
Now, we're migrating from a single server to a cluster, so there are two copies of the application running.
I can't keep checking for the max load at the application code, because the two nodes combined might exceed the allowed load.
I can't simply reduce the load on each server, because if the other node is idle, the first node can send out more requests.
This is a JavaEE 5 environment. What is the best way to throttle the requests the application sends out ?
Since you are already in a Java EE environment, you can create an MDB that handles all requests to the webservice based on a JMS queue. The instances of the application can simply post their requests to the queue and the MDB will recieve them and call the webservice.
The queue can actually be configured with the appropriate number of sessions that will limit the concurrent access to you webservice, thus your throttling is handled via the queue config.
The results can be returned via another queue (or even a queue per application instance).
The N nodes need to communicate. There are various strategies:
broadcast: each node will broadcast to everybody else that it's macking a call, and all other nodes will take that into account. Nodes are equal and maintain individial global count (each node know about every other node's call).
master node: one node is special, its the master and all other nodes ask permission from the master before making a call. The master is the only one that know the global count.
dedicated master: same as master, but the 'master' doesn't do calls on itslef, is just a service that keep track of calls.
Depending on how high do you anticipate to scale later, one or the other strategy may be best. For 2 nodes the simplest one is broadcast, but as the number of nodes increases the problems start to mount (you'll be spending more time broadcasting and responding to broadcats than actually doing WS requests).
How the nodes communicate, is up to you. You can open a TCP pipe, you can broadcats UDP, you can do a fully fledged WS for this purpose alone, you can use a file share protocol. Whatever you do, you are now no longer inside a process so all the fallacies of distributed computing apply.
Many ways of doing this: you might have a "Coordination Agent" which is responsible of handing "tokens" to the servers. Each "token" represents a permission to perform a task etc. Each application needs to request "tokens" in order to place calls.
Once an application depletes its tokens, it must ask for some more before proceeding to hit the Web Service again.
Of course, this all gets complicated when there are requirements with regards to the timing of each calls each application makes because of concurrency towards the Web Service.
You could rely on RabbitMQ as Messaging framework: Java bindings are available.
I recommend using beanstalkd to periodically pump a collection of requests (jobs) into a tube (queue), each with an appropriate delay. Any number of "worker" threads or processes will wait for the next request to be available, and if a worker finishes early it can pick up the next request. The down side is that there isn't any explicit load balancing between workers, but I have found that distribution of requests out of the queue has been well balanced.
This is an interesting problem, and the difficulty of the solution depends to a degree on how strict you want to be on the throttling.
My usual solution to this is JBossCache, partly because it comes packaged with JBoss AppServer, but also because it handles the task rather well. You can use it as a kind of distributed hashmap, recording the usage statistics at various degrees of granularity. Updates to it can be done asynchronously, so it doesn't slow things down.
JBossCache is usually used for heavy-duty distributed caching, but I rather like it for these lighter-weight jobs too. It's pure java, and requires no mucking about with the JVM (unlike Terracotta).
Hystrix was designed for pretty much the exact scenario you're describing. You can define a thread pool size for each service so you have a set maximum number of concurrent requests, and it queues up requests when the pool is full. You can also define a timeout for each service and when a service starts exceeding its timeout, Hystrix will reject further requests to that service for a short period of time in order to give the service a chance to get back on its feet. There's also real time monitoring of the entire cluster through Turbine.
Related
I have a spring application that retrieves messages from one queue (aws sqs) renders and sends request to the outside vendor, gets response process it again and puts it back into another processed queue. Spring application has no API, communicating through queues only. I need to determine throughput (# of msg/s) of my application. What's the best way to do it? Any existent tools for my use case?
You can benchmark the "service" code "in isolation" from SQS using various techniques. As mentioned in the comment on your question a popular tool is jmeter. You could expose a http endpoint just for exercising the service code (the same code that will run when an SQS message is received)
You could also consider running locally a localstack docker image which will allow you to mock SQS (you can use a test harness to put messages into the localstack sqs queue and then, assuming that you have a way to correlate the message produced by the service measure the time between the message being sent to the queue and the time at which it appears on the queue that the app write to.
This of course is potentially misleading as using the "real" SQS will likely have some overhead of its own (e.g. locally running docker won't involve remote network calls which will hide some amount of network latency and perhaps the real SQS processing time has different characteristics to the localstack one). Of course, you could actually just use real SQS queues if the cost of those messages doesn't bother you too much and this will be more accurate.
Another key thing to consider is, given that your service sends a request to an outside vendor your performance characteristics will be linked to that of the downstream service that you depend upon - if that service has latency that varies between 100ms to 2000 ms for example it'll impact yours so when deciding whether to benchmark your code in isolation (for example by using a mock of that service) you would need to consider that.
Is making REST based web service (POST) asynchronous is the best way to handle thousands of requests at one time (Keeping in mind that I have only single instance of server serving the request)?
Edited:
Jersey is wrongly tagged.
For eg: I have a rest based web service, which is supposed to be consumed by 100 thousand clients within a very short span of time (~60 seconds). I understand that if I am allowed to deploy multiple instance of the server, then I can use a load balancer to handle all my incoming request and delegate them accordingly. But I am restricted to use only single instance. What design could I opt within this restriction?
I could think of making the request asynchronous( which will not respond to client immediately ) in order to be able to let the server be free from this load and handle the requests at it's own pace.
For now we can ignore memory limitations.
Please let me know if this clarifies your doubt?
The term asynchronous could have different meanings in different places. For a web application code, it could refer to a Nonblocking I/O server such as Node or Netty/Akka which is a way for HTTP Requests to time multiplex on the same worker threads. If you're writing callbacks or using async or future constructs, it probably is non-blocking I/O which people sometimes refer to as asynchronous.
However, I could have REST API running on Node which implements non-blocking I/O, but the API or the overall architecture is still fully synchronous. For example, let's say I have an API endpoint POST /photos, which takes in a photo, creates image thumbnails, stores the URLs of the photo in a SQL Db and then stores the images in S3. The REST API could still block from the initial POST until after the image is processed and stored.
A second way is for the server to accept the photo process as a job and return immediately. Then the server could store the photo in a in memory or network based queue to be processed later by some other worker thread. In fact, I could even implement this async architecture even with a blocking server like some good old Java 7 and Jetty.
I have an application consisting of several Java services, which communicate through direct RMI lines. I'm about to upgrade this to something more modern and stable using JMS / ActiveMQ.
The most common scenario is a number of processes connecting to a central service and performing requests. -> This can be implemented in JMS with a named request queue and named or temporary response queues.
Through the above link, processes will also register themselves as event listeners with the central service, which maintains a list of them, and dispatches events by sending it to each subscriber directly via RMI. -> A JMS topic is an ideal replacement for this.
The third scenario is more complex: I'll also have several processes registering themselves as workers with the central service. This central service will have to maintain a pool of those workers, which can be started, stopped and restarted dynamically and unexpectedly.
The pool will then assign tasks to specific workers (e.g. the worker with the lowest load, so no broadcasting or random selection). But I don't think that'll be very difficult, the core problem is keeping the pool up to date.
The workers will also need to communicate back with information about the running tasks or the general worker status (e.g. current load, or, is it accepting new tasks).
How might I implement this, in a stable way, on top of JMS? Well, explaining how to fully implement this complex scenario may be a bit much, but are there general design patterns that can be applied here, assuming the availability of queue- and topiclike channels?
Can Akka provide web request throttling for a distributed application (Java/JEE)?
My application consumes a number of web services each of which allows a maximum number of concurrent requests. I've looked at
TimerBasedThrottle - suitable for single node application, but not possible to manage the number or requests sent in distributed setting.
Balancing dispatcher - shares a single mailbox between Actors sending messages to idle Actors, but it does not enforce a limit per second/minute, etc.
What is the best way to achieve this with Akka?
If you want to control and limit the number of certain actions performed by a distributed system, then your distributed nodes will have to communicate to make that happen. The easiest is to have one central actor which keeps track of all requests made to a certain target web service and handing out tickets allowing them to happen (delaying or dropping requests when going over the configured limit). If you do not want to incur the overhead of inter-node communication, then you will have to partition your quota such as to guarantee that by throttling all nodes individually their sum cannot exceed the limit, but this is obviously wasteful unless the request originators are perfectly balanced.
I'm looking for opinion from you all. I have a web application that need to records data into another web application database. I not prefer to use HTTP request GET on 2nd application because of latency issue. I looking for fast way to save records on 2nd application quickly, I came across the idea of "fire and forget" , will JMS suit for this scenario? from my understanding JMS will guarantee message delivery, guarantee whether message will be 100% deliver is not important as long as can serve as many requests as possible. Let say I need to call at least 1000 random requests per seconds to 2nd application should I use JMS? HTTP request? or XMPP instead?
I think you're misunderstanding networking in general. There's positively no reason that a HTTP GET would have to be any slower than anything else, and if HTTP takes advantage of keep alives it's faster that most options.
JMX isn't a protocol, it's a specification that wraps many other protocols including, possibly, HTTP or XMPP.
In the end, at the levels where Java will operate, there's either UDP or TCP. TCP has more overhead by guarantees delivery (via retransmission) and ordering. UDP offers neither guaranteed delivery nor in-order delivery. If you can deal with UDP's limitations you'll find it "faster", and if you can't then any lightweight TCP wrapper (of which HTTP is one) is just about the same.
Your requirements seem to be:
one client and one server (inferred from your first sentence),
HTTP is mandatory (inferred from your talking about a web application database),
1000 or more record updates per second, and
individual updates do not need to be acknowledged synchronously (you are willing to use "fire and forget" approach.
The way I would approach this is to have the client threads queue the updates internally, and implement a client thread that periodically assembles queued updates into one HTTP request and sends it to the server. If necessary, the server can send a response that indicates the status for individual updates.
Batching eliminates the impact of latency on the client, and potentially allows the server to process the updates more efficiently.
The big difference between HTTP and JMS or XMPP is that JMS and XMPP allow asynchronous fire and forget messaging (where the client does not really know when and if a message will reach its destination and does not expect a response or an acknowledgment from the receiver). This would allow the first app to respond fast regardless of the second application processing time.
Asynchronous messaging is usually preferred for high-volume distributed messaging where the message consumers are slower than the producers. I can't say if this is exactly your case here.
If you have full control and the two web applications run in the same web container and hence in the same JVM, I would suggest using JNDI to allow both web applications to get access to a common data structure (a list?) which allows concurrent modification, namely to allow application A to add new entries and application B to consume the oldest entries simultaneously.
This is most likely the fastest way possible.
Note, that you should keep the information you put in the list to classes found in the JRE, or you will most likely run into class cast exceptions. These can be circumvented, but the easiest is most likely to just transfer strings in the common data structure.