一文看完 HTTP3 的演化歷程「轉」

HTTP 協議為 Web 的發展提供了驅動力,它始於 1991 年的 HTTP/0.9,在 1999 年演變為 HTTP/1.1,並由 IETF(互聯網工程任務組)負責進行標準化。HTTP/1.1 存在了很長一段時間,但 Web 不斷變化的需求要求推出更好的協議,於是 HTTP/2 在 2015 年出現了。IETF 最近宣佈要推出新的版本,即 HTTP/3。對於有些人來說,這是一個驚喜,但也會讓他們感到有一點點困惑。如果你沒有密切關注 IETF 的工作,就會覺得 HTTP/3 出現得很突然。不過,我們可以通過一系列實驗和 Web 協議的演變史來追溯它的起源,特別是 QUIC 傳輸協議。

如果你還不熟悉 QUIC,可以先看看我的一些同事所寫的文章。John 的這篇文章描述了當今 HTTP 世界的一些惱人之處,Alessandro 的這篇文章描述了傳輸層的實際細節,而 Nick 的這篇文章介紹瞭如何進行測試。我們在https://cloudflare-quic.com收集了更多的資源。如果你喜歡,請務必看一看我們用 Rust 實現的 QUIC 協議quiche。

HTTP/3 是 HTTP 應用程序到 QUIC 傳輸層的映射。這個名稱在第 17 版草案(draft-ietf-quic-http-17)中正式啟用,該草案於 2018 年 10 月底提出,在 11 月於曼谷舉行的 IETF 103 大會期間進行了討論並達成初步的共識。HTTP/3 之前叫作 HTTP over QUIC,再往前又叫 HTTP/2 over QUIC。在那之前,我們有 HTTP/2 over gQUIC,再往前,我們有 SPDY over gQUIC。事實上,HTTP/3 只是一種基於 QUIC(基於 UDP 的多路複用和安全傳輸)的 HTTP 新語法。

在這篇文章中,我們將探討 HTTP/3 舊名稱背後的歷史以及改名背後的動機。我們將回到 HTTP 的早期階段,介紹一路走來所做的工作。如果你想要獲得一個整體的視圖,可以打開這個非常詳細的SVG 版本。

HTTP/3 協議層

場景設定

在開始介紹 HTTP 之前,需要注意的是,有兩個協議都使用了 QUIC 這個名稱。gQUIC 通常用來表示谷歌 QUIC(原始協議),而 QUIC 通常用來表示 IETF 正在進行標準化的版本。

從 90 年代初期開始,Web 的需求已經發生了很大的變化。我們有了新版本的 HTTP,並增加了傳輸層安全(TLS)來增強安全性。

為了更好地解釋 HTTP 和 TLS 的歷史,我整理了協議規範和日期的細節。這些信息通常以文本形式呈現出來,例如按日期排序的項目列表。但因為存在標準分支,它們在時間上有所重疊,簡單的列表無法表達出這種複雜的關係。而且,在 HTTP 方面還存在一些並行的工作,這些工作通過重構核心協議來簡化使用,通過擴展協議來增加新的用途,以及通過重新定義數據交換方式來提高性能。要想跨越近 30 年的互聯網發展史和不同的工作流分支,並把它們串起來,需要對它們進行可視化。於是,我製作了 Cloudflare Secure Web Timeline。

接下來,我將按照這個時間表來解釋 HTTP 歷史的關鍵篇章。為了更好地理解本文的內容,最好先知道為什麼要進行協議標準化以及 IETF 是如何實現的。因此,在回到時間表之前,我們先簡要介紹這個主題。如果你已經很熟悉 IETF,可以跳過下面的部分。

互聯網標準的類型

通常,標準定義了共同的引用術語、範圍、約束、適用性和其他考慮事項。標準可以以多種形式存在,可以是非正式的(也就是所謂的“事實上的標準”)或正式的(由標準定義組織——例如 IETF、ISO 或 MPEG——同意或發佈)。標準被用在很多領域,甚至連茶葉都有一個正式的標準——英國製茶標準 BS 6008。

早期 Web 使用的是在 IETF 外部發布的 HTTP 和 SSL 協議,這些在 Secure Web Timeline 上被標記為紅線。客戶端和服務器對這些協議的採用使它們成為事實上的標準。

到了某個時刻,人們決定將這些協議正式化(後面部分將描述其背後的動機)。互聯網標準通常由 IETF 負責定義,IETF 的指導原則是“粗略共識和可運行的代碼”。這個原則以互聯網的開發和部署經驗為基礎,與嘗試在真空中開發完美方案的“clean room”方法是不一樣的。

IETF 互聯網標準被稱為 RFC。這個解釋起來很複雜,所以我建議你閱讀由 QUIC 工作組聯合主席 Mark Nottingham 撰寫的博文“如何閱讀 RFC”。這裡所謂的工作組(或 WG)一般是指郵件列表。

IETF 每年都會召開三次會議,為所有工作組提供時間和設施,如果他們願意,可以親自參加會議。會議期間的議程可能安排得非常緊湊,只有非常有限的時間可用於深入討論技術領域的問題。為了解決這個問題,一些工作組還選擇在 IETF 常規會議中間的幾個月召開臨時會議。自 2017 年以來,QUIC 工作組已經召開了幾次臨時會議,會議主頁上提供了完整的會議清單。

IETF 會議還為其他與 IETF 相關的人員提供了會面的機會,例如互聯網架構委員會(Internet Architecture Board)或互聯網研究工作組(Internet Research Task Force)。近年來,在 IETF 會議之前的週末都會舉行 IETF Hackathon。這為社區提供了開發可運行代碼的機會,更重要的是,可以與其他人在同一個房間裡進行互操作性測試,這樣有助於找出規範中存在的問題。

本文要強調的一點是,RFC 不是突然間出現的,它們一般會經歷一個過程,通常從 IETF 互聯網草案(I-D)開始。如果規範已經存在,那麼要準備一個 I-D 就很簡單,只需要進行簡單的重新格式化。I-D 從發佈之日起有 6 個月的有效期。要保持 I-D 的活躍狀態,就要發佈新版本。在實際當中,一個 I-D 的消失並不會產生多大後果,而且這種事情經常發生。這些文件會繼續託管在IETF 文檔網站上,任何想要閱讀它們的人都可以繼續訪問它們。

I-D 在 Secure Web Timeline 中使用紫色線條表示。每條線都有一個唯一的名稱,格式為 draft-{作者姓名}-{工作組}-{主題}-{版本}。工作組字段是可選的,有時會發生變化。如果一個 I-D 被 IETF 採納,或者直接由 IETF 內部發起,名字則為 draft-ietf-{工作組}-{主題}-{版本}。I-D 可能會有分支,會發生合併,或者分支直接停止發展。版本從 00 開始,每次發佈新草案時增加 1。例如,I-D 第 4 稿的版本為 03。如果 I-D 名稱發生變化,版本將重置為 00。

需要注意的是,任何人都可以向 IETF 提交 I-D,但你不應該把它們當作標準來看待。如果 IETF 的標準化流程針對某個 I-D 達成了共識,並且最終文檔通過了評審,我們最終會得到一個 RFC。在這個階段名稱會再次發生變化。每個 RFC 都會獲得一個唯一的編號,例如 RFC 7230。這些在 Secure Web Timeline 上使用藍線表示。

RFC 是不可變文檔,這意味著修改 RFC 後需要一個全新的編號。修改 RFC 可能是為了合併勘誤(編輯方面或技術方面的錯誤)或為了改進規範的佈局。RFC 可能會淘汰舊版本(完全替換),或者更新它們(實質性變更)。

所有 IETF 文檔均可在http://tools.ietf.org上公開獲得。我個人認為IETF Datatracker對用戶更加友好,因為它提供了文檔的進度可視化。

下面是一個例子,顯示了 RFC 1945(HTTP/1.0)的開發過程,很顯然,它是 Secure Web Timeline 的靈感來源。

有趣的是,在我創建 Secure Web Timeline 的過程中,我發現上面的可視化其實是不對的。由於某種原因,它缺少了 draft-ietf-http-v10-spec-05。由於 I-D 的生命週期是 6 個月,因此在成為 RFC 之前似乎存在一個空白,實際上,草案 05 在 1996 年 8 月之前仍然有效。

Secure Web Timeline

在稍微瞭解了互聯網標準文檔的實現方式之後,現在可以開始介紹 Secure Web Timeline 了。接下來將展示一些圖表,它們顯示了整個時間表的重要部分。每個點代表文檔或功能的可用日期。對於 IETF 文檔,為清晰起見,省略了草案編號。如果你想查看所有詳細信息,請參看完整的時間表。

HTTP 從 1991 年的 HTTP/0.9 協議開始,在 1994 年發佈了 draft-fielding-http-spec-00,這個 I-D 很快被 IETF 採用,改名為 draft-ietf-http-v10-spec-00。這個 I-D 在 1996 年成為 RFC 1945(HTTP/1.0)之前經歷了 6 個草案版本。

但是,在 HTTP/1.0 相關工作完成之前,另一項與 HTTP/1.1 相關的工作就已啟動。draft-ietf-http-v11-spec-00 於 1995 年 11 月發佈,並於 1997 年正式作為 RFC 2068。你們可能已經發現 Secure Web Timeline 中並未完全捕獲這一系列事件,這是可視化工具的問題。

1997 年中期,HTTP/1.1 的修訂工作啟動了,對應的 I-D 為 draft-ietf-http-v11-spec-rev-00。這項工作於 1999 年完成,並作為 RFC 2616 發佈。2007 年之前,IETF 的 HTTP 世界都很平靜。

SSL 和 TLS 簡史

SSL 2.0 規範在 1995 年左右發佈,而 SSL 3.0 則在 1996 年 11 月發佈。有趣的是,SSL 3.0 對應的 RFC 6101 於 2011 年 8 月發佈。根據 IETF 的說法,這屬於“Historic”,即“通常是為了記錄那些被考慮過但又被放棄的想法,或者在決定記錄它們時就已經是 Historic 的協議”。對於這種情況,擁有一個描述 SSL 3.0 的 IETF 文檔是有好處的,因為它可以作為規範在其他地方被引用。

我們更感興趣的是 SSL 是如何激發了 TLS 的開發,TLS 從 1996 年 11 月開始,I-D 為 draft-ietf-tls-protocol-00。它經歷了 6 個草案版本,並在 1999 年初作為 RFC 2246(TLS 1.0)發佈。

在 1995 年到 1999 年期間,SSL 和 TLS 協議被用於保護 HTTP 通信。作為一種事實上的標準,這種方式運作得很好。直到 1998 年 1 月,隨著 draft-ietf-tls-https-00 的發佈,HTTPS 的正式標準化過程才開始。這項工作在 2000 年 5 月結束,發佈了 RFC 2616(HTTP over TLS)。

TLS 在 2000 年至 2007 年期間繼續演化,出現了 TLS 1.1 和 TLS 1.2。TLS 的下一個版本於 2014 年 4 月被採用,即 draft-ietf-tls-tls13-00。在經歷了 28 個草案之後,於 2018 年 8 月成為 RFC 8446(TLS 1.3)。

互聯網標準化進程

我希望你能夠通過仔細觀察時間表瞭解 IETF 的工作原理。互聯網標準的形成大致是這樣的:研究人員或工程師設計適合特定用例的實驗性協議,然後在不同規模水平公開或私下對協議進行實驗。實驗數據有助於識別或改進問題。相關工作可能被公開,用於向公眾作出解釋,收集更廣泛的意見,或找到其他實現者。那些採用了早期工作成果的人讓實驗協議成為了事實上的標準,對實驗協議成為正式標準起到了促進作用。

對於正在考慮實現、部署或以某種方式使用協議的組織而言,協議的狀態是一個重要的考慮因素。正式的標準化過程會讓事實上的標準更具吸引力,因為它會帶來更高的穩定性。但需要注意的是,並非所有正式標準化都能獲得成功。

確定最終標準的過程幾乎與標準本身一樣重要。以最初的想法為基礎,邀請人們一起來貢獻想法,這些人擁有更廣泛知識和經驗,可以為更廣泛的人群帶來更有用的東西。但是,標準化過程並不總是那麼容易,陷阱和障礙總是存在的。有時候,這個過程需要很長時間,以至於最終得到的結果已經變得不那麼重要了。

Cloudflare 的可運行代碼

Cloudflare 很自豪能夠成為不斷髮展的新協議的早期採用者。我們很早就開始採用新標準,如 HTTP/2,我們還嘗試使用實驗性或尚未最終確定的功能,如 TLS 1.3 和 SPDY。

在 IETF 標準化過程中,將可運行的代碼部署在跨不同網站的真實網絡上可以幫助我們瞭解協議在真實環境中的運行情況。我們將現有的專業知識和從實驗中獲得的信息結合起來,用以改進可運行的代碼,並向正在標準化協議的工作組反饋有意義的問題和改進意見。

測試新的東西並不是唯一的優先事項。創新者應該知道什麼時候該前進,什麼時候該把舊的創新拋在腦後。有時候這與面向安全的協議有關,例如,由於 POODLE 漏洞,Cloudflare 默認禁用了 SSLv3。在其他情況下,舊協議會被更先進的新協議所取代,Cloudflare 就使用 HTTP/2 替換了 SPDY。

相關協議的引入和棄用在 Secure Web Timeline 上使用橙色線表示。虛線豎線有助於將 Cloudflare 事件與相關的 IETF 文檔關聯起來。例如,Cloudflare 在 2016 年 9 月引入了 TLS 1.3 支持,而 RFC 8446 最終版在兩年後的 2018 年 8 月發佈。

HTTP 重構

HTTP/1.1 是一個非常成功的協議。時間表顯示,在 1999 年之後,IETF 就沒有太多的動作。然而,真實的情況是,多年的使用經驗發現了 RFC 2616 中潛在的問題,這些問題導致了一些互操作性問題。此外,其他 RFC(如 2817 和 2818)擴展了 RFC 2616。2007 年,IETF 決定啟動一項新工作,以改進 HTTP 協議規範。這項工作被稱為 HTTPbis(“bis”源於拉丁語,意為“兩個”、“兩次”或“重複”),併成立了新的工作組。原始章程描述了他們試圖解決的問題。

簡單地說就是 HTTPbis 決定重構 RFC 2616。它將合併勘誤修復,並借鑑在此期間發佈的其他一些規範的某些方面。他們將文檔分成了幾個部分,於 2007 年 12 月發佈了 6 個 I-D:

draft-ietf-httpbis-p1-messagingdraft-ietf-httpbis-p2-semanticsdraft-ietf-httpbis-p4-conditionaldraft-ietf-httpbis-p5-rangedraft-ietf-httpbis-p6-cachedraft-ietf-httpbis-p7-auth

上圖顯示了在最終標準化之前,這項工作如何通過長達 7 年的起草過程,發佈了 27 個草案版本。2014 年 6 月,發佈了所謂的 RFC 723x 系列(其中 x 的範圍為從 0 到 5)。HTTPbis 工作組主席用“RFC2616 已死”來慶祝這一成就,也就是說這些新文件將使舊的 RFC 2616 作廢。

這與 HTTP/3 有什麼關係?

當 IETF 正忙於 RFC 723x 系列時,這個世界並沒有停下發展的腳步。人們繼續在互聯網上增強、擴展和試驗 HTTP。其中就包括谷歌,谷歌已經開始試驗一種叫作 SPDY(發音為 speedy)的協議。谷歌宣稱,這個協議旨在提高 Web 瀏覽的性能。2009 年底,SPDY v1 發佈,很快又在 2010 年推出 SPDY v2。

我不打算深入解釋 SPDY 的技術細節,關鍵的是要知道,SPDY 採用了 HTTP 的核心範式,並對數據交換格式稍作修改。事後看來,HTTP 明確劃分了語義和語法。語義描述了請求和響應交換的概念,包括:方法、狀態碼、標頭(元數據)和正文(有效載荷),語法則描述瞭如何將語義映射到在網絡上傳輸的字節。

HTTP/0.9、1.0 和 1.1 共享了很多語義,還以字符串形式共享了一些語法。SPDY 採用了 HTTP/1.1 語義,並將語法從字符串改為二進制形式。

谷歌的 SPDY 實驗表明,他們想要改變 HTTP 語法,但會保留現有的 HTTP 語義。例如,保留https:// 格式的 URL 可以避免很多可能會影響到採用率的問題。

在看到了一些積極的結果後,IETF 認為是時候看看 HTTP/2.0 的效果了。於 2012 年 3 月舉行的 IETF 83 大會的一份幻燈片展示了 HTTP/2.0 的需求、目標和成功的衡量標準。它還明確指出“HTTP/2.0 只在傳輸格式方面與 HTTP/1.x 不兼容”。

在那次會議期間,社區成員被邀請分享他們的提案。提交審議的 I-D 包括 draft-mbelshe-httpbis-spdy-00、draft-montenegro-httpbis-speed-mobility-00 和 draft-tarreau-httpbis-network-friendly-00。最終,SPDY 草案獲得通過,並於 2012 年 11 月啟動 draft-ietf-httpbis-http2-00 相關工作。在短短兩年多的時間內完成了 18 次草案,並於 2015 年發佈了 RFC 7540(HTTP/2)。在這期間,HTTP/2 的語法分散到足以使 HTTP/2 和 SPDY 不兼容。

這些年,IETF 一直忙於與 HTTP 相關的工作,HTTP/1.1 重構和 HTTP/2 標準化同時進行。這與 21 世紀初多年的平靜形成鮮明對比。

儘管 HTTP/2 正處於標準化階段,但使用 SPDY 和試驗 SPDY 仍然是有好處的。Cloudflare 從 2012 年 8 月起開始支持 SPDY,但在 2018 年 2 月就棄用了。當時的統計數據顯示,不到 4%的 Web 客戶想要使用 SPDY。2015 年 12 月,我們又推出了 HTTP/2 支持,也就是在 RFC 發佈後不久,我們的數據分析表明,有相當一部分 Web 客戶端可以使用它。

支持 SPDY 和 HTTP/2 協議的 Web 客戶端傾向於使用 TLS。2014 年 9 月推出的通用 SSL 可以確保所有註冊到 Cloudflare 的網站都能夠在我們引入這些新協議時使用它們。

gQUIC

谷歌在 2012 年至 2015 年期間繼續進行實驗,併發布了 SPDY v3 和 v3.1。他們也開始研究 gQUIC(當時發音為 quick),並於 2012 年初推出初始版本的規範。

gQUIC 的早期版本使用了 SPDY v3 形式的 HTTP 語法,因為當時 HTTP/2 規範還沒有完成。SPDY 二進制語法被打包成可以在 UDP 數據報中發送的 Q​​UIC 數據包,與 HTTP 使用的 TCP 傳輸有所不同。

SPDY over gQUIC 協議層

gQUIC 使用了一些巧妙的技巧來提升性能,其中之一就是打破應用程序和傳輸之間的分層界限。這意味著 gQUIC 只支持 HTTP。因此,當時被稱為“QUIC”的 gQUIC 被當作 HTTP 的下一個候選版本。儘管 QUIC 在過去幾年中不斷髮生變化,直到今天,人們還是將 QUIC 理解為最初的 HTTP 變體。

有關 gQUIC 的實驗繼續進行,並最終切換到更接近 HTTP/2 的語法,以至於大多數人直接將其稱為“HTTP/2 over QUIC”。但是,由於技術方面的限制,它們之間存在一些非常微妙的差異,比如 HTTP 標頭的序列化和交互方式。雖然這是一個很小的差異,但卻意味著 HTTP/2 over gQUIC 與 IETF 的 HTTP/2 是不兼容的。

最後,我們始終需要考慮互聯網協議的安全性問題。gQUIC 沒有使用 TLS,相反,谷歌開發了一種叫作 QUIC Crypto 的方法,可以加快安全握手過程。已經與服務器建立了安全會話的客戶端可以重用會話信息來執行“零往返時間”或 0-RTT 握手(0-RTT 後來被 TLS 1.3 採用)。

那麼 HTTP/3 到底是什麼?

到目前為止,我們應該已經熟悉了標準化過程,也知道了 gQUIC 是什麼。2015 年 6 月,谷歌提交了題為“QUIC: A UDP-based Secure and Reliable Transport for HTTP/2”的 draft-tsvwg-quic-protocol-00。它的語法幾乎與 HTTP/2 相同。

簡單地說,與 IETF 合作的結果就是,QUIC 在傳輸層似乎提供了很多優勢,應該與 HTTP 解耦,因此有必要重新引入分層。此外,有人傾向於返回到基於 TLS 的握手機制(由於在這個時候有關 TLS 1.3 的工作正在進行中,同時也正在整合 0-RTT,所以並沒有那麼糟糕)。

大約一年後,也就是在 2016 年,提交了一系列新的 I-D:

draft-hamilton-quic-transport-protocol-00draft-thomson-quic-tls-00draft-iyengar-quic-loss-recovery-00draft-shade-quic-http2-mapping-00

這是另一個 HTTP 和 QUIC 令人感到混淆的地方。draft-shade-quic-http2-mapping-00 的標題是“HTTP/2 Semantics Using The QUIC Transport Protocol”,並將自己描述為“基於 QUIC 的 HTTP/2 語義映射”。但其實這種說法不是很恰當。HTTP/2 在保持語義的同時也在改變語法。此外,“HTTP/2 over gQUIC”已經不能用來準確地描述語法了,至於原因,之前已經提到過了。

IETF 版本的 QUIC 是一個全新的傳輸協議。這是一個巨大的承諾,在做出這個承諾之前,IETF 希望先看看成員的實際興趣。為此,2016 年在柏林舉行的 IETF 96 大會上召開了正式的“Birds of a Feather”會議。我很幸運能夠親自參加這次會議,還有其他數百人也參加了會議。在會議結束時達成了共識,QUIC 將被 IETF 採用並標準化。

用於將 HTTP 映射到 QUIC 的第一個 IETF QUIC I-D(draft-ietf-quic-http-00)採用了 Ronseal 方法,並將其名稱簡化為“HTTP over QUIC”。不幸的是,這項工作並沒有完全完成,而且在正文中出現了很多次“HTTP/2”。I-D 新編輯 Mike Bishop 發現了這一點,並開始修復 HTTP/2 的命名錯誤。在 01 草案中,描述被改為“基於 QUIC 的 HTTP 語義映射”。

隨著時間的推移和版本的增加,“HTTP/2”一詞的使用在逐漸減少。往後推兩年,也就是在 2018 年 10 月,I-D 到了第 16 版。雖然 HTTP over QUIC 與 HTTP/2 很相似,但它終究是一個獨立的、不向後兼容的 HTTP 語法。對於那些沒有密切關注 IETF 開發的人(佔了大多數)來說,文檔名稱並沒有體現出這種差異。標準化的要點之一是促進交流和互操作性,然而,像命名這樣簡單的事情是造成社區混亂的主要原因。

回想一下 2012 年所說的“HTTP/2.0 只在傳輸格式方面與 HTTP/1.x 不兼容”。IETF 遵循了現有的線索。在 IETF 103 召開之前和召開期間,經過深思熟慮,各方一致同意將“HTTP over QUIC”重命名為 HTTP/3。

但 RFC 7230 和 7231 不同意你對語義和語法的定義!

有時候,文檔的標題也會令人感到混淆。描述語法和語義的 HTTP 文檔是:

RFC 7230——超文本傳輸​​協議(HTTP/1.1):消息語法和路由RFC 7231——超文本傳輸​​協議(HTTP/1.1):語義和內容

我們可能會對這些名稱進行過多的解讀,認為基本的 HTTP 語義是特定於 HTTP 版本的,即 HTTP/1.1。好在 HTTPbis 工作組正在努力解決這個問題。一些成員正在進行另一輪文件修訂工作。這項工作現在正在進行當中,被稱為 HTTP 核心活動。它將把六份草案壓縮成三份:

HTTP 語義(draft-ietf-httpbis-semantics)HTTP 緩存(draft-ietf-httpbis-caching)HTTP/1.1 消息語法和路由(draft-ietf-httpbis-messaging)

基於這種新的結構,HTTP/2 和 HTTP/3 成為了通用 HTTP 語義的語法定義。這並不意味著它們除了語法之外就沒有自己的特性,但這應該有助於今後的討論。

總結

這篇文章簡要介紹了 HTTP 在過去三十年的標準化過程。我試著在不涉及很多技術細節的情況下解釋我們是如何發展到達今天的 HTTP/3 的。如果你想要跳過中間的部分,希望用一句話來概括,那麼應該是這樣:HTTP/3 只是一種基於 IETF QUIC(一種基於 UDP 的多路複用和安全傳輸)的新 HTTP 語法。

在這篇文章中,我們介紹了 HTTP 和 TLS 發展過程的重要篇章。我們將全部內容整合到下面的這張 Secure Web Timeline 中。對於喜歡一探究竟的人,請務必查看完整版本,其中包含了草案編號。

英文原文:https://blog.cloudflare.com/http-3-from-root-to-tip/

譯文地址:https://www.infoq.cn/article/IgME_4ebP3d46m3tHbaT