3

我正在重新考虑我们的 Spring MVC 应用程序行为,无论是从数据库中提取(Java8 Stream)数据还是让数据库推送(Reactive / Observable)数据并使用背压来控制数量更好。


现在的情况:

  1. User请求最近的 30 篇文章
  2. Service进行数据库查询并将 30 个结果放入List
  3. Jackson迭代List并生成 JSON 响应

为什么要切换实现?

这非常消耗内存,因为我们一直将这 30 个对象保存在内存中。这不是必需的,因为应用程序一次处理一个对象。尽管应用程序应该能够检索一个对象、对其进行处理、将其丢弃并获取下一个对象


Java8 流?(拉)

java.util.Stream很容易:Service创建一个Stream,它在幕后使用数据库游标。并且每次Jackson为 的一个元素写入 JSON 字符串时Stream,它会请求下一个元素,然后触发数据库游标返回下一个条目。


RxJava / 反应式 / 可观察?(推)

这里我们有相反的情况:数据库必须逐个推送条目,并且Jackson必须为每个元素创建 JSON 字符串,直到onComplete调用该方法。

Controller告诉Service给我一个Observable<Article>。然后Jackson可以请求尽可能多的数据库条目,因为它可以处理。


分歧和担忧:

请求下一个数据库条目和检索/处理它Streams之间总是有一些延迟。如果网络连接速度较慢或必须发出大量数据库请求来完成响应,这可能会减慢 JSON 响应时间。

使用RxJava应该始终有可用于处理的数据。如果它太多,我们可以使用背压来减慢从数据库到应用程序的数据传输。在最坏的情况下,缓冲区/队列将包含所有请求的数据库条目。那么内存消耗将等于我们当前使用List.


我为什么要问/我要什么?

  • 我错过了什么?还有其他优点/缺点吗?

  • Stream如果每个数据库请求/响应之间总是存在(短)延迟,为什么(特别是)Spring Data Team 扩展他们的 API 以支持来自数据库的响应?对于大量请求的条目,这可能会导致一些明显的延迟。

  • 是否建议在RxJava这种情况下使用(或其他一些反应式实现)?还是我错过了任何缺点?

4

1 回答 1

2

您似乎在谈论底层数据库引擎的提取大小。

如果您将其减少到一个(一次获取和处理一行),是的,您将在请求期间节省一些空间......

但通常有一个合理的块大小是有意义的。如果它太小,您将有很多昂贵的网络往返。如果块大小太大,您就有可能耗尽内存或在每次提取时引入过多的延迟。所以这是一种折衷方案,正确的块/获取大小取决于您的特定用例。

关于反应性方法与否,我认为这无关紧要。就像 RxJava 和 Cassandra 一样,可以从异步结果集中创建一个 Observable,这取决于查询(配置)一次应该获取和推送多少项。

于 2016-06-17T23:27:30.093 回答