如何開發一個開源閘道器?

spacewander發表於2022-12-14

編寫本文並非打算總結開發開源閘道器的最佳實踐,僅僅是談談自己的一些觀點。

基石

如果有人問我,開發開源閘道器最重要的是什麼,我會毫不猶豫地提到兩點:

  1. 要有一套一致的設計語言。
  2. 要有持續的人力投入

設計語言

由於現在開源專案內卷化,要想推出一個新的開源閘道器,已經必須要有整套的控制面(CP) + Dashboard + 資料面(DP)。只是開源其中幾個元件而非整體產品,就意味著給競對留下空間來佔領你的市場。你可以開源出一個入門版的實現,但是至少不能沒有。

既然我們要開源出一個整體產品,就需要有一個可以打通各個層次的設計語言。比如 APISIX 用 jsonschema,kong 有自己的 schema,envoy 有 grpc。一個設計語言需要滿足兩個目標:

  1. 能編寫配置,可以在多種平臺下面使用,支援在配置中增加標記。
  2. 支援豐富的檢驗規則,如必需的欄位、有效值的範圍、根據某個欄位來決定對其他欄位的檢驗規則等等。

有了這個設計語言之後,我們可以避免在不同的元件間重複程式碼,並提供一致的體驗。比如 Dashboard 的表單欄位和資料面的配置項,都可以由該設計語言編寫的配置中生成。這時候,使用者就可以根據表單欄位名稱找到資料面上具體的配置,方便學習和除錯。

人力投入

雖然閘道器的門檻不高,但是競爭激烈,而且投入週期長。所以需要有足夠多的人力,持續地在這上面工作。

開源閘道器是一個紅海。在我腦海裡,能立刻報上名字的開源閘道器個數,在十個以上。其中大部分背後都有一個團隊在運作。甚至還有幾家閘道器卷不過別人,抱團合作的情況。(沒錯,我說的就是 Envoy gateway)

開源閘道器的開發是一個馬拉松。APISIX 在 2019 年 6 月開源,在 2020 年內也主要是在 OpenResty 圈子裡面流行。直到 2021 年,APISIX 才算是國內 API 閘道器界的一個標杆。到了 2021 年冬,APISIX 終於能夠有個爆發性的增長。此時距離開源已經過去了兩年多。總結就是,第一年讓大家知道你;第二年陸續有人使用你;到第三年才會有使用量的飛躍。開源閘道器的開發沒有速勝論。

有人會問,既然做的是開源閘道器,我們可以依靠眾多的貢獻者來降低人力成本嗎?以 APISIX 為例,作為一個專注於發展社群、吸納更多貢獻者的專案,APISIX 有著 350 多位貢獻者。所有非 API7 員工加起來的程式碼量,佔當前 APISIX 的 40%。換句話說,有 60% 是由 API7 的員工實現的。我統計過許多開源專案的貢獻者分佈,大部分專案都是由核心開發者貢獻了半數以上的程式碼。這意味著,實際上我們還是需要有持之以恆地投入核心開發者來推動閘道器的開發工作。

定位

既然開源閘道器競爭激烈,那麼我們就需要有一個清晰的定位,先佔住一塊利基市場,才能活下來。一個良好的定位,對內可以說服金主持續的投入,對外可以說服使用者堅定地選擇。一個閘道器,可以主打豐富的功能、可以主打低部署成本、可以主打強勁的效能,但是不能是一個樣樣皆通、樣樣稀鬆的平庸的閘道器。力要往一處使,需要在開始時找到自己發力的方向,饒有毅力地往上鑽,才能打出自己的一片天。

不過,無論閘道器的定位如何,都需要解決兩個問題:

  1. 讓使用者用起來
  2. 讓使用者用下去

讓使用者用起來

拋開一些非技術的手段不談,要想讓使用者上手你的閘道器,首先要有清晰容易的部署方式,其次要有簡明扼要的文件引導。最好一條命令就能讓整個閘道器跑起來,並在讀完 10 分鐘以內的文件後完成 Hello World 示例的配置。

讓使用者用下去

在把人吸引過來之後,我們就要考慮留住人了。通常來講,使用者對閘道器的應用是比較小心謹慎的,往往需要經歷很長時間才能做到充分地信任。所以我們需要保證這個閘道器是非常穩定的,不會給他們帶來意外的“驚喜”。

這個穩定分兩類。一個是功能上的穩定,使用者使用了不會擔心出線上事故。從閘道器的開發上講,我們需要有一套周全的自動化測試流程來保障這一點。另一個是配置上的穩定,使用者不用擔心升級了某個版本之後,配置就出問題了。在這一點上,我們可以借鑑 Envoy 和 k8s 的做法,透過把配置欄位給版本化,在提供了清晰的配置升級路徑的同時,也保證了舊有配置的穩定性。

迭代

由於本文的主題是關於開源閘道器的,那麼這裡的迭代,主要指如何把開源貢獻者的力量引入到閘道器的迭代中來。

如前所述,閘道器的主要開發,還是要由核心開發者完成。核心開發者需要把骨架搭起來,把流程跑通,開源貢獻者才能去往裡面填充新的功能。

所謂的“搭建骨架”,有三個含義:

  1. 需要把文件、測試、CI 給打通,貢獻者只需要照著現有的程式碼加上自己的就行,不需要琢磨如何增加新的機制。
  2. 需要把擴充點給放置好,貢獻者只需要圍繞這個擴充點程式設計,比如新增一個外掛或配置 provider,只需參考現有的就行。
  3. 做新功能時,只實現一個 MVP 的功能。比如呼叫鑑權服務時,第一版的實現只會傳送客戶端請求的頭。如果使用者想要一個增加額外自定義頭的功能,可以邀請他一起來開發。當然這麼做也要控制好度,避免被人吐槽只是做了個門面。

有道是,“海納百川,有容乃大”。當維護者的,心裡總是希望能合併更多人貢獻的程式碼。但有時他們卻不會這麼做。通常這會是出於兩個理由:

  1. 對貢獻者缺乏信任
  2. 怕增加維護成本

要想降低合併新功能所需的信任和維護成本,我們可以建立一個 contri 目錄,專門放置更外圍的程式碼。預設情況下,不會啟用(甚至打包) contri 下面的程式碼。同時我們會在文件中宣告,contri 下面的程式碼的安全性不由該專案維護者負責。我們還可以弄一份文件,記錄 contri 裡面每個外掛的實際 owner 是誰。總而言之,我們需要強調 contri 裡面的程式碼是有另外的 owner 的,一旦有問題,可以撇清責任。這麼一來,對信任和維護成本的要求就可以降低了。

文件

最後,但不是最不重要的,開源閘道器要有良好的文件。為什麼我會把文件的事情獨立來說呢?因為無論你選擇哪種技術棧來開發閘道器,都需要思考同樣的文件問題。

開源閘道器的文件,通常可以分為以下各部分:

  1. Concept。包括入門指南、閘道器的架構、本文件中涉及的術語等,是給初學者看的。
  2. Cookbook。包括面向各種場景下閘道器的配置方式,是給已經入門的使用者看的。
  3. Reference。包括閘道器的各種配置欄位說明,是給使用者查詢的。
  4. Ops Guide。包括如何做高可用、如何升級、如何除錯,是給運維看的。
  5. Dev Guide。包含如何擴充該閘道器,如何貢獻程式碼。是給開發者看的。

核心開發者需要把文件的架構給搭起來,方便貢獻者來完善它。

由於本文是用中文寫的,讀者都是中文使用者,所以自然而然地會有一個問題 —— 我們是否要提供中文文件?

從我個人實踐角度看,提供中文文件,與其說是降低門檻,不如說是傳達一種我們重視本地化的態度。如果人力允許,還是要做的,但是我們需要有一個自動化的方式來做。畢竟現在 AI 這麼發達,如果不用上它實在算不上一個程式設計師。Databend 曾經分享過自己的自動化流程:https://xuanwo.io/reports/202... (雖然我看它的文件裡面有翻譯的內容仍然只是小部分)。

相關文章