我可以限制分布式应用程序发出的请求吗?
我的应用程序发出 Web 服务请求;提供商处理的请求有最大速率,因此我需要限制它们。
当应用程序在单个服务器上运行时,我曾经在应用程序级别执行此操作:一个对象跟踪到目前为止已发出的请求数量,并在当前请求超出允许的最大负载时等待。
现在,我们正在从单个服务器迁移到集群,因此有两个应用程序副本正在运行。
- 我无法继续检查应用程序代码的最大负载,因为两个节点的组合可能会超出允许的负载。
- 我不能简单地减少每个服务器上的负载,因为如果另一个节点空闲,第一个节点可以发出更多请求。
这是一个 JavaEE 5 环境。限制应用程序发出的请求的最佳方法是什么?
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 ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
由于您已经处于 Java EE 环境中,因此您可以创建一个 MDB 来处理基于 JMS 队列的 Web 服务的所有请求。应用程序的实例只需将它们的请求发布到队列中,MDB 将接收它们并调用 Web 服务。
实际上可以为队列配置适当数量的会话,这将限制对 Web 服务的并发访问,因此您的限制是通过队列配置来处理的。
结果可以通过另一个队列(甚至每个应用程序实例的队列)返回。
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).
N个节点需要进行通信。有多种策略:
根据您预计以后的扩展程度,一种或另一种策略可能是最好的。对于 2 个节点,最简单的一种是广播,但随着节点数量的增加,问题开始增多(您将花费更多的时间来广播和响应广播,而不是实际执行 WS 请求)。
节点如何通信取决于您。你可以打开一个 TCP 管道,你可以广播 UDP,你可以单独为此目的做一个成熟的 WS,你可以使用文件共享协议。无论您做什么,您现在都不再处于进程内,因此所有分布式计算的谬论都适用。
The N nodes need to communicate. There are various strategies:
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.
执行此操作的方法有很多:您可能有一个“协调代理”,负责将“令牌”传递给服务器。每个“令牌”代表执行任务等的权限。每个应用程序都需要请求“令牌”才能发出呼叫。
一旦应用程序耗尽其令牌,它必须在再次访问 Web 服务之前请求更多令牌。
当然,当由于 Web 服务的并发性而对每个应用程序进行的每次调用的时间有要求时,这一切都会变得复杂。
您可以依赖 RabbitMQ 作为消息传递框架:Java 绑定可用。
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.
我建议使用 beanstalkd 定期将一组请求(作业)注入到管(队列),每个都有适当的延迟。任意数量的“工作”线程或进程将等待下一个请求可用,如果工作人员提前完成,它可以接收下一个请求。缺点是工作人员之间没有任何明确的负载平衡,但我发现队列外的请求分配已经得到了很好的平衡。
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.
这是一个有趣的问题,解决方案的难度在一定程度上取决于你想要对限制有多严格。
我通常的解决方案是 JBossCache,部分原因是它与 JBoss AppServer 一起打包,但也因为它处理任务相当好。您可以将其用作一种分布式哈希图,记录不同粒度的使用统计信息。它的更新可以异步完成,因此不会减慢速度。
JBossCache 通常用于重型分布式缓存,但我也更喜欢它用于这些轻量级作业。它是纯 java,不需要对 JVM 进行任何操作(与 Terracotta 不同)。
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 的设计几乎与您所描述的场景完全相同。您可以为每个服务定义线程池大小,以便设置最大并发请求数,并在池已满时对请求进行排队。您还可以为每个服务定义一个超时,当某个服务开始超过其超时时,Hystrix 将在短时间内拒绝对该服务的进一步请求,以便让该服务有机会恢复正常。还可以通过 Turbine 实时监控整个集群。
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.