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

微服務(wù)公用代碼組織實(shí)踐

新聞 架構(gòu)
我們知道,微服務(wù)架構(gòu)由多個(gè)相對(duì)簡(jiǎn)單的服務(wù)組成,依賴服務(wù)之間的隔離性降低系統(tǒng)復(fù)雜度。理論上拆解完備的微服務(wù),不應(yīng)當(dāng)存在過(guò)多業(yè)務(wù)代碼復(fù)用的機(jī)會(huì),因?yàn)榉?wù)之間的有效的隔離會(huì)使得各自代碼只關(guān)注自身的上下文,微服務(wù)的邊界清晰不但包含職責(zé)清晰,從代碼層面也應(yīng)當(dāng)清晰隔離。

 [[320323]]

我們知道,微服務(wù)架構(gòu)由多個(gè)相對(duì)簡(jiǎn)單的服務(wù)組成,依賴服務(wù)之間的隔離性降低系統(tǒng)復(fù)雜度。理論上拆解完備的微服務(wù),不應(yīng)當(dāng)存在過(guò)多業(yè)務(wù)代碼復(fù)用的機(jī)會(huì),因?yàn)榉?wù)之間的有效的隔離會(huì)使得各自代碼只關(guān)注自身的上下文,微服務(wù)的邊界清晰不但包含職責(zé)清晰,從代碼層面也應(yīng)當(dāng)清晰隔離。

但微服務(wù)群組產(chǎn)出的兩類(lèi)代碼,我們?nèi)匀唤ㄗh被公用:

第一類(lèi)是交互協(xié)議代碼,微服務(wù)之間交互協(xié)議標(biāo)準(zhǔn)的代碼,由于每個(gè)獨(dú)立微服務(wù)單一職責(zé)都有自身邊界,微服務(wù)之間交互就被暴露為新的特征。交互協(xié)議標(biāo)準(zhǔn)代碼公用,也可以看做以微服務(wù)容易理解的方式公布出來(lái),有利于維護(hù)微服務(wù)之間交互的便利性和精確性。

第二類(lèi)是純工具類(lèi)代碼,這部分代碼獨(dú)立于微服務(wù)群的業(yè)務(wù)特征,往往是提供更低層次的函數(shù)庫(kù)或組件,如版本比較、時(shí)間對(duì)比工具、上傳資源組件等。這一類(lèi)代碼應(yīng)當(dāng)視為第三方獨(dú)立倉(cāng)庫(kù),類(lèi)似我們引用的 Github 上的開(kāi)源庫(kù)。

第二類(lèi)代碼相對(duì)簡(jiǎn)單,作為獨(dú)立于微服務(wù)業(yè)務(wù)群組的倉(cāng)庫(kù)存在即可。對(duì)于第一類(lèi),微服務(wù)之間同步的信息傳遞,往往是通過(guò) HTTP、PRC 等通信協(xié)議,并依據(jù)交互雙方定義的業(yè)務(wù)協(xié)議將傳遞的 JSON 或 Protobuf 等解析為業(yè)務(wù)可理解的信息。這部分交互相關(guān)的代碼可以被視為公用代碼。本文來(lái)探討這部分代碼在整個(gè)微服務(wù)體系中如何更好的被組織和使用,以提升研發(fā)效率并減少相關(guān)故障。

此部分代碼組織的問(wèn)題,本質(zhì)上并非為系統(tǒng)或模塊的依賴問(wèn)題,而是在微服務(wù)架構(gòu)體系中,如何更方便的同步和使用公用代碼的問(wèn)題。我司在走上了微服務(wù)修行的不歸之路后,此部分交互代碼組織也經(jīng)歷了不同的階段,本文會(huì)借此案例進(jìn)行探討。Go 是我司的指定語(yǔ)言,本文的一些示例和特性是用 Golang 來(lái)展示,Git 是最流行的分布式版本控制系統(tǒng),討論也基于 Git。

1. 交互示例

討論之初,我們首先列出微服務(wù)之間交互的代碼和目錄結(jié)構(gòu)示例,及簡(jiǎn)單的三個(gè)定義:

  1. 源服務(wù):產(chǎn)出 Model、Client 的服務(wù)。
  2. Model:定義數(shù)據(jù)模型的代碼,作為微服務(wù)業(yè)務(wù)之間的交互協(xié)議編碼解析使用。
  3. Client:微服務(wù)發(fā)起請(qǐng)求的代碼,并使用 Model 來(lái)解析相互傳遞的數(shù)據(jù),通常是源服務(wù)提供 API 時(shí)候,可以附帶提供。

微服務(wù)交互的簡(jiǎn)化代碼及目錄如下,其中 model 存放數(shù)據(jù)模型代碼,client 存放網(wǎng)絡(luò)請(qǐng)求代碼:

微服务公用代码组织实践

數(shù)據(jù)模型實(shí)體代碼:project/base/model/user.go

  1. type User struct { 
  2.     UserID      int64  `json:"user_id" form:"user_id"
  3.     UserName    string `json:"user_name" form:"user_name"
  4.     Status      int    `json:"status" form:"status"
  5.     Avatar      string `json:"avatar" form:"avatar"
  6.     AvatarSmall string `json:"avatar_small" form:"avatar_small"

交互請(qǐng)求代碼:

  1. project/base/client/user_client.go 
  2. url := "http://<demo.com>/project/<user-info-api>" 
  3. userClient := http.Client{ 
  4. Timeout: time.Second * 2// Maximum of 2 secs 
  5. req, _ := http.NewRequest(http.MethodGet, url, nil) 
  6. res, _ := userClient.Do(req) 
  7. body, _ := ioutil.ReadAll(res.Body) 
  8. user := model.User{} 
  9. jsonErr := json.Unmarshal(body, &user) 
  10. if jsonErr != nil { 
  11.  log.Fatal(jsonErr) 
  12. fmt.Println(user.UserName) 

2. 練氣期——手工拷貝:

微服務(wù)的核心意義不止是服務(wù)拆分,也在于團(tuán)隊(duì)的組織和溝通形式也在調(diào)整。團(tuán)隊(duì)初始切換為微服務(wù)時(shí)候,各個(gè)成員從源服務(wù)拷貝 data 內(nèi) model 和 client 至各自相關(guān)服務(wù)。雖然代碼拷貝后各自修改完全不影響,但隨著服務(wù)數(shù)目的增多,找源服務(wù)拷貝代碼越來(lái)越麻煩,大家的溝通過(guò)程通常是:

A:“兄弟們,我代碼提了。”

B:“又改了啊!改了哪些。”

A:“xxx xxx xxx xxx xxx xxx xxx xxx xxx ”,

B:“靠,這么多,你把文件傳給我!”

G:“我也要!”

這種全憑人力來(lái)維護(hù)代碼的過(guò)程,容易缺失修改文件的。且更新操作不順暢,長(zhǎng)期容易導(dǎo)致相關(guān)微服務(wù)和源服務(wù)維護(hù)的 base 差異較大。從源服務(wù)拷貝回來(lái)的代碼,和自身項(xiàng)目庫(kù)的約束并無(wú)二致,可以被任意修改,容易因本地的手工修改而引發(fā)協(xié)議的不一致,隨著團(tuán)隊(duì)人員增加和規(guī)模擴(kuò)大,這種方式開(kāi)始被組員吐槽和詬病。

3. 筑基期——集中倉(cāng)庫(kù)

程序員是不會(huì)滿足現(xiàn)狀的,程序員天生就是要解決手動(dòng)操作的問(wèn)題,拷貝代碼這種原始而粗暴的手段自然很容易被淘汰掉。有成員提出創(chuàng)建個(gè)單獨(dú)的倉(cāng)庫(kù)來(lái)集中管理各微服務(wù) base 代碼,代碼從源服務(wù)被手工拷貝至 base 倉(cāng)庫(kù),所有成員從這個(gè)單獨(dú)的 base 倉(cāng)庫(kù)拉取更新,簡(jiǎn)直是順理成章。團(tuán)隊(duì)成員一致認(rèn)為這簡(jiǎn)直是修仙進(jìn)階的必然趨勢(shì),所有人一拍即合。

調(diào)整為統(tǒng)一的代碼倉(cāng)庫(kù)后,雖然仍舊需要手動(dòng)拷貝到 base 倉(cāng)庫(kù)代碼。但使用方操作簡(jiǎn)單,只需有事沒(méi)事,拉取下 base 倉(cāng)庫(kù)就可以拉到最新的依賴代碼。而且整個(gè)團(tuán)隊(duì)微服務(wù)之間交互的所有的 client 和 model 都可以在 base 里直接找到。大家對(duì) base 倉(cāng)庫(kù)的認(rèn)知統(tǒng)一,一時(shí)間歌舞升平,相安無(wú)事。

整個(gè)代碼倉(cāng)庫(kù)組織如下,其中 base 倉(cāng)庫(kù)包含多個(gè) project-base 目錄,該目錄與 project 倉(cāng)庫(kù)里 base 目錄完全一致:

微服务公用代码组织实践

此時(shí)團(tuán)隊(duì)成員溝通的過(guò)程通常是:

A、B 、C、D、E、F、G:“push!push!push!push!”

A:“兄弟們,我代碼提了,更新下 base!”

B、C、D、E、F、G:“pull!pull!pull!pull!”

在 95% 的情況下,大家的合作溝通都是是愉快的,然而也有倒血霉的時(shí)候,特別是當(dāng)小 G 被迫緊急修復(fù)一個(gè)半年內(nèi)都處于穩(wěn)定維護(hù)期的項(xiàng)目時(shí):

A、B、C、D、E、F、G:持續(xù)默默提交…

G:“pull!”

G:“蒼天,我只要更新 B 的一個(gè)更新,為啥 pull 下來(lái)幾百個(gè)更新,我編譯不過(guò)啊!嚶嚶嚶。”

小 G 很負(fù)責(zé)任,嚶嚶之后還得解決問(wèn)題,好容易深夜兩點(diǎn)解決完畢,終于上線了,殊不知更慘的還在后面,深夜四點(diǎn)被監(jiān)控告警叫起來(lái),因?yàn)閯偛诺纳暇€引發(fā)了一起線上事故。

老板:“這個(gè)線上事故影響面大,小 G 明天復(fù)盤(pán)一下!”

G:“我只是想更新了 B 的 base,A、B、C、D、E、F 幾個(gè)月那么多更新,我哪知道掉坑里了啊。”小 G 嚎啕大哭。

問(wèn)題根源:

集中倉(cāng)庫(kù) Base 為各個(gè)微服務(wù)的 base 代碼合集,一次更新會(huì)導(dǎo)致全部更新,無(wú)法單獨(dú)更新某一部分 Base。如示例中 aggregation 項(xiàng)目更新 project1-base 時(shí),project2-base、project3-base、project4-base 也會(huì)被 Git 無(wú)腦直接更新,這些代碼的改動(dòng),通常不在預(yù)期和測(cè)試的范圍之內(nèi)。base 內(nèi)只有數(shù)據(jù)結(jié)構(gòu)和請(qǐng)求代碼相對(duì)比較簡(jiǎn)單,雖然長(zhǎng)期天下太平,但冷不丁也會(huì)禍起蕭墻。要牢記,任何更改都不安全,如何減少公用代碼倉(cāng)庫(kù)的變更的影響范圍,是我們要去探究的。

4. 結(jié)丹期——獨(dú)立子倉(cāng)庫(kù)

小 G 痛定思痛,第二天腫著雙眼來(lái)到了公司,拉上研發(fā)的小伙伴們進(jìn)行復(fù)盤(pán),復(fù)盤(pán)的結(jié)果是,這種統(tǒng)一集中倉(cāng)庫(kù)管理的方式,肯定有改進(jìn)空間,大家七嘴八舌:

B:“可以打 Tag”

G:“不行,解決不了我要部分更新,拉下一堆更新的問(wèn)題。”

C:“可以直接引用源項(xiàng)目,Go vendor 只會(huì)復(fù)制需要文件到當(dāng)前工程”

D:“不行,直接引用微服務(wù)代碼心理負(fù)擔(dān)比較重,也容易誘導(dǎo)直接使用源微服務(wù)里其他代碼引起混亂,而且,對(duì)于跨部門(mén)且代碼權(quán)限有差異時(shí),此方案不適用,如保密級(jí)別高的工程。”

E:“……”

小 G 的眼淚沒(méi)有白流,一番討論后,大家明確了目標(biāo):應(yīng)該將集中倉(cāng)庫(kù)拆分或者分割引用,但又需要有便捷的子倉(cāng)庫(kù)拆分和同步方案,避免手工拷貝,才容易被接受推廣,畢竟大家都是懶人。

目標(biāo)明確了,小 G 一頓猛如虎的調(diào)研后,驚喜的發(fā)現(xiàn):Git 雖然沒(méi)有可以使得 G 倉(cāng)庫(kù)直接引用 B 倉(cāng)庫(kù)某個(gè)目錄的功能,但已經(jīng)有 B 項(xiàng)目的子目錄,直接和 B-Base 子倉(cāng)庫(kù)保持同步的內(nèi)置功能:git subtree 。B 倉(cāng)庫(kù)子目錄和 B-Base 子倉(cāng)庫(kù)保持同步,小 G 直接使用 B-Base 子倉(cāng)庫(kù)即可。這一定是有不少同行也給 Git 提過(guò)類(lèi)似的需求,雖然工具仍還不夠完美,但我們做些限制,只有源倉(cāng)庫(kù)提交,只用它最基本的功能仍然夠用!小 G 感慨,早發(fā)現(xiàn)就好了。獨(dú)立子倉(cāng)庫(kù)同步機(jī)制詳述下文列出。

此時(shí)的代碼倉(cāng)庫(kù)組織形式如下:

微服务公用代码组织实践

A:“兄弟們,我代碼提了,有需要的更新下我的 Base”

B、C、D、E、F:無(wú)視之。

G:“好嘞!pull A-base!”

此方案雖然也有一些額外成本,比如小倉(cāng)庫(kù)數(shù)增多,需要大家了解 git subtree 命令。但是權(quán)衡比較,正向收益居多,而且 git subtree 命令也可以被直接使用腳本或 Git 鉤子直接屏蔽,使得更新范圍更加可控的同時(shí),更加便捷自動(dòng)化。

這種方案使⽤用現(xiàn)有的工具體系,未增加學(xué)習(xí)成本,同時(shí)微服務(wù)的所有者可以決定何時(shí)選擇同步該修改到服務(wù)中,有效減少了未經(jīng)測(cè)試代碼直接進(jìn)⼊線上而引發(fā)故障概率。

對(duì)于前文所述的純工具類(lèi)代碼,我們也建議避免包攬萬(wàn)象的工具倉(cāng)庫(kù),例如 common 倉(cāng)庫(kù)。更好的方法是把包攬萬(wàn)象庫(kù)按功能拆分成具有獨(dú)立上下文的多個(gè)庫(kù),例如創(chuàng)建基于上下文的 storage、util、log 等倉(cāng)庫(kù)。這能夠把不經(jīng)常改變的代碼和頻繁改動(dòng)的代碼分離開(kāi),使用方自行控制每次變更范圍。

獨(dú)立子倉(cāng)庫(kù)同步機(jī)制詳述:

格式約定:

約定對(duì)每個(gè)微服務(wù),創(chuàng)建相對(duì)應(yīng)的子倉(cāng)庫(kù),倉(cāng)庫(kù)名以<-base>為后綴,比如,Project1 對(duì)應(yīng)子倉(cāng)庫(kù)為 Project1-base <git@gitlab.company.com:back-end/project1-base.git>

約定在源微服務(wù)代碼組織中創(chuàng)建 base 包,model 和 client 存放其中(命名也可以根據(jù)自己公司規(guī)范),如圖:

微服务公用代码组织实践

約定其他微服務(wù)需要和源微服務(wù)交互時(shí)候,直接使用子倉(cāng)庫(kù)。由于子倉(cāng)庫(kù)是完全看做獨(dú)立的倉(cāng)庫(kù)來(lái)依賴,日常更新普通的 git pull 命令即可。

源服務(wù) base 倉(cāng)庫(kù)拆分:

源服務(wù) base 倉(cāng)庫(kù)拆分的核心命令如下:

  1. cd  <project-folder> 
  2. # 無(wú)base目錄時(shí),直接添加子倉(cāng)庫(kù) 
  3. git subtree add -P base <git@gitlab.company.com:back-end/project-base.git> master 
  4. # 如果base已經(jīng)存在,先拆分提交至子倉(cāng)庫(kù),再刪除本地后關(guān)聯(lián)遠(yuǎn)程子倉(cāng)庫(kù)。 

cd <project-folder># 無(wú)base目錄時(shí),直接添加子倉(cāng)庫(kù)git subtree add -P base <git@gitlab.company.com:back-end/project-base.git> master# 如果base已經(jīng)存在,先拆分提交至子倉(cāng)庫(kù),再刪除本地后關(guān)聯(lián)遠(yuǎn)程子倉(cāng)庫(kù)。

日常同步:

日常提交限定在源服務(wù)內(nèi),避免過(guò)多使用高階 gitsubtree 命令。提交過(guò)多后定期 git subtree split --rejoin 來(lái)解決提交都需要重頭遍歷 commits 耗時(shí)過(guò)長(zhǎng)的問(wèn)題, 建議通過(guò)腳本和 Git 鉤子來(lái)自動(dòng)化:

  1. # 提交 
  2. git subtree push -P <name-of-folder> <git@gitlab.company.com:back-end/project1-base.git> master 
  3.  
  4. # 更新 
  5. git subtree pull -P <name-of-folder> <git@gitlab.company.com:back-end/project1-base.git> master 

5. 總結(jié)討論

公用代碼組織形式演進(jìn)的過(guò)程,是繁雜宏大的研發(fā)工程中一個(gè)細(xì)小的工具化和規(guī)范化的流程。通常,集中倉(cāng)庫(kù)的方式操作簡(jiǎn)單直觀,也容易被認(rèn)同,絕大部分時(shí)間也都可以運(yùn)轉(zhuǎn)正常。伴隨著問(wèn)題的驅(qū)動(dòng),我們切換至更精細(xì)的獨(dú)立子倉(cāng)庫(kù)方式。獨(dú)立子倉(cāng)庫(kù)方案使用現(xiàn)有的工具體系,在不增加復(fù)雜度的情況下,提供自動(dòng)推送變更以及可選擇同步公用代碼能力。實(shí)踐中有效提高效率,也減少了未經(jīng)測(cè)試代碼直接進(jìn)入線上而引發(fā)故障概率,是本文推薦的方案。

當(dāng)然,我們看到每種方案在各公司也有不同實(shí)踐,如有的公司手工拷貝代碼使用的也很好。在實(shí)踐中可以根據(jù)自己團(tuán)隊(duì)的口味來(lái)選擇方案,更歡迎有更好經(jīng)驗(yàn)的小伙伴來(lái)交流。

6. 作者介紹

奇正,曾在奧多比 、百度任高級(jí)工程師,現(xiàn)任某互聯(lián)網(wǎng)公司后端業(yè)務(wù)線 Leader,先后從事過(guò) C++、Android,Golang 開(kāi)發(fā)工作。

 

責(zé)任編輯:張燕妮 來(lái)源: 架構(gòu)頭條
相關(guān)推薦

2017-09-05 14:05:11

微服務(wù)spring clou路由

2023-02-08 09:42:30

策略方式容量

2021-09-08 10:32:29

微服務(wù)容器化Serverless

2024-01-10 21:35:29

vivo微服務(wù)架構(gòu)

2022-09-01 08:17:15

Gateway微服務(wù)網(wǎng)關(guān)

2018-12-17 16:44:49

Golang微服務(wù)

2022-08-30 15:12:10

架構(gòu)實(shí)踐

2018-12-17 16:48:05

Golang微服務(wù)

2018-12-17 16:39:20

Golang微服務(wù)

2024-05-16 13:13:39

微服務(wù)架構(gòu)自動(dòng)化

2018-04-20 10:38:25

2022-01-24 10:26:46

Kubernetes微服務(wù)

2023-12-19 09:33:40

微服務(wù)監(jiān)控

2019-12-26 15:49:14

微服務(wù)架構(gòu)業(yè)務(wù)

2020-04-21 15:20:12

微服務(wù)架構(gòu)實(shí)踐

2021-02-20 10:26:00

前端

2023-09-02 20:55:04

微服務(wù)架構(gòu)

2023-11-06 08:55:31

2025-09-05 01:00:00

2021-10-25 10:40:03

Java開(kāi)發(fā)微服務(wù)
點(diǎn)贊
收藏

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