背压对于构建健壮和响应性的应用程序非常重要。从本质上说,它是一个从消费者到生产者的反馈渠道。消费者对在任何时候可以处理多少数据有一定的控制。这样,消费者或消息传递中间件在高负载下不会变得饱和和无响应。相反,他们要求很少的信息,让生产者决定如何放慢速度。
在每一个通过消息传递(或事件)交换数据的系统中,一个消费者无法与生产者保持同步的问题就会出现。根据底层实现,它可以以不同的方式表现出来。如果通信通道以某种方式使生产者和消费者同步(例如,通过使用ArrayBlockingQueue),当消费者无法跟上负载时,生产者就会被阻塞(阻塞)。这将导致生产者和消费者之间的耦合,而它们之间应该是非耦合的。消息传递通常意味着异步处理,生产者突然必须等待消费者这种假设一定会失败。更糟糕的是,生产者可能是层次结构中不同生产者的消费者,层叠增加了延迟。
相反,如果消费者和生产者之间的媒介是无界的,嗯…那么它仍然受到我们控制较少的因素的束缚。像LinkedBlockingQueue这样的无限队列允许生产者在不阻塞的情况下大大超越消费者。也就是说,在LinkedBlockingQueue不占用所有内存和崩溃整个应用程序之前。如果媒介是持久的——例如JMS消息代理——同样的问题也可以在技术上体现为磁盘空间,但这是不太可能的。更常见的情况是消息传递中间件很难管理成千上万的未被使用的消息。一些专业的消息中间件,如Kafka,可以在技术上存储数以百万计的信息,直到落后的消费者抓到它们。但是,这导致了在消息生产和消费之间的延迟时间的巨大增长。
尽管消息驱动系统通常被认为更加健壮和可伸缩,但生产者过于热切生产事件的问题仍然没有得到解决。但是,也有一些努力来解决这个集成问题。采样和节流(使用sample()和其他)和批处理(使用window()和buffer())是减少RxJava中生产者负载的手动方式。当Observable 生成更多可以被消费的事件时,我们可以应用采样或批处理来增加订阅吞吐量。然而,需要更有力和更系统的方法,因此,Reactive Streams 应运而生。这一小部分接口和语义旨在使问题形式化,并为生产者-消费者协调提供一种系统的算法,称为背压。
Backpressure(背压)是一种简单的协议,它允许使用者报告在一个时间内消费多少数据,有效地为生产者提供一个反馈通道。生产者接收来自消费者的请求,避免消息溢出。当然,这种算法只适用于能够节流的生产者;例如,当它们依靠静态集合或者可以通过Interator迭代的数据源。当生产者无法控制它所产生的数据的频率(源是外部的或Hot类型的)时,背压帮助不大。