爲什麼需要可編程代理

經常會有人問 “當你們說可編程代理的時候,那麼什麼是可編程代理,爲什麼需要可編程代理”?本文從不同角度回答這個問題。首先會簡單的介紹代理;然後討論下代理在發展過程中的階段劃分;基於這些階段的劃分,討論每一個階段相比於上一個階段的改進之處,以及爲什麼需要這些改進,同時我們討論下 “可編程” 所包含的幾個層面;最後我們總結下 “爲什麼需要可編程代理”。

什麼是代理及代理的功能

代理是代理服務器的簡稱,代理服務器通常部署在兩個互相隔離的網絡的中間處,既能訪問一側網絡也能訪問另一側網絡,通過把一側的數據搬運到另一側,實現了網絡的連通。代理是一種串路網絡設備,自從計算機網絡誕生,代理就存在了。由於代理是串路的,因此代理在實現網絡連通功能的同時也衍生出新的功能和使用場景:

提供橋接兩個網絡功能的除了代理還有路由器。路由器工作在網絡的 3 層;而代理工作在 3 層以上,或者說 4 層和 7 層。

軟件代理的發展

軟件代理服務器在發展過程中,大致上經歷瞭如下幾個階段:

  1. 配置文件時代。代理類軟件(最主要是開源軟件),佔到了網絡基礎設施類軟件的大多數,這些軟件在細分領域提供了不同的功能,比如針對不同協議的代理、比如側重負載均衡的代理、比如側重緩存加速的代理。這一代類軟件,都是基於配置的。用戶在配置文件中設置參數、配置規則,然後啓動服務進程執行這些規則

  2. 配置語言時代。配置難於表達複雜邏輯,所以很多代理軟件在配置基礎上引入了很薄的腳本能力,我們一般稱爲 “配置語言” 或者說 DSL,比如 Haprxoy 的 ACL,Varnish 的 VCL

  3. 腳本語言時代。當邏輯進一步複雜的時候,配置語言也會難於表達;同時,當配置語言數量多到一定程度時候,配置語言本身的管理,會有很大難度。就像 shell 腳本可以寫簡單的邏輯,但是當 shell 代碼多到一定程度的時候,通常會進一步選擇 Perl 或者 Python 這些更加結構化的腳本語言。Proxy 支持腳本語言,既有腳本語言的便利性,也有編程語言結構化的優勢。這類的例子如 Openresty(Nginx + Lua)、Nginx Plus(Nginx + NJS). 同時,這類例子裏也包括大量應用類編程語言實現的代理服務器,比如基於 NodeJS 的 StrongLoop、Spring Gateway 等,這些應用類編程語言往往自己就有腳本支持能力

  4. 集羣時代。腳本語言解決了代理中複雜邏輯的模塊化、結構化實現難點。此時進一步的需求是把代理和其他的管理控制工具集成,因此需要有 REST 接口。外部的控制平面可以通過 REST 接口動態的設置腳本中的邏輯。同時,人們對代理的使用也從單實例上升到集羣化,因此這一類代理通常都自身支持集羣能力,比如 Enovy 和基於 Openresty 的 Kong,他們通過某種集中或者共享方式實現集羣能力,同時對外提供 REST 接口。對於上邊說的 #4 類型的代理,通過配置管理,一般也可以實現集羣管理;並且配置管理工具也可以對外暴露 REST 接口。比如使用 Ansible + Nginx 的方案,實現了和 #5 類似的能力。相比之下,#4 的方案需要要更多的組件形成方案,而 #5 的方案更收斂

  5. 雲時代。在 #5 的基礎上,代理採用分佈式的方式部署,最常見的場景是爲每個應用進程部署一個代理,也就是 sidecar proxy 模式。在採用分佈式以後,針對不同的上游服務,採用不同的規則和策略,也就是多租戶能力。不同上游服務,不僅在邏輯上有獨立的規則和策略;在物理上也進一步提供了隔離,實現進程級和接口級的細粒度管理。如果我們把服務網格的控制平面和數據平面看作一個整體,那麼服務網格是這個領域的代表,典型的比如 Istio+Envoy,Linkerd+Linkerd Proxy。Pipy 就是這個階段的產物

在如上的各個階段裏,每一個階段都比上一個階段有所改進,概要的說:

代理的需求演化

讓我再從另一個視角看下代理的演化過程 -- 需求的演化。

  1. 第一代的代理主要是實現了代理功能,並且提供了基礎的可配置能力;同時,網絡設備,尤其是串路網絡設備的特性,要求代理是高可靠的;網絡的海量數據實時傳輸的特性,要求代理高吞吐、低延遲、低資源。和所有的軟件一樣,代理也需要支持模塊化和可擴展,這個階段的代理主要採用 C 語言開發,相應的開發擴展模塊也使用 C 語言,模塊在進程啓動是加載。概括起來說,這個階段的代理需求是:連通性(網絡功能)、易用性(可以通過配置文件配置)、可靠性(串路設備的要求)、高性能擴展性

  2. 第二代代理的改進體現在進一步提高了擴展性和靈活性,如一些動態的數據獲取和配套的邏輯判斷。腳本的引入,進一步增強了易用性;對於組合邏輯和動態數據獲取的支持,提供了靈活性,同時改進了擴展性

  3. 第三代代理相比於第二代代理的改進主要是可管理性開發者友好可編程。腳本大量的使用,一方面是因爲使用 C 語言等做擴展開發難度大、維護難度大,一方面是腳本在現場開發的效率要優於編譯型語言。開發者的開發效率和大量腳本維護帶來的難度,要求這一代代理使用更爲結構化的腳本語言,並且需要保持不低於上一代的性能、資源佔用等核心能力。結構化和模塊化的腳本語言的使用,開啓了代理的可編程時代,此時擴展代理服務器的功能就包含了兩個層面和可能性,一個是使用 C 語言等開發_核心模塊_,一個是使用腳本開發_動態邏輯_;或者說**可編程**包含了_核心模塊_ **可編程** 和_動態邏輯_ **可編程**

  4. 第四代代理開始了集羣支持能力,屬於可管理性的改進。對 REST 接口的支持,使得代理作爲網絡基礎設施(network infra),開始融入到了整體的管理中,是 infra as code 的一個落地點。REST 接口能力,提升了代理的被管理能力,也是管理易用性的一部分。_外部接口_也是可編程的一個重要特徵,而 REST 作爲最常用的接口形式也廣泛的出現在代理服務器領域。此時可編程就包含了三個層面:#3 中描述的_核心模塊_可編程,動態邏輯_可編程,以及提供對外接口供調用的_外部接口 可編程。代理服務器集羣的出現,體現了擴展性從_功能擴展_向_資源擴展_的變化。REST 接口的出現,爲進一步的自服務託管服務提供了技術基礎

  5. 第五代代理的演化是雲計算普及和高速發展驅動的。雲的彈性、自服務、租戶、隔離、計量,要求代理服務軟件具備雲化的能力。如果說第四代代理是面向_系統管理員_的,那麼第五代代理就是面向_雲服務_的。在充分保持了之前幾代代理軟件特徵的同時,進一步實現了 Cloud Ready;而隨着雲計算向邊緣側拓展,第五代代理也向着硬件異構、軟件異構、低能耗的方向發展,因此這一代代理開始呈現了雲邊一體的能力。第五代代理在可編程方面進一步演化,從_核心模塊_、_動態邏輯_、_外部接口_,增加了_雲化_的能力;包括支持分佈式、多租戶、可計量等。可計量是多租戶的衍生需求,多租戶一方面要求隔離,另一方面要求資源可以被儘可能小的粒度進行計量

我們把如上的討論彙總成一個表格,第一列標識代理所滿足的某方面需求;第一行表示不同階段的代理;在每個單元格里,我們用_來表示是否有該類能力,以及能力的程度(1-5 個_,5 個_表示充分支持,1 個_表示基本支持)。同時,我們還列出了各個階段的標誌性軟件:

總結

上表中的 #11~#17 是代理 可編程 的具體的多個方面,這些方面也同時構成了 Why Programming Proxy 的答案:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/4z_QxmnnE3XlkeoDEGjJfw