继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Spring 响应式编程 随记 -- C3 响应式流 新的标准流 (二)

维生素P
关注TA
已关注
手记 42
粉丝 8343
获赞 253

系列文章

3.1.3 流量控制问题

上一个小节通过消息的推拉模型对比,可以得到结论,使用推模型主要的原因,是因为它减少了请求量和闲等,从而优化了整体的处理时间。因此 RxJava 1.x 以及类似的库,都是以推送消息数据为目的去设计的,使的流技术能够更高校的处理分布式系统组件中间的重要通信。

另一方面,推模型也是有局限性的。

消息驱动通信的本质是假设每个请求都会有一个响应,因此服务可能收到异步的潜在的无限消息流。

消费者的吞吐能力是有限的,这种场景可能会影响系统的整体稳定性,特别是下面两类情况。

【场景1】慢生产,快消费

这种一般是特定业务场景,消费者也可能是动态变化的,解决的关键是需要明确真正的消费需求和吞吐量,但纯推的模型是得不到这个消费者相关的信息的,所以没有办法动态增加系统的吞吐量,如果又一些指标可以指示消费者情况,也可以利用伸缩性增加生产者来给消费者增加负载。

除了消费者会等待时间比较长,使其性能表现差一些之外,这个场景不会有其他太糟糕的崩溃情况。

【场景2】快生产,慢消费

这种情况下生产者发生的大量数据远远超出了消费者的处理能力,并且会越堆积越多。消费者在压力负载下可能会有崩溃问题。

针对这种情况的一个常见方案是让消息去排队等待,将未处理的元素收集到消息队列中。这个队列可以构建在消费者和生产者之间,甚至消费者自己可以做一个消息排队维护,这样能够保证慢速处理前面的数据时,仍然能够来应对生产者继续产生的新数据。

队列的选型,需要去针对场景来分析合适的队列特性

通常有以下三种常见的队列:

  • 无界队列 UnbondedQueue
  • 有界丢弃队列 DropQueue
  • 有界阻塞队列 BlockingQueue

无界队列, 优点是能够保证消息可达,终究有一个时间点会去处理消息(即使需要等比较久),但是系统的响应回弹性会很差,因为大量消息的时候,会消耗大量存储资源,当资源达到上限的时候容易引发整体系统性的崩溃。

有界丢弃队列,考虑了资源的限制,根据资源能力来配置队列容量。当消息的可达重要程度不是那么高的时候(比如有重试机制,或者允许丢消息),通常会使用这种做法。丢弃策略,也需要根据业务场景来选择,比如丢弃新到消息,丢弃优先级低的消息,删除最早的消息,随机等均丢弃,丢弃到另一个死信队列等各种不同的策略。

有界阻塞队列, 指的是有能力阻塞生产者的处理队列。这种队列适合于重要消息必须保证可达,但无法提高吞吐量的情况。比如支付系统是绝对不允许丢失任何一个交易消息的。在队列满了之后,会直接和生产者交互使其阻塞等待。

但这种阻塞是和系统本身的异步设计完全冲突的。

一旦生产者把消息塞满了队列,它就会被阻塞,直到消费者消费掉至少一个消息,使得队列可用。

必须要保证这个最慢的消费者以及队列能工作,否则就会一直堵塞,这样则会导致一个最慢的消费者的吞吐量,变成了整个系统的吞吐量,有效的资源利用率很差。

这种场景和我们设计所追求的回弹性,弹性,即时响应都互相矛盾。这种队列使得整体的架构设计更加复杂。

所以纯推模型是有局限性的,在上述两个场景下,这些不受控制的情况要求系统设计本身,需要去考虑如何更加巧妙的响应负载,进而引出了 “背压机制”

RxJava 1.x 响应式库没有这种标准化功能,在纯粹的推模式中,我们可以使用批处理来稳定生产速率。

3.1.4 解决方案

好在2013年,一群来自 Lightbend,Netflix,Pivotal 的工程师为了解决上述问题给 JVM 社区提供了方案标准。

这就是 “响应式流规范”,也就是标准化的响应式流编程模式。

下一章将会详细展开。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP