使用RxJava通过异步HTTP客户端限制传出HTTP请求

使用RxJava通过异步HTTP客户端限制传出HTTP请求,http,jersey,rx-java,vert.x,throttling,Http,Jersey,Rx Java,Vert.x,Throttling,我正在尝试使用Jersey客户端限制传出http请求。因为我运行的是Vertx垂直体,所以我创建了一个特殊的RateLimitor类来处理节流 我的目标是防止HTTP调用的速率超过每秒1次。其思想是,提交的可调用对象将使用单线程ExecutorService运行,这样我就可以阻止该单线程,以保证这些任务不会以更高的速率处理 基本上,该类中唯一的公共方法是call: public <T> Observable<T> call(Callable<Observable&

我正在尝试使用Jersey客户端限制传出http请求。因为我运行的是Vertx垂直体,所以我创建了一个特殊的RateLimitor类来处理节流

我的目标是防止HTTP调用的速率超过每秒1次。其思想是,提交的可调用对象将使用单线程ExecutorService运行,这样我就可以阻止该单线程,以保证这些任务不会以更高的速率处理

基本上,该类中唯一的公共方法是call:

 public <T> Observable<T> call(Callable<Observable<T>> action) {
    return Observable.create(subscriber -> {

        Observable<Observable<T>> observed =
                Observable.from(executor.submit(() -> {                         
                        return action.call();
                    })
                ).doOnError(throwable -> {
                               logger.error(throwable);
                           }
                );

        observed.subscribe(t -> {
            try {
                Thread.sleep(1000); 
                t.subscribe(data -> {
                    try {
                        subscriber.onNext(data);
                    } catch (Throwable e) {
                        subscriber.onError(e);
                    }
                    subscriber.onCompleted();
                });
            } catch (Exception e) {
                logger.error(e);
            }

        });
    });
} 
这是我当前的实现,它使用1秒睡眠,无论上次调用后经过了多少时间。最初,我尝试使用ScheduledExecutorService并计算延迟时间,以便以每秒1的速率提交请求。然而,在这两种情况下,它往往无法满足费率限制,我收到两个请求,一个接一个地立即提交

我的假设是,在某个地方,请求被传递到不同的执行队列,该队列由不同的线程连续轮询,因此,如果由于某种原因,该线程很忙,并且队列中同时存在两个请求,则它们将按顺序执行,但不会延迟


有没有办法解决这个问题?也许是另一种方法?

只需在web服务调用之前添加番石榴。下面是RxJava中的一个示例,它显示了如何将每500毫秒的事件限制为每秒一次

    Function<Long, Long> throttlingFunction = new Function<Long, Long>() {
        private RateLimiter limiter = RateLimiter.create(1.0);

        public Long apply(Long t) throws Exception {
            limiter.acquire();
            return t;
        }
    };
    Observable.interval(500, TimeUnit.MILLISECONDS)
        .map(throttlingFunction)
        .subscribe(new Consumer<Long>() {
        public void accept(Long t) throws Exception {
            System.out.println(t);
        }
    });

同样在vert.x中,所有的阻塞都应该在的帮助下运行。

只需在web服务调用之前使用guava。下面是RxJava中的一个示例,它显示了如何将每500毫秒的事件限制为每秒一次

    Function<Long, Long> throttlingFunction = new Function<Long, Long>() {
        private RateLimiter limiter = RateLimiter.create(1.0);

        public Long apply(Long t) throws Exception {
            limiter.acquire();
            return t;
        }
    };
    Observable.interval(500, TimeUnit.MILLISECONDS)
        .map(throttlingFunction)
        .subscribe(new Consumer<Long>() {
        public void accept(Long t) throws Exception {
            System.out.println(t);
        }
    });

同样在vert.x中,所有阻塞都应该在的帮助下运行。

我将使用简单的Vertx事件总线和一个队列,您可以从中每秒轮询一次:

 public static void main(String[] args) {


    Vertx vertx = Vertx.vertx();

    vertx.deployVerticle(new DebounceVerticle(), (r) -> {

        // Ok, verticle is ready!
        // Request to send 10 events in 1 second
        for (int i = 0; i < 10; i++) {
            vertx.eventBus().publish("call", UUID.randomUUID().toString());
        }
    });


}


private static class DebounceVerticle extends AbstractVerticle {

    HttpClient client;
    @Override
    public void start() {
        client = vertx.createHttpClient();

        BlockingQueue<String> queue = new LinkedBlockingQueue<>();

        vertx.eventBus().consumer("call", (payload) -> {
            String message = (String) payload.body();
            queue.add(message);
            System.out.println(String.format("I got %s but I don't know when it will be executed", message));
        });

        vertx.setPeriodic(1000, (l) -> {
            String message = queue.poll();

            if (message != null) {
                System.out.println(String.format("I'm finally sending %s", message));

                //Do your client magic
            }
        });
    }
}

我将使用简单的Vertx事件总线和一个队列,您可以从中每秒轮询一次:

 public static void main(String[] args) {


    Vertx vertx = Vertx.vertx();

    vertx.deployVerticle(new DebounceVerticle(), (r) -> {

        // Ok, verticle is ready!
        // Request to send 10 events in 1 second
        for (int i = 0; i < 10; i++) {
            vertx.eventBus().publish("call", UUID.randomUUID().toString());
        }
    });


}


private static class DebounceVerticle extends AbstractVerticle {

    HttpClient client;
    @Override
    public void start() {
        client = vertx.createHttpClient();

        BlockingQueue<String> queue = new LinkedBlockingQueue<>();

        vertx.eventBus().consumer("call", (payload) -> {
            String message = (String) payload.body();
            queue.add(message);
            System.out.println(String.format("I got %s but I don't know when it will be executed", message));
        });

        vertx.setPeriodic(1000, (l) -> {
            String message = queue.poll();

            if (message != null) {
                System.out.println(String.format("I'm finally sending %s", message));

                //Do your client magic
            }
        });
    }
}

操作员有什么问题?它是否会过滤掉在指定的持续时间内未满足要求的事件?我希望以相同的速率发出所有请求。文档中的术语emit指调用的回调。但我不知道它如何保证以我需要的速度执行传出请求。如果您能用代码示例详细说明如何实现我的目标,那将非常有帮助。请让我总结一下您的问题,我确实理解它。您已经使用Vertx完成了一些web服务。所讨论的服务可以在一秒钟内调用多次。服务本身对Jersey客户端执行rest调用。应以每秒1的速率限制其余调用方。对web服务Vertx的每次调用都应该处理一个结果。让我们一秒钟处理5个请求。然后,将针对rest触发第一个。其他四个将等待一秒钟,直到下一个将被处理?对于最后一个请求,您需要等待5秒钟才能响应?@YanivCohen然后用超时检查缓冲区。实际上,这比这个简单一点。让我这样说:我有一个web服务在vert.x上工作,也就是我的服务,该服务使用jersey http client对另一个web服务(也就是其他服务)进行http rest调用,该服务每秒只允许1个请求。对我的服务的单个rest调用将创建对其他服务的许多请求。只要其他服务以每秒1个请求的速度被我的服务命中,我就可以了。操作员怎么了?它不会过滤掉在指定时间内未满足请求的事件吗?我希望以相同的速率发出所有请求。文档中的术语emit指调用的回调。但我不知道它如何保证以我需要的速度执行传出请求。如果您能用代码示例详细说明如何实现我的目标,那将非常有帮助。请让我总结一下您的问题,我确实理解它。您已经使用Vertx完成了一些web服务。所讨论的服务可以在一秒钟内调用多次。服务本身对Jersey客户端执行rest调用。应以每秒1的速率限制其余调用方。对web服务Vertx的每次调用都应该处理一个结果。让我们一秒钟处理5个请求。然后,将针对rest触发第一个。其他四个将等待一秒钟,直到下一个将被处理?对于最后一个请求,您需要等待5秒钟才能响应?@YanivCohen然后用超时检查缓冲区。实际上,这比这个简单一点。让我这样说:我有一个web服务在vert.x上工作,也就是我的服务,该服务使用jersey http client对另一个web服务(也就是其他服务)进行http rest调用,该服务每秒只允许1个请求。对我的服务的单个rest调用将创建对其他服务的许多请求。只要另一项服务正在运行
以每秒1个请求的速度被我的服务击中,我应该可以。好吧,我会使用Guava速率限制器,只是我有两个问题:好吧,我会使用Guava速率限制器,只是我有两个问题: