标签: http-kit

我可以使用http-kit和core.async创建一个完全无阻塞的后端应用程序吗?

我想知道是否可以使用http-kit整合一个完全无阻塞的Clojure后端Web应用程序.

(实际上任何与Ring兼容的http服务器都没关系;我提到了http-kit,因为它声称有一个事件驱动的非阻塞模型).


编辑:TL; DR

这个问题是我对非阻塞/异步/事件驱动系统性质的一些误解的症状.如果你和我在同一个地方,这里有一些澄清.

只有当所有(例如,大多数)IO从头开始以非阻塞方式处理时,才能使事件驱动系统具有非阻塞的性能优势(如在Node.js中).这意味着所有数据库驱动程序,HTTP服务器和客户端,Web服务等都必须首先提供异步接口.特别是:

  • 如果您的数据库驱动程序提供同步接口,则无法使其成为非阻塞.(您的线程被阻止,无法检索它).如果你想要非阻塞,你需要使用其他东西.
  • 像core.async这样的高级协调实用程序无法使系统无阻塞.它们可以帮助您管理非阻塞代码,但不启用它.
  • 如果您的IO驱动程序是同步的,您可以使用core.async来获得异步的设计优势,但是您将无法获得它的性能优势.您的线程仍将浪费时间等待每个响应.

现在,具体来说:

  • 作为HTTP服务器的http-kit提供了非阻塞的异步接口.见下文.
  • 但是,许多Ring中间件由于它们基本上是同步的,因此与这种方法不兼容.基本上,任何更新返回响应的Ring中间件都不可用.

如果我做对了(我不是专家,所以请告诉我,如果我正在做错误的假设),Web应用程序的这种非阻塞模型的原则如下:

  1. 有一些超快的OS线程处理所有CPU密集型计算; 这些绝对不能等待.
  2. 有很多"弱线程"处理IO(数据库调用,Web服务调用,休眠等); 这些主要是为了等待.
  3. 这是有益的,因为在处理请求上花费的等待时间通常是2(磁盘访问)到5(Web服务调用)数量级高于计算时间.

从我所看到的,默认情况下,Play Framework(Scala)和Node.js(JavaScript)平台支持此模型,具有基于承诺的实用程序,用于以编程方式管理异步.

让我们尝试使用Compojure路由在基于Ring的clojure应用程序中执行此操作.我有一个通过调用my-handle函数构造响应的路由:

(defroutes my-routes
  (GET "/my/url" req (my-handle req))
  )
(def my-app (noir.util.middleware/app-handler [my-routes]))
(defn start-my-server! [] 
  (http-kit/run-server my-app))
Run Code Online (Sandbox Code Playgroud)

在Clojure应用程序中管理异步的普遍接受的方式似乎是基于CSP,使用core.async库,我完全没问题.因此,如果我想接受上面列出的非阻塞原则,我将以my-handle这种方式实现:

(require '[clojure.core.async :as a])

(defn my-handle [req]
  (a/<!!
    (a/go ; `go` makes channels calls asynchronous, so I'm not …
Run Code Online (Sandbox Code Playgroud)

clojure nonblocking ring core.async http-kit

35
推荐指数
1
解决办法
4832
查看次数

如何在Clojure(/ Java)中强大地生成大量并发HTTPS请求

我有一个输入流,我想HTTPS在将结果传递给程序的另一部分之前为每个输入生成2个网络请求.典型的吞吐量是每秒50.

for each input:
    HTTP request A
    HTTP request B
    pass event on with (A.body and B.body)
Run Code Online (Sandbox Code Playgroud)

我正在使用http-kit客户端,默认情况下是异步的.它返回一个promise,也可以进行回调.Http-kit使用Java NIO(参见此处此处)

请求的速度与发出请求的时间相结合,足够高,需要异步完成.

我尝试了3种方法:

  1. 当一个事件进来时,把它放在一个频道上.一些go例程拉开了频道.每个请求都通过deref来自HTTP请求的promise 来"阻止"goblock .这不起作用,因为我认为这个承诺不会与线程一起发挥作用.
  2. 当一个事件进入时,立即启动a future,这将阻止异步承诺.这导致非常高的CPU使用率.再加上网络资源的饥饿.
  3. 当一个事件进入时,http-kit立即触发请求A的请求,传入一个回调,它产生请求B,传递一个传递事件的回调.几小时后,这会导致内存不足错误.

这些都可以工作并处理一段时间的容量.他们最终都崩溃了.大约12个小时后最近的崩溃:

Mar 10, 2016 2:05:59 AM com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector run
WARNING: com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@1bc8a7f5 -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending
 tasks!
Mar 10, 2016 3:38:38 AM com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector run
WARNING: com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@1bc8a7f5 -- APPARENT DEADLOCK!!! Complete Status:
        Managed Threads: …
Run Code Online (Sandbox Code Playgroud)

networking asynchronous clojure core.async http-kit

9
推荐指数
1
解决办法
904
查看次数

使用core.async频道在clojure中使用http-kit的帖子结果是否合理?

我是clojure的新手,我正在编写一个库,将发布结果发送到服务器以获得响应.我通过将响应放在core.async通道上来消耗响应.这是理智还是有更好的方法?

以下是我正在做的事情的高级概述:

(defn my-post-request [channel options]
  (client/post http://www.example.com options
          (fn [{:keys [status headers body error]}] ;; asynchronous handle response
              (go (>! channel body)))))

(defn request-caller [options]
  (let [channel (chan)]
    (my-post-request channel options)
    (json/parse-string (<!! (go (<! channel))))))
Run Code Online (Sandbox Code Playgroud)

以下是我使用的实际代码:https://github.com/gilmaso/btc-trading/blob/master/src/btc_trading/btc_china.clj#L63

它有效,但我很难确认这是否是正确的方法.

clojure core.async http-kit

9
推荐指数
1
解决办法
3066
查看次数

HTTP Kit WebSocket客户端

我有点困惑如何创建http-kit WebSocket客户端.在网站上有一个例子如何创建WebSocket服务器,创建客户端可能是微不足道的,但我似乎无法做到正确.那些没有专注于Javascript客户端的例子?

PS在这个问题中有一些讨论,但只有aleph示例,并且表明http-kit现在支持WebSocket客户端.

client clojure websocket http-kit

7
推荐指数
2
解决办法
1745
查看次数

使用Clojure在Heroku上进行HTTP流/分块响应

我正在制作一个Clojure Web应用程序,该应用程序使用分块的HTTP响应将数据流式传输到客户端。当我使用本地运行它时,此方法效果很好foreman,但是当将其部署到Heroku时,它无法正常运行。

可以在我的github上找到一个展示这种行为的最小示例。前端(中的resources/index.html)执行AJAX GET请求,并在响应块到达时打印它们。服务器使用http-kit每秒向连接的客户端发送一个新块。按照设计,HTTP请求永远不会完成。

当将相同的代码部署到Heroku时,发送第一个块后,服务器将立即关闭HTTP连接。似乎是Heroku的路由网格导致了这种断开连接的发生。

这也可以通过使用curl执行GET请求来看到:

$ curl -v http://arcane-headland-2284.herokuapp.com/stream
* About to connect() to arcane-headland-2284.herokuapp.com port 80 (#0)
*   Trying 54.243.166.168...
* Adding handle: conn: 0x6c3be0
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x6c3be0) send_pipe: 1, recv_pipe: 0
* Connected to arcane-headland-2284.herokuapp.com (54.243.166.168) port 80 (#0)
> GET /stream HTTP/1.1
> User-Agent: curl/7.31.0
> Host: arcane-headland-2284.herokuapp.com
> Accept: */*
> 
< HTTP/1.1 …
Run Code Online (Sandbox Code Playgroud)

http clojure heroku chunked-encoding http-kit

5
推荐指数
1
解决办法
1273
查看次数

使用 HTTP Kit 进行流式连接/长轮询?

我正在尝试使用一个永远不会关闭的 HTTP 流连接(它是 Gnip 合规流)。

我想使用HTTP Kit,但我无法让它工作。如果我通过:stream参数:

@(http/get "http://example.com/stream-connection" {:as :stream})
Run Code Online (Sandbox Code Playgroud)

在请求关闭之前响应不会返回(并且永远不会完成)。

有没有办法做到这一点?

我已经用clj-http尝试过同样的事情,但没有运气。

http clojure http-kit

5
推荐指数
1
解决办法
321
查看次数

在运行服务器时注册多个处理程序

有没有办法在运行http-kit服务器时注册多个处理程序:

(defroutes rest-main-app
  (GET "/" "Welcome"))

(defroutes rest-events-app
  (GET "/events" "Event API"))

(defn -main []
  (run-server rest-main-app {:port 5000}))
Run Code Online (Sandbox Code Playgroud)

如何将两个路由都传递给运行服务器,例如rest-main-app和rest-events-app?

clojure compojure ring http-kit

3
推荐指数
1
解决办法
209
查看次数

环防伪中间件是否可以有条件应用?

我们有一个使用 HttpKit 来服务请求的 Web 应用程序和一个用 Ring 中间件包装的处理程序。

该处理程序类似于:

(def handler
  (->  #'req-handler
    (wrap-defaults site-defaults)
    (wrap-content-type-and-encoding)
    (wrap-cookies)
    (wrap-stacktrace)))
Run Code Online (Sandbox Code Playgroud)

在站点默认设置中可以找到:

 :security  { ...
              :anti-forgery         anti-forgery-setting
              ... }
Run Code Online (Sandbox Code Playgroud)

该应用程序过去仅服务来自浏览器的请求,但现在某些端点响应 API 请求,包括 POST 操作。

在文档中我可以读到:

如果没有有效的防伪令牌,此中间件将阻止除 GET 和 HEAD 之外的所有 HTTP 方法访问您的处理程序。

因此,您应该只将此中间件应用于应用程序中设计为通过 Web 浏览器访问的部分。此中间件不应应用于定义 Web 服务的处理程序。

有没有办法有条件地应用防伪设置,或者site-defaults根据请求提供不同的版本?

clojure ring http-kit

3
推荐指数
1
解决办法
135
查看次数

Clojure Web(HttpKit,Manifold)vs Elixir/Pheonix

我目前正在权衡使用Elixir vs Clojure来运行Web服务器来处理许多并发Web套接字连接.现在Elixir/Phoenix似乎很适合这一点,你会看到基准测试表明它的扩展程度(我怀疑这与现实生活负荷有关).但是,我们的大多数基础设施都是用Clojure编写的.

在我们的例子中,websocket处理程序几乎完全独立于现有代码库的其余部分.

所以问题是 - 你会考虑采用另一种语言/生态系统,因为它更适合某项特定工作吗?vs使用已经是现有生态系统很大一部分的工具.

并且,Elixir/Phoenix在真实世界负载下是否会超过Clojure/JVM以进行此类任务以证明使用它?

clojure elixir http-kit phoenix-framework

2
推荐指数
1
解决办法
677
查看次数