RxJava一个发布服务器的多个使用者

RxJava一个发布服务器的多个使用者,java,caching,rx-java,reactive-streams,backpressure,Java,Caching,Rx Java,Reactive Streams,Backpressure,我正在编写一种带有缓存的中间件HTTP代理。工作流程是: 客户端请求此代理获取资源 如果缓存中存在resurce,代理将返回它 如果未找到资源,代理将获取远程资源并返回给用户。在加载数据时,代理将此资源保存到缓存中 我的界面具有用于远程资源的Publisher流、接受Publisher保存的缓存,以及接受Publisher作为响应的客户端连接: //远程资源 接口资源{ Publisher-fetch(); } //缓存 接口缓存{ 可完全保存(发布者数据); } //客户端响应连接 接口连接{

我正在编写一种带有缓存的中间件HTTP代理。工作流程是:

  • 客户端请求此代理获取资源
  • 如果缓存中存在resurce,代理将返回它
  • 如果未找到资源,代理将获取远程资源并返回给用户。在加载数据时,代理将此资源保存到缓存中
  • 我的界面具有用于远程资源的
    Publisher
    流、接受
    Publisher
    保存的缓存,以及接受
    Publisher
    作为响应的客户端连接:

    //远程资源
    接口资源{
    Publisher-fetch();
    }
    //缓存
    接口缓存{
    可完全保存(发布者数据);
    }
    //客户端响应连接
    接口连接{
    可完成发送(发布者数据);
    }
    
    我的问题是,在向客户机发送响应时,我需要将这个字节缓冲区流延迟保存到缓存中,因此客户机应该负责从远程资源请求
    bytebyfer
    块,而不是缓存

    我尝试使用
    Publisher::cache
    方法,但这对我来说不是一个好选择,因为它将所有接收到的数据都保存在内存中,这是不可接受的,因为缓存数据的大小可能只有几GB

    作为解决方法,我创建了
    主题
    ,由从
    资源
    收到的下一个项目填充:

    私有最终缓存;
    私人最终连接输出;
    可完成代理(资源资源){
    Subject mirror=PublishSUbject.create();
    返回Completable.mergeArray(
    out.send(res.fetch().doOnNext(镜像::onNext),
    cache.save(mirror.toFlowable(BackpressureStrategy.BUFFER))
    );
    }
    

    是否可以重用相同的
    Publisher
    ,而不在内存中缓存项目,并且只有一个订阅者负责向Publisher请求项目?

    我可能遗漏了一些内容(添加了关于我的
    Publisher
    界面版本不同的注释)

    但是,在概念上,我是这样做的

    我将简化接口以处理
    整数

    // remote resource
    interface Resource {
      ConnectableObservable<Integer> fetch();
    }
    
    // cache
    interface Cache {
      Completable save(Integer data);
    }
    
    // client response connection
    interface Connection {
      Completable send(Integer data);
    }
    
    输出:

    Caching 1
    Caching 2
    Caching 3
    Caching 4
    Sending 1
    Caching 5
    Caching 6
    Caching 7
    Caching 8
    Caching 9
    Sending 2
    Caching 10
    . . . 
    

    更新

    根据您的评论,在您的案例中,尊重背压似乎很重要

    假设您有一个
    发行商
    在某个地方尊重背压,您可以将其转换为
    可流动的
    ,如下所示:

    Flowable<T> flowable = Flowable.fromPublisher( publisher );
    

    我无法理解你说的话:所以客户端应该负责从远程资源而不是缓存请求ByteByfer块。!@bubbles我指的是背压:
    Publisher
    has method
    请求(长n)
    正在从
    Publisher
    请求下一个
    n
    项目的数量。客户端的
    连接
    缓存
    慢,因此只有
    连接
    应该负责从
    资源的
    远程
    Publisher
    请求下一个
    n
    字节缓冲
    项目的数量在RxJava的版本中是这样的吗?我在2.x上,
    Publisher
    只有一个方法:
    Publisher.subscribe(订阅anks以获取答案。我使用的是RxJava2,
    Publicher
    接口是reactivestreams
    1.0.0
    的一部分,请看,实际上与您的接口存在一些不匹配,因为
    Cache
    Connection
    接受
    Publisher
    (让我们使用
    T
    而不是整数和缓冲区),而不是纯整数。因此问题在于
    发行商的
    订阅者在
    onSubscribe()之后可能会从
    订阅
    请求下一个项目
    call@Kirill在您的链接中,
    Publisher
    有一个方法:
    Publisher::subscribe
    。您的问题引用了一个方法
    Publisher::cache
    ,而您的代码似乎引用了
    Publisher::doOnNext
    。我找不到这两个方法中的任何一个。在我对问题的原始评论中,我谈到了
    subscribration
    Publisher
    ,而不是Publisher
    本身,它有方法
    请求(长)
    :另外,我在问题中提到了背压是重要的一部分,
    缓存作为消费者要快得多,因此它填充了
    可连接的可流动的
    的缓冲区,在发送到慢速
    连接之前,内存将充满项目,这是主要问题(请参阅原始问题).@Kirill
    ConnectableFlowable
    尊重来自最慢使用者的背压,您可以通过调用
    Flowable.publish(int-bufferSize)来控制其缓冲区的大小
    。假设您的基础资源/发布服务器也考虑了背压,那么就不会有内存消耗问题。谢谢,我刚刚验证过,可连接的发布服务器考虑了来自最慢的用户的背压。
    Flowable<T> flowable = Flowable.fromPublisher( publisher );
    
    ConnectableFlowable<T> flowable = Flowable.fromPublisher( publisher ).publish();
    out.send(flowable);   // calls flowable.subscribe()
    cache.save(flowable); // calls flowable.subscribe()
    flowable.connect();   // begins emitting values