我正在重新考虑我们的Spring MVC应用程序行为,是否更好地从数据库中拉(Java8 Stream)数据或让数据库推送(Reactive / Observable)它的数据和使用背压来控制数量。
现状:
User
请求最近的30篇文章Service
执行数据库查询并将30个结果放入List
Jackson
遍历List
并生成JSON响应为什么要切换实施?
这非常耗费内存,因为我们始终将这30个对象保存在内存中。这不是必需的,因为应用程序一次处理一个对象。虽然应用程序应该能够检索一个对象,处理它,扔掉它,然后获取下一个。
Java8 Streams? (拉)
使用java.util.Stream
这很容易:Service
创建一个Stream
,它在幕后使用数据库光标。每次Jackson
为Stream
的一个元素写入JSON字符串时,它会询问下一个元素,然后触发数据库光标返回下一个条目。
RxJava / Reactive / Observable? (推)
这里我们有相反的情况:数据库必须按条目推送,Jackson
必须为每个元素创建JSON字符串,直到调用onComplete
方法。
即。 Controller
告诉Service
:给我一个Observable<Article>
。然后Jackson
可以请求尽可能多的数据库条目。
差异与关注:
对于Streams
,要求下一次数据库输入和检索/处理之间总会有一些延迟。如果网络连接速度很慢或者为了完成响应而需要进行大量的数据库请求,这可能会减慢JSON响应时间。
使用RxJava
应始终有可供处理的数据。如果它太多了,我们可以使用背压来减慢从数据库到我们应用程序的数据传输速度。在最坏的情况下,缓冲区/队列将包含所有请求的数据库条目。然后使用List
将内存消耗等于我们当前的解决方案。
我为什么要问/我要求的是什么?
我错过了什么?还有其他优点/缺点吗?
为什么(特别是)Spring Data Team扩展其API以支持来自数据库的Stream
响应,如果每个数据库请求/响应之间总是有(短)延迟?对于大量请求的条目,这可能会导致一些显着的延迟。
建议在这种情况下使用RxJava
(或其他一些反应式实施)吗?或者我是否遗漏了任何缺点?
答案 0 :(得分:2)
您似乎在谈论底层数据库引擎的获取大小。
如果你将它减少到一个(一次取一行并处理一行),是的,你会在请求时间内节省一些空间......
但是通常有合理的块大小是有意义的。 如果它太小,你会有很多昂贵的网络往返。如果块大小太大,则存在内存不足或每次提取引入过多延迟的风险。所以这是一个折衷方案,正确的块/提取大小取决于您的具体用例。
关于被动方式与否,我认为这是不相关的。与RxJava和Cassandra一样,可以从异步结果集创建一个Observable,并且由查询(配置)决定应该一次提取和推送多少项。