具有持久性的 HTTP POST 请求的非阻塞队列

Posted

技术标签:

【中文标题】具有持久性的 HTTP POST 请求的非阻塞队列【英文标题】:Non-blocking queue of HTTP POST requests with persistence 【发布时间】:2012-07-19 12:24:11 【问题描述】:

在我们开发自定义解决方案之前,我正在寻找某种库,它提供:

HTTP 请求的非阻塞队列

具有这些属性:

保持请求以避免在以下情况下丢失: 网络连接中断 应用退出,后台应用强制 GC 等等.. 可以排除所有这些字段: 地址 标题 POST 数据

那么请问,有什么有用的知道吗,有什么可以节省我们一整天的时间来开发这个?

现在我们不需要对完成的请求进行任何回调,也不需要保存结果数据,因为不会有这样的。

【问题讨论】:

看起来你需要开发一个。 @ChenKinnrot 我只是希望这是我们应该在 android 平台上解决多年的常见问题。 我没有遇到这样的问题,但我认为推出自己的实现并不难。使用 Java 非阻塞 IO,您可以启动一个服务器套接字以同时接受所有请求,保存发布给您的所有内容的原始字节,稍后以您喜欢的方式处理请求。 @MarekSebera,如果我理解正确,您正在尝试在收到请求时坚持该请求。这种期望是在原始套接字级别(原始请求)还是在解析请求的更高级别? @Santosh,我正在尝试在离线时或从客户端应用程序生成许多请求时保留请求,以便稍后根据网络可用性和 httpclient 并发发送到服务器。在用户退出应用程序或 GC 将在后台杀死它的情况下,坚持到本地文件系统/db/whatever。我对解析来自服务器的响应没有兴趣(但这将是奖励功能)。在请求中,我需要指定额外的标头、URL 和 POST 数据(如果声明请求是 POST 而不是 GET) 【参考方案1】:

以我的拙见,一个好的和直接的解决方案是使用复杂的连接处理框架开发自己的层(不应该那么复杂),例如 Netty https://netty.io/ ,以及用于异步处理的复杂框架,例如 Akka http://akka.io/

让我们先来看看 Netty 在http://static.netty.io/3.5/guide/#architecture.8 对 http 的支持:

4.3。 HTTP 实现

HTTP 绝对是 Internet 上最流行的协议。已经有许多 HTTP 实现,例如 Servlet 容器。那么为什么 Netty 在其核心之上有 HTTP 呢?

Netty 的 HTTP 支持与现有的 HTTP 库非常不同。它使您可以完全控制在低级别交换 HTTP 消息的方式。因为它基本上是 HTTP 编解码器和 HTTP 消息类的组合,所以没有强制线程模型等限制。也就是说,您可以编写自己的 HTTP 客户端或服务器,完全按照您想要的方式工作。您可以完全控制 HTTP 规范中的所有内容,包括线程模型、连接生命周期和分块编码。

现在让我们深入了解Akka。 Akka 是一个在 Java 并发 API 之上提供优秀抽象的框架,它带有 Java 或 Scala 的 API。

它为您提供了一种将应用程序构建为 actors 层次结构的清晰方法: Actor 通过消息传递进行通信,使用不可变消息,因此您不必关心线程安全 Actors 消息存储在消息框中,可以持久化 演员有责任监督他们的孩子 Actor 可以在一个或多个 JVM 上运行,并且可以使用多种协议进行通信 它为异步处理提供了一个轻量级的抽象Future,比Java Futures更容易使用。 它提供了其他花哨的东西,例如事件总线、ZeroMQ 适配器、远程支持、数据流并发、调度器

一旦您熟悉了这两个框架,就会发现通过它们可以轻松编写您需要的代码。

事实上,您需要的是一个用 Netty 编码的 http 代理,它在收到请求后立即向 FSM 类型的 Akka Actor 发送消息(http: //doc.akka.io/docs/akka/2.0.2/java/fsm.html) 使用耐用邮箱 (http://doc.akka.io/docs/akka/2.0 .2/modules/durable-mailbox.html)

【讨论】:

哇,超级答案,我需要查看所有提到的,但这看起来确实像适合企业/企业使用的解决方案。我只是想知道(我需要调查一下)它将如何扩大应用程序的大小(所需的库大小)以及在现有解决方案中如何容易实现:)) 如果你愿意尝试学习一些 Scala,我可以保证你会用不到 1000 行代码来完成它,因为 Scala 简洁。当然 Scala 可以编译成合法的 Java 字节码,所以一切都可以互操作 当然,我在最近的一个 Spring 项目中遇到了 Scala,看起来,是时候从标准 Java 转移到 Scala/Groovy/等了。因为这些正在变得又快又好最近的进展:) 请看***.com/questions/5453602/… 附加评论:由于没有广泛采用的内部开发解决方案将具有更高的初始成本,但会降低维护和升级成本,而如果您获得由其他人编写的代码......祝你好运!【参考方案2】:

Here 是一个开源库的链接,该库是布拉格捷克技术大学一名学生的硕士论文。它是一个非常大且功能强大的库,主要关注位置。不过,它的好处是它省略了 REST 所具有的标头和其他内容。

这是最新的分支,希望它至少能给你“自己的”解决方案的灵感。

【讨论】:

【参考方案3】:

那些并发集合怎么样:

http://mcg.cs.tau.ac.il/projects/concurrent-data-structures

我希望许可证没问题。

【讨论】:

您能否举个例子来扩展您的答案?我无法识别这 7 个并发数据结构中的哪一个,应该回答我的问题。 集合非常基础,甚至比java的还要多。原因是它们需要并发。在性能上做了更多的努力。无论如何,您写道您需要一个队列,因此选择一个队列,并使其适合您的需求(因为您需要使其与 http 请求一起使用)。这些集合非常通用。它们应该适用于任何数据类型。【参考方案4】:

你会想看看这些帖子。 (添加在文档末尾)

基本上,一种对我来说非常有效的方法是将请求与队列和执行程序分开。 请求作为 Runnables 或 Callables 执行。从它们继承以创建对您的 API 或服务的不同类型的请求。在执行它们之前将它们设置在那里添加标题和/或正文。

将这些请求排入队列(选择更适合您的 - 我会说LinkedBlockingQueue 将完成这项工作)链接到绑定服务内的执行程序,并从您的活动或任何其他范围调用它们。如果您不需要获取响应和回调,您可以避免使用 Guava 来监听期货或创建自己的回调。

我会继续关注的。如果您需要更多深度,我可以发布一些特定的代码。不过,第一个链接中有一个基本示例的来源。

http://ugiagonzalez.com/2012/08/03/using-runnables-queues-and-executors-to-perform-tasks-in-background-threads-in-android/

http://ugiagonzalez.com/2012/07/02/theres-life-after-asynctasks-in-android/

更新:

您可以为那些无法执行的请求创建另一个队列。 我想到的一种方法是将所有失败的请求添加到重试队列中。当手机仍然认为有任何类型的互联网连接可用时,重试队列将尝试重新运行这些任务。在请求对象中,您可以设置最大重试次数,并将其与每次重试时增加的 currentRetry 数进行比较。 嗯,这可能很有趣。我一定会考虑将它纳入我的图书馆。

【讨论】:

感谢 José 的输入,您所说的解决方案是将任务排入某些 Executors 服务的解决方案,该服务将对它们起作用。你的回答只涉及到问题的一半。主要问题是以某种简单的方式持久化请求,并让它们在我们有网络连接后立即在远程服务器上执行,并仅在成功发送请求时将它们从队列中删除(可能由 HTTP 结果代码定义)。所以库/包提供的循环是异步请求队列,网络不存在时请求持久化。

以上是关于具有持久性的 HTTP POST 请求的非阻塞队列的主要内容,如果未能解决你的问题,请参考以下文章

C中的非繁忙阻塞队列实现

实现有界缓冲区(读取器和写入器之间的非阻塞,读取器之间的阻塞,写入器之间的阻塞)

HTTP 请求之间具有持久状态的模型

Redis实现简单消息队列

NodeJShttp请求获取get和post参数

9. 阻塞队列