新手问题 有没有这样一种 HTTP 请求方案?

ibachue · 2013年11月14日 · 最后由 linjunhalida 回复于 2013年11月16日 · 6527 次阅读

Hi all,

之前曾经在论坛上求助过大家《Ruby http 库没有 non-blocking 的 API 版本?》,收到了很多回复。但感觉似乎都是为异步的并行请求设计的,在并行请求期间代码其实依然是 block 的,我现在还想寻求一种 Ruby non-blocking API 的方法,非并行请求的,不设置成功或者失败后的 Callback,无视结果,使得真正做到方法调用后不用管,这样从而达到 Non-blocking 的效果。请问有没有这种方案?

谢谢大家

改成发邮件就好了嘛

#1 楼 @bhuztez 发邮件本身也是 block 的啊

#2 楼 @iBachue 直接 fork 发啊

#3 楼 @bhuztez 那不是性能影响比 Thread 还大?

#4 楼 @iBachue 为什么会影响啊?fork 完就不管了啊

#5 楼 @bhuztez 不是要创建一个新的进程嘛?效率不高啊

#6 楼 @iBachue 怎么体现出效率不高,不就 fork 了一个进程么

#7 楼 @bhuztez 我大学时候读的 Kernel 源码,感觉 fork 一个进程执行的代码相当长而且复杂。一般感觉只要是 syscall 效率都不会很高。

#8 楼 @iBachue 代码长并且复杂不代表效率不高吧。。说不定时间片切换的消耗比 fork 的消耗大。 “非并行请求的,不设置成功或者失败后的 Callback,无视结果,使得真正做到方法调用后不用管”,这个设置 callback 为空就可以了吧?

为啥不用管啊?那可以直接 fork 一个 curl 出来?

#8 楼 @iBachue 要达到你说的这个,那么需要映射回 C 语言里面的模型,调用底层的发送库,然后编译一个 gem 自己用其实就好了吧。

#9 楼 @linjunhalida 当然没这么简单,很多号称 non-blocking 的 http 发送实际执行的时候还是在明显的 block(最简单的例子就是EM.run),无论 callback 是否为空。我希望的就是真正 non-blocking。

#11 楼 @linjunhalida 底层东西我就不懂了呀。。哪个 C 的发送库能够实现这个功能呢?

#10 楼 @nouse 嗯。。因为发送的数据并不重要,事实上即使发送不成功也无所谓。正是因为无所谓,所以也不希望损耗过多的性能在站上面。fork 一个 curl 还是 fork 吧。。

#9 楼 @linjunhalida

代码长并且复杂不代表效率不高吧。。说不定时间片切换的消耗比 fork 的消耗大。

这个我也没比较过呀。。我觉得我不懂 OS 底层的东西简直和文盲差不多。。

#16 楼 @iBachue 看过 linux 源码还说不懂底层的东西。。。强。。

#17 楼 @linjunhalida 又不是看最新版本的。。这也叫懂?关键是我还不懂硬件,所以对于 Kernel 源码也只是一知半解。。

#15 楼 @xds2000

是 Stream API? https://dev.twitter.com/docs/streaming-apis

这个相当于挂长连接了吧?其实对于 HTTP 而言,一般挂长连接的时候是只收不发的,比如 SSE 就是这样。 如果要做到一直发,就不能用 HTTP 了。。

#13 楼 @iBachue 你还是要实现丢一个 http post 请求给 solr,然后其他就不管了。不过 http 协议还是要收个结果回来,那么就不能直接用 http,生成数据,然后用 tcp 丢过去,之后断掉不管了。。

#20 楼 @linjunhalida 说得也是。我觉得我这思路其实很接近 UDP 的。。

#21 楼 @iBachue 我觉得按照这种丢掉不用管得思路,应该丢队列。队列处理完拉倒。

#22 楼 @linjunhalida 你是说 resque 那种?我们的 OPS 大概是不会批准的吧。。我们项目里倒是 delayed job,但是我觉得往表里写数据和发送 http 请求相比效率差不多的。。。

@iBachue 你这个需求已经不是应用层的协议了。直接到下面一层 TCP 吧。

#23 楼 @iBachue 为什么不会批准?大系统不可能没有用到队列的吧?

#24 楼 @xds2000

你这个需求已经不是应用层的协议了。直接到下面一层 TCP 吧。

好吧。。。大概确实如此。。

#25 楼 @linjunhalida 我们只有一个效率很慢的 delayed job,这是因为数据库本来就要维护。resque 要用到 redis 就需要 ops 做额外工作去维护了呀,工作量变大又不涨工资的事情他们能批准嘛?

#27 楼 @iBachue 靠,技术的东西扯到政治就复杂了。。

恩,跑通了,我做了一个样例,你看看: https://github.com/halida/nonblocking_http

跑的结果:

 $ ruby client.rb
on nonblock tcp
Time elapsed 0.000794 seconds
on blocking http
Time elapsed 2.003173 seconds

不过 request 内容要你自己用一个库来生成。

#29 楼 @linjunhalida 哇 好棒!!谢谢!

#32 楼 @iBachue 不过建立连接和断开连接都是 block 的,不能算是完全的啥都不关心,不过对方服务器 solr 应该是局域网的,并且支持多连接,问题不大。

这个也许对你有帮助: https://github.com/brandonhilkert/sucker_punch

源码我还没看,如果你看了给总结下 :)

#29 楼 @linjunhalida

恩,跑通了,我做了一个样例,你看看: https://github.com/halida/nonblocking_http

我觉得可以基于这个方法做一个 HTTPRequest 的 gem 了

#34 楼 @knwang 看上去不错的样子嘛

@linjunhalida @iBachue 就是一个 sendmsg_nonblock 而已啊?

#37 楼 @zgm 刚刚看了下 net/http 的源码 感觉把这个改装一下很容易就可以获得一个完整的 nonblocking 的 http 库了。。

这样下去不能算 HTTP 了吧。

#39 楼 @iBachue 根本不用改装,你只要发一个 TCP 装成 HTTP 的样子到 HTTP Server, 不 read response 都能实现你的要求。

#41 楼 @zgm 那还有 POST 请求呢 HTTPS 请求呢?还是在人家的轮子上改进比较好

不负责猜测,把 net/http 里面 read response 的部分删了,估计就是你要的了... 哈哈。

#43 楼 @zgm 嗯 你太小看 HTTP 请求了 人家功能是很强大的。。

就是只要 HTTP 的 Request 部分,无视 Response 部分

用 head 请求..

#46 楼 @jjym HEAD 请求当 GET 处理的 但是有时候我们可能只要 POST 或者 PUT 或者 DELETE 请求。。

#46 楼 @jjym HEAD 也要读 header 的,只是不读 body 而已

#48 楼 @zgm 对了,差点忘了。而且那个 nonblocking 版 client 关闭太快难道不是有可能引起 server 异常么

#49 楼 @jjym client 都已经自己主动关闭了,server 再出现异常就说不过去了。

#50 楼 @linjunhalida 也对,server 肯定考虑这种情况了

#34 楼 @knwang

这个也许对你有帮助: https://github.com/brandonhilkert/sucker_punch

Ruby 中竟然有这么神奇的异步库 了不起啊!是该好好学习源码了

#50 楼 @linjunhalida @jjym 如果不用 EM 呢?

#53 楼 @zgm server.rb 我就随手拷贝用来做测试用例的。client.rb 才是做 nonblocking 的。 这个示例的意思是,丢 http 请求然后什么都不管了其实是一个很简单的事情,建立 tcp 连接,丢数据,close 掉就好了,不至于那么复杂啊,不需要讨论那么多的。

https://github.com/typhoeus/typhoeus 这个行不行,可以做并行的。

#55 楼 @jimrokliu 不是要并发请求啊。。。是真正的无阻塞

#56 楼 @iBachue typhoeus 使用了https://github.com/typhoeus/ethonhttps://github.com/ffi/ffi,来完成 libcurl 的包装。libcurl 是支持非阻塞方式调用的。

#57 楼 @jimrokliu 那你给个 Example?那个 README 所有 Example 我都研究过的,没有符合要求的

#58 楼 @iBachue 仔细看了你前面说的确实不满足的要求。你这可是不完整的 http 请求啊。标准做法要回给客户端状态的,你这突然掐断,你猜写服务器代码的这些人怎么给你回应,直接抛个异常记录到 log 里。不停的抛 exception 还不拖垮了服务器。

#59 楼 @jimrokliu 至少我在本地用 Sinatra 做测试的时候是不发生 Exception 的

#59 楼 @jimrokliu 我前面说了,建立和断开 tcp 连接保持正常,但是 http 协议层面上面只发送不接收,一般的服务器是没有问题的。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号