我想知道是否可以使用http-kit整合一个完全无阻塞的Clojure后端Web应用程序.
(实际上任何与Ring兼容的http服务器都没关系;我提到了http-kit,因为它声称有一个事件驱动的非阻塞模型).
这个问题是我对非阻塞/异步/事件驱动系统性质的一些误解的症状.如果你和我在同一个地方,这里有一些澄清.
只有当所有(例如,大多数)IO从头开始以非阻塞方式处理时,才能使事件驱动系统具有非阻塞的性能优势(如在Node.js中).这意味着所有数据库驱动程序,HTTP服务器和客户端,Web服务等都必须首先提供异步接口.特别是:
现在,具体来说:
如果我做对了(我不是专家,所以请告诉我,如果我正在做错误的假设),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) 我有一个输入流,我想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种方法:
go例程拉开了频道.每个请求都通过deref来自HTTP请求的promise 来"阻止"goblock .这不起作用,因为我认为这个承诺不会与线程一起发挥作用.future,这将阻止异步承诺.这导致非常高的CPU使用率.再加上网络资源的饥饿.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) 我是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
它有效,但我很难确认这是否是正确的方法.
我有点困惑如何创建http-kit WebSocket客户端.在网站上有一个例子如何创建WebSocket服务器,创建客户端可能是微不足道的,但我似乎无法做到正确.那些没有专注于Javascript客户端的例子?
PS在这个问题中有一些讨论,但只有aleph示例,并且表明http-kit现在支持WebSocket客户端.
我正在制作一个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 流连接(它是 Gnip 合规流)。
我想使用HTTP Kit,但我无法让它工作。如果我通过:stream参数:
@(http/get "http://example.com/stream-connection" {:as :stream})
Run Code Online (Sandbox Code Playgroud)
在请求关闭之前响应不会返回(并且永远不会完成)。
有没有办法做到这一点?
我已经用clj-http尝试过同样的事情,但没有运气。
有没有办法在运行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?
我们有一个使用 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根据请求提供不同的版本?
我目前正在权衡使用Elixir vs Clojure来运行Web服务器来处理许多并发Web套接字连接.现在Elixir/Phoenix似乎很适合这一点,你会看到基准测试表明它的扩展程度(我怀疑这与现实生活负荷有关).但是,我们的大多数基础设施都是用Clojure编写的.
在我们的例子中,websocket处理程序几乎完全独立于现有代码库的其余部分.
所以问题是 - 你会考虑采用另一种语言/生态系统,因为它更适合某项特定工作吗?vs使用已经是现有生态系统很大一部分的工具.
并且,Elixir/Phoenix在真实世界负载下是否会超过Clojure/JVM以进行此类任务以证明使用它?
clojure ×9
http-kit ×9
core.async ×3
ring ×3
http ×2
asynchronous ×1
client ×1
compojure ×1
elixir ×1
heroku ×1
networking ×1
nonblocking ×1
websocket ×1