偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

從 Kubernetes 學(xué)習(xí)大規(guī)模 Go 項(xiàng)目架構(gòu)

開發(fā) 后端 云原生
如何在演進(jìn)過程中持續(xù)優(yōu)化模塊設(shè)計(jì)和代碼結(jié)構(gòu)、提升迭代速度,是我們需要深入思考和探索的問題。

在嘗試使用 Go 構(gòu)建一個(gè)具有高可擴(kuò)展性、高可靠性和高可維護(hù)性的大型項(xiàng)目之前,先來看一下 Kubernetes 的項(xiàng)目結(jié)構(gòu),了解它是如何組織一系列用于容器編排的功能模塊的。

1. Kubernetes 代碼布局

下面是 Kubernetes 主目錄下的各個(gè)頂層目錄及其主要功能,隨后我們會(huì)逐一說明它們的用途。

  • api:存放接口協(xié)議;
  • build:與構(gòu)建相關(guān)的腳本和代碼;
  • cmd:各個(gè)可執(zhí)行程序的入口;
  • pkg:各組件的核心實(shí)現(xiàn)和導(dǎo)出包;
  • staging:臨時(shí)存放組件間相互依賴的代碼。

(1) api

該目錄存放 OpenAPI 和 Swagger 文件,包括 JSON 與 Protocol Buffer 的定義。

(2) build

該目錄包含構(gòu)建 Kubernetes 項(xiàng)目所需的腳本,包括各組件的編譯和鏡像(例如 pause 鏡像)的構(gòu)建。

(3) cmd

cmd 目錄存放用于生成可執(zhí)行文件的 main 包源代碼。若需構(gòu)建多個(gè)可執(zhí)行程序,可將它們分別放在各自的子目錄下。以 Kubernetes 為例,cmd 目錄下有:

  • kube-proxy:負(fù)責(zé)網(wǎng)絡(luò)相關(guān)規(guī)則的實(shí)現(xiàn) ;
  • kube-apiserver:暴露 Kubernetes API 并處理請(qǐng)求,為 Pod、ReplicaSet、Service 等資源提供增刪改查(CRUD)操作;
  • kube-controller-manager:kubernetes 資源控制器;
  • kube-scheduler:監(jiān)控新建的 Pod,并為其選擇運(yùn)行節(jié)點(diǎn);
  • kubectl:訪問集群的命令行工具;

由此可見,像 kube-proxy、kube-apiserver 這樣的核心組件,都在這里有對(duì)應(yīng)的可執(zhí)行入口。

(4) pkg

pkg 目錄既包含項(xiàng)目自身的依賴,也包含對(duì)外導(dǎo)出的包。主要實(shí)現(xiàn)了各個(gè)核心組件的業(yè)務(wù)邏輯。

(5) staging

staging 目錄下的包通過符號(hào)鏈接映射到 k8s.io 下。首先,由于 Kubernetes 項(xiàng)目體量龐大,這樣做可以避免因倉庫分散帶來的開發(fā)障礙,使所有代碼能夠在一次 PR 中提交和審查。通過這種方式,既保證了模塊化,又保持了主倉庫的完整性。

同時(shí),借助 go mod 中的replace指令,無需為每個(gè)依賴單獨(dú)打 tag,簡(jiǎn)化了版本管理和發(fā)布流程。

如果不這么做,而是采用將 staging 目錄下的所有代碼拆分到獨(dú)立倉庫的方式,那么每次子倉庫代碼變化時(shí),都需要先在子倉庫提交 PR、發(fā)布新 tag,然后在主倉庫中更新 go mod 依賴,才能繼續(xù)開發(fā)。這無疑會(huì)大幅增加整體開發(fā)成本。

因此,通過符號(hào)鏈接將 staging 目錄下的包關(guān)聯(lián)到主倉庫,能夠有效簡(jiǎn)化版本管理和發(fā)布流程。

2. 與標(biāo)準(zhǔn) Go 項(xiàng)目結(jié)構(gòu)的對(duì)比

在 Go 中,internal目錄用于存放不對(duì)外導(dǎo)出的包。它的原則是在項(xiàng)目?jī)?nèi)部可以正常使用,但外部項(xiàng)目無法訪問。

然而,Kubernetes 并沒有internal 目錄。這是因?yàn)?Kubernetes 項(xiàng)目最早啟動(dòng)于 2014 年左右,而 Go 1.4(于 2014 年底發(fā)布)才引入了 internal 目錄的概念。在 Kubernetes 早期開發(fā)階段,使用 internal 目錄的慣例尚未普及,且后來也未進(jìn)行大規(guī)模重構(gòu)來添加它。

此同時(shí),Kubernetes 的設(shè)計(jì)目標(biāo)之一就是模塊化與解耦。它通過明確的包組織和代碼結(jié)構(gòu)來實(shí)現(xiàn)封裝,而無需依賴internal=目錄來限制包的訪問權(quán)限。

至此,我們已經(jīng)了解了構(gòu)建項(xiàng)目的標(biāo)準(zhǔn)頂層目錄結(jié)構(gòu)。

Go 并不像 Java 那樣有一套統(tǒng)一的目錄框架。因此,不同項(xiàng)目往往各自為政。即使在同一個(gè)團(tuán)隊(duì)中,也可能存在多種結(jié)構(gòu),這對(duì)新人理解項(xiàng)目是一大障礙。

正因?yàn)槿绱耍瑓f(xié)作往往會(huì)變得困難。統(tǒng)一的頂層目錄結(jié)構(gòu)能讓我們快速定位代碼,并在接手項(xiàng)目時(shí)擁有標(biāo)準(zhǔn)的切入點(diǎn),從而提高開發(fā)效率,減少協(xié)作中的定位混亂。

但僅僅有統(tǒng)一的目錄結(jié)構(gòu),就能構(gòu)建完美的大型項(xiàng)目嗎?答案顯然是否定的。

單靠統(tǒng)一目錄結(jié)構(gòu),無法從根本上解決代碼隨著項(xiàng)目規(guī)模擴(kuò)大而逐漸“衰變”“混亂”的問題。唯有遵循良好的設(shè)計(jì)原則,才能在項(xiàng)目不斷擴(kuò)張時(shí)始終保持清晰的設(shè)計(jì)脈絡(luò)。

3. 聲明式設(shè)計(jì)理念

聲明式 API 貫穿 Kubernetes 的整個(gè)代碼設(shè)計(jì),防止系統(tǒng)陷入過程式編程。

例如,當(dāng)需要改變某個(gè)資源的狀態(tài)時(shí),我們應(yīng)告訴 K8s “期望的狀態(tài)”,而不是告訴它 “要執(zhí)行哪些步驟”。這也是為何 kubelet 的滾動(dòng)更新最終被廢棄:它的設(shè)計(jì)對(duì)更新 Pod 的整個(gè)過程進(jìn)行了過度微觀管理。

通過告知 Kubernetes 目標(biāo)狀態(tài),kubelet 可以根據(jù)該狀態(tài)自主采取相應(yīng)措施,而無需外部過度干預(yù)。

此時(shí)你可能會(huì)疑問:聲明式 API 在項(xiàng)目擴(kuò)展時(shí)如何有助于保持模塊清晰?這不正是用戶在使用Kubernetes 時(shí)的感受嗎?它與內(nèi)部設(shè)計(jì)有什么關(guān)系?

如果我們?cè)谠O(shè)計(jì)接口時(shí),將整個(gè)操作流程完全暴露給用戶,讓他們逐步干預(yù) Pod 更新的每個(gè)步驟,那么我們?cè)O(shè)計(jì)的模塊就不可避免地演變?yōu)檫^程式。這會(huì)導(dǎo)致代碼模塊與大量用戶操作高度耦合,難以保持清晰。

而采用聲明式 API 后,我們僅向 K8s 傳達(dá)期望狀態(tài),集群內(nèi)部的多個(gè)組件便能協(xié)同工作,最終實(shí)現(xiàn)該狀態(tài)。用戶無需關(guān)心內(nèi)部的更新細(xì)節(jié)。更重要的是,當(dāng)需要增加新的協(xié)作插件時(shí),只需新增相應(yīng)模塊,無需再對(duì)外暴露更多用戶操作的 API。

以 cAdvisor 為例,它獨(dú)立監(jiān)控 Kubernetes 部署的資源并收集容器指標(biāo),不依賴外部組件。控制器再將這些指標(biāo)與用戶聲明的目標(biāo)進(jìn)行對(duì)比,以判斷是否滿足擴(kuò)容或縮容條件。

由于各模塊相互獨(dú)立,cAdvisor 只需專注于采集并返回監(jiān)控?cái)?shù)據(jù),而無需關(guān)心這些數(shù)據(jù)是用于觀測(cè)還是自動(dòng)伸縮。

這也是設(shè)計(jì)不同任務(wù)組件時(shí)的關(guān)鍵原則:

  • 明確要達(dá)成的需求;
  • 傳遞信息時(shí)只關(guān)注輸入與輸出;
  • 內(nèi)部實(shí)現(xiàn)則封裝起來,不向外暴露,讓外部業(yè)務(wù)調(diào)用保持盡可能簡(jiǎn)單。

4. 避免過度設(shè)計(jì)

過度的工程設(shè)計(jì)往往比設(shè)計(jì)不足更糟糕。

Kubernetes 的最早版本是 0.4。在網(wǎng)絡(luò)方面,官方的實(shí)現(xiàn)方案是讓 GCE 運(yùn)行 Salt 腳本來創(chuàng)建網(wǎng)橋,而在其他環(huán)境下推薦使用 Flannel 和 OVS。

隨著 Kubernetes 的發(fā)展,F(xiàn)lannel 在某些場(chǎng)景下已不足以滿足需求。大約在 2015 年,社區(qū)中出現(xiàn)了 Calico 和 Weave,基本解決了網(wǎng)絡(luò)問題。于是 Kubernetes 就不用再花力氣自己去做網(wǎng)絡(luò)實(shí)現(xiàn),而是引入了 CNI 以標(biāo)準(zhǔn)化網(wǎng)絡(luò)插件。

很顯然,Kubernetes 并不是一開始就設(shè)計(jì)得十分完美,而是在新問題出現(xiàn)時(shí),才逐步引入新的設(shè)計(jì)來適應(yīng)不同環(huán)境的變化。

在項(xiàng)目啟動(dòng)初期,依賴關(guān)系相對(duì)清晰,所以工程設(shè)計(jì)階段一般不會(huì)出現(xiàn)循環(huán)依賴。但隨著項(xiàng)目規(guī)模增長(zhǎng),這些問題會(huì)逐漸顯現(xiàn)。產(chǎn)品功能的不斷演進(jìn),會(huì)導(dǎo)致代碼設(shè)計(jì)中出現(xiàn)互相引用。

即便我們?cè)陧?xiàng)目啟動(dòng)前盡力去了解所有業(yè)務(wù)背景和待解問題,隨著產(chǎn)品功能的變化和程序的迭代,總會(huì)出現(xiàn)新的問題。我們能做的,是關(guān)注模塊設(shè)計(jì)和依賴管理,盡可能保持功能內(nèi)聚,并在后續(xù)添加抽象時(shí),避免對(duì)已有代碼進(jìn)行大規(guī)?!爸貥?gòu)”式的改動(dòng)。

為“可擴(kuò)展性”過度設(shè)計(jì)系統(tǒng)、只為設(shè)計(jì)而設(shè)計(jì),反而會(huì)成為未來變更的絆腳石。

下面用一個(gè)電商業(yè)務(wù)場(chǎng)景來說明設(shè)計(jì)演進(jìn)。

初始階段,系統(tǒng)包含兩個(gè)模塊:

  • 訂單模塊: 負(fù)責(zé)創(chuàng)建訂單、支付、狀態(tài)更新等,依賴用戶模塊獲取用戶信息(如收貨地址、聯(lián)系方式等)。
  • 用戶模塊: 負(fù)責(zé)管理用戶信息、注冊(cè)、登錄,存儲(chǔ)用戶數(shù)據(jù),不依賴訂單模塊。

在這個(gè)階段,依賴關(guān)系是單向的:訂單模塊 → 用戶模塊。此時(shí)無需過度抽象,過早的設(shè)計(jì)投入并不劃算;許多項(xiàng)目并不知道是否能夠成功,從產(chǎn)品發(fā)布角度看,投入過多設(shè)計(jì)成本并不可行,而且若產(chǎn)品定位發(fā)生劇烈變化,過度設(shè)計(jì)會(huì)成為后續(xù)修改的障礙。

隨著需求演變,出現(xiàn)了個(gè)性化推薦的需求:平臺(tái)需要根據(jù)用戶的購買歷史(訂單記錄)向用戶推薦商品。

為實(shí)現(xiàn)個(gè)性化推薦,用戶模塊需要調(diào)用訂單模塊的 API 來獲取用戶的歷史訂單。此時(shí)依賴關(guān)系變?yōu)椋?/p>

訂單模塊 依賴 用戶模塊(獲取用戶信息)

用戶模塊 依賴 訂單模塊(獲取訂單歷史)

這就形成了循環(huán)依賴。為了解決它,可以考慮責(zé)任拆分:引入一個(gè)新的“推薦模塊”,專門處理個(gè)性化推薦邏輯。推薦模塊分別從用戶模塊和訂單模塊獲取數(shù)據(jù),避免它們之間直接依賴。通過提取模塊,我們解決了用戶與訂單模塊之間的耦合。

然而,新需求又來了:在促銷活動(dòng)期間,用戶購買特定活動(dòng)商品時(shí),產(chǎn)品經(jīng)理希望推薦模塊能實(shí)時(shí)感知此類訂單,并推薦相關(guān)的促銷商品(例如用戶買了打折運(yùn)動(dòng)手表,就推薦打折藍(lán)牙運(yùn)動(dòng)耳機(jī),以提高復(fù)購率)。

在這個(gè)場(chǎng)景中,讓訂單模塊直接調(diào)用推薦模塊來傳遞數(shù)據(jù)顯然不合適:推薦模塊已經(jīng)依賴訂單模塊獲取用戶購買數(shù)據(jù),如果再讓訂單模塊調(diào)用推薦模塊,就又會(huì)產(chǎn)生循環(huán)依賴。

那么,推薦模塊該如何快速感知訂單變化?這就需要事件驅(qū)動(dòng)架構(gòu)。

  • 當(dāng)用戶下單時(shí),訂單模塊觸發(fā)一個(gè)事件;
  • 推薦模塊訂閱與用戶訂單相關(guān)的事件;
  • 通過事件傳遞數(shù)據(jù)后,推薦模塊立即觸發(fā)模型重訓(xùn)練,并向用戶推薦相關(guān)商品。

從上述例子可見,企業(yè)級(jí)應(yīng)用的一大挑戰(zhàn)是:業(yè)務(wù)域建模。在建模過程中,需要隨著需求的持續(xù)演進(jìn),不斷優(yōu)化設(shè)計(jì)。

上面提到的用戶、訂單與推薦模塊,也是大多數(shù) To-C(面向消費(fèi)者)產(chǎn)品演進(jìn)中的常見場(chǎng)景。如何在演進(jìn)過程中持續(xù)優(yōu)化模塊設(shè)計(jì)和代碼結(jié)構(gòu)、提升迭代速度,是我們需要深入思考和探索的問題。

5. 總結(jié)

讓我們回顧下本文內(nèi)容:

  • 在構(gòu)建大型項(xiàng)目時(shí),統(tǒng)一的目錄結(jié)構(gòu)可以提高協(xié)作效率,但良好的設(shè)計(jì)原則才是在項(xiàng)目不斷增長(zhǎng)時(shí)保持清晰性和可擴(kuò)展性的關(guān)鍵;
  • Kubernetes 的聲明式 API 能讓模塊保持獨(dú)立,避免過程式編程的陷阱;
  • 項(xiàng)目設(shè)計(jì)應(yīng)根據(jù)實(shí)際需求逐步演進(jìn),避免過度設(shè)計(jì);
  • 著重模塊職責(zé)和依賴的合理拆分,并使用事件驅(qū)動(dòng)的方法解決模塊間的耦合。
責(zé)任編輯:趙寧寧 來源: 令飛編程
相關(guān)推薦

2025-06-27 10:12:15

Go封裝開發(fā)

2020-10-15 19:22:09

Menger機(jī)器學(xué)習(xí)強(qiáng)化學(xué)習(xí)

2023-03-19 23:31:32

OpenKruise項(xiàng)目自動(dòng)化

2021-03-26 09:49:22

架構(gòu)并行處理

2019-04-02 08:00:39

閃存架構(gòu)共享

2009-03-20 09:49:00

負(fù)載均衡CDN網(wǎng)站架構(gòu)

2017-06-03 16:34:22

云服務(wù)數(shù)據(jù)中心公有云

2022-06-09 13:45:18

vivoK8S集群Kubernetes

2023-11-24 13:24:14

CIOOptus

2015-06-12 09:58:51

2022-07-07 11:00:09

美團(tuán)模型實(shí)踐

2017-10-09 16:51:34

機(jī)器學(xué)習(xí)No Free Lun

2016-01-29 20:23:23

華為

2017-04-26 13:30:24

爬蟲數(shù)據(jù)采集數(shù)據(jù)存儲(chǔ)

2009-04-09 09:32:00

VoWLANWLAN

2010-09-01 15:16:49

WLAN交換機(jī)結(jié)構(gòu)

2020-02-17 08:00:02

云計(jì)算云開發(fā)Kubernetes

2024-04-30 07:00:00

公共云云策略云計(jì)算

2011-12-16 09:54:17

網(wǎng)絡(luò)架構(gòu)網(wǎng)絡(luò)架構(gòu)系統(tǒng)架構(gòu)系統(tǒng)

2023-04-06 16:29:18

模型AI
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)