草庐IT

抛弃 TCP 和 QUIC 的 HTTP

dog250 2023-08-02 原文

下班路上发了一则朋友圈:

周四听了斯坦福老教授 John Ousterhout 关于 Homa 的分享,基本重复了此前那篇 It’s Time To Rep… 的格调,花了一多半时间喷 TCP…

Ousterhout 关于 Homa 和 TCP 之间的论争和论证,诸多反复回执,非常精彩:Is It Time to Replace TCP in Data Centers? && Response to Ivan Pepelnjak’s Blog Post && …

但本文我要说点和 Homa 有关又无关的东西,关于 HTTP 的。我觉得 HTTP 非常适合用 Message-Based protocol 传输。从 RFC2068 1.4 说起:

HTTP only presumes a reliable transport; any protocol that provides such guarantees can be used;

紧接着下面一段多余了:

In HTTP/1.0, most implementations used a new connection for each request/response exchange. In HTTP/1.1, a connection may be used for one or more request/response exchanges, although connections may be closed for a variety of reasons.

上面这段话的 connection 关键词深入人心,让人觉得理所当然。

HTTP 是个无状态协议,天然应被 Message-Based transport 承载,非常自然且合理,why not?所以根本不需要 QUIC,甚至不再需要 TCP。

Homa 号称 RPC-Oriented,但也可以 HTTP-Oriented,每一对 Request/Response 类似一次 RPC。不限于 Homa,任何一个 Message-Based transport 承载 HTTP 都是高尚的。

采用 Message 承载 HTTP,其生命周期和 HTTP 的无状态对应,限制在一次 Request/Response,也就再也无需 TCP 连接管理了。

传输层为每次 Request/Response 生成单机唯一的 Message ID,将 Request/Response 映射到 Message,将 Message 映射到 packet 完成 packetization,以 Message ID 区分,即可并行多个 Request/Response。走这条路线,可直接消除 TCP 的问题,也就没了 QUIC 存在的必要。

HTTP/1.0 多条 TCP 连接并行处理多个 Request/Response,考虑 TCP 连接开销不可扩展,HTTP/1.1 允许多个 Request/Response 复用同一条 TCP 连接,但连接复用引入了 HTTP HoL blocking,比如短 Response 跟在长 Response 后面,为解决 HTTP HoL blocking,HTTP/2 引入二进制分帧多路复用,但引入了 TCP HoL blocking,为了解决 TCP HoL blocking,搞出了 QUIC。

若一开始使用 Message 模式并行处理 Request/Response,问题消失,就没有创建多条 TCP 的必要,自然就不会遭遇连接开销过大问题,接下来的一连串问题都不存在。遗憾的是,HTTP/1.0 一开始采用了 TCP。

这一切的根源在于一开始用一个有状态的 byte stream 协议去承载一个无状态的 Message 交互,结果最终 QUIC 虽然 UDP-Based,却也成了 TCP-Like,造化弄人。

Message 承载 HTTP 可能让人觉得奇怪,可将 HTTP 换成 RPC 就变得很自然,明明一回事,这就是先入为主的力量。
随便就是两个问题,若 Response 有 2GB,Message 如何装得下,若 Response 只 1KB,丢了就没有足够的 packet 触发 fast retransmit。说到底还是在用 TCP 思维解决 Message 问题。

必须要明确,TCP fast retransmit 是大量报文一起发送时顺带的恩惠,不是必须的,如果 TCP 只发生 1 个报文,便不会触发 fast retransmit。至于 2GB 的 Response,虽然怎么看它都像一条流,但它其实还是 Message:

采用 Message 承载 HTTP 并不仅仅因为它解决了连接管理问题,更不是因为它看起来更合理,还有一个很重要的优势,Ousterhout 在分享 Homa 时也提到了,Message-Based 可以利用多核优势并行处理,提高计算资源利用率。

至于说 Message-Based 拥塞控制,今晚没时间写了,明天详细聊下 L4S。

好归好,但历史和现实的力量往往更强大。

HTTP 标准化前,只有 TCP 满足 “reliable” 需求,著名的 Web Server 全假设 HTTP 被 TCP 承载,浏览器根本没有动力和动机偏向 UDP,到 HTTP 标准化时,就有了 “most implementations used a new connection…” ,注意修饰词,most implementations,但实际上是 all implementations。

之前说过,若不是 Google 同时掌控 App Server 和 Chrome Browser,QUIC 同样很难演进,可即便是 QUIC,依然还是 TCP-Like,还是没能突破老路子。

TCP 的影响力渗透到了每一根汗毛,即使 Amazon SRD 也在 “纠正 TCP 的问题”,各个新的旧的 transport 都在被 TCP 牵绕,却几乎从来没能另辟蹊径解决根本核心的问题,也许这个问题和 TCP 根本就没关系,就像本文说的 HTTP。

任何一个新协议都要试图解决 TCP 的某个或某些问题而不是解决 TCP 上层逻辑真正的问题,这才是真正的问题。

以前就了解过 Homa,但只有听 Ousterhout 亲自讲的时候才会有仪式感,他不止一次提到 Message 如何如何比 byte stream 好,比如边界清晰,并行处理,负载均衡…但他也说了,Homa 是专治 DataCenter 的各种不服的,而不打算去卷公网… 可我 don’t think so. 我觉得 Message-Based protocol 可以更好承载 HTTP 在公网上传输(运营商友好性是问题,但这是后话),我觉得 HTTP 和 RPC 是一回事,无状态乒乓协议真不适合用 byte stream 承载,无论 TCP 还是 QUIC。我还是觉得现在几乎所有 transport 都被 TCP 影响了,任何一个新协议都要试图解决 TCP 的某个问题而不是解决 TCP 上层逻辑真正的问题。回头看,很多使用 TCP 的应用并不是非要用 TCP,而是没有别的选择借用 TCP,时间久了就成事实上的 TCP-Based。重新审视这些 “借用” 是高尚的。

浙江温州皮鞋湿,下雨进水不会胖。

有关抛弃 TCP 和 QUIC 的 HTTP的更多相关文章

  1. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  2. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  3. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  4. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  5. ruby-on-rails - Rails - 从命名路由中提取 HTTP 动词 - 2

    Rails中有没有一种方法可以提取与路由关联的HTTP动词?例如,给定这样的路线:将“users”匹配到:“users#show”,通过:[:get,:post]我能实现这样的目标吗?users_path.respond_to?(:get)(显然#respond_to不是正确的方法)我最接近的是通过执行以下操作,但它似乎并不令人满意。Rails.application.routes.routes.named_routes["users"].constraints[:request_method]#=>/^GET$/对于上下文,我有一个设置cookie然后执行redirect_to:ba

  6. ruby-on-rails - Heroku 吃掉了我的自定义 HTTP header - 2

    我正在使用Heroku(heroku.com)来部署我的Rails应用程序,并且正在构建一个iPhone客户端来与之交互。我的目的是将手机的唯一设备标识符作为HTTPheader传递给应用程序以进行身份​​验证。当我在本地测试时,我的header通过得很好,但在Heroku上它似乎去掉了我的自定义header。我用ruby​​脚本验证:url=URI.parse('http://#{myapp}.heroku.com/')#url=URI.parse('http://localhost:3000/')req=Net::HTTP::Post.new(url.path)#boguspara

  7. ruby-on-rails - 使用 HTTP.get_response 检索 Facebook 访问 token 时出现 Rails EOF 错误 - 2

    我试图在我的网站上实现使用Facebook登录功能,但在尝试从Facebook取回访问token时遇到障碍。这是我的代码:ifparams[:error_reason]=="user_denied"thenflash[:error]="TologinwithFacebook,youmustclick'Allow'toletthesiteaccessyourinformation"redirect_to:loginelsifparams[:code]thentoken_uri=URI.parse("https://graph.facebook.com/oauth/access_token

  8. ruby - HTTP 请求中的用户代理,Ruby - 2

    我是Ruby的新手。我试过查看在线文档,但没有找到任何有效的方法。我想在以下HTTP请求botget_response()和get()中包含一个用户代理。有人可以指出我正确的方向吗?#PreliminarycheckthatProggitisupcheck=Net::HTTP.get_response(URI.parse(proggit_url))ifcheck.code!="200"puts"ErrorcontactingProggit"returnend#Attempttogetthejsonresponse=Net::HTTP.get(URI.parse(proggit_url)

  9. ruby - 如何使用 Ruby HTTP::Net 处理 404 错误? - 2

    我正在尝试解析网页,但有时会收到404错误。这是我用来获取网页的代码:result=Net::HTTP::getURI.parse(URI.escape(url))如何测试result是否为404错误代码? 最佳答案 像这样重写你的代码:uri=URI.parse(url)result=Net::HTTP.start(uri.host,uri.port){|http|http.get(uri.path)}putsresult.codeputsresult.body这将打印状态码和正文。

  10. ruby - 让 bundler 使用 http : instead of git:? - 2

    我正在安装gitlabhq,并且在Gemfile中有对某些资源的“git://...”的引用。但是,我在公司防火墙后面,所以我必须使用http://。我可以手动编辑Gemfile,但我想知道是否有另一种方法告诉bundler使用http://作为git存储库? 最佳答案 您可以通过运行gitconfig--globalurl."https://".insteadOfgit://或通过将以下内容添加到~/.gitconfig:[url"https://"]insteadOf=git://

随机推荐