微服務在Golang開發(fā)中的實現方案
Part 01
微服務的概念
在傳統(tǒng)軟件開發(fā)中,整個應用的代碼都組織在一個單一的代碼庫,一般會有以下拆分代碼的方式:一是按照特征做代碼拆分,如MVC模式;二是按照功能做拆分,在更大的項目中將代碼封裝在處理不同業(yè)務的包中,包內部再做拆分。
無論怎么拆分,最終二者的代碼都會集中在一個庫中進行開發(fā)的管理,而微服務則是上述第二種拆分方法的拓展,其將代碼按功能拆分為好幾個包,每個都是可獨立運行的單一代碼庫,其區(qū)別如下:
傳統(tǒng)代碼庫與微服務代碼庫區(qū)別
微服務相較于傳統(tǒng)開發(fā)來說大大降低了開發(fā)維護復雜度且提高了業(yè)務拓展性。在傳統(tǒng)單一代碼庫的應用中,模塊之間是緊耦合且邊界模糊的,隨著產品的深入迭代,代碼的開發(fā)和維護將變得更加復雜,潛在的bug和漏洞也不可避免的會越來越多,而將整個應用的代碼按功能對應拆分為小且獨立的微代碼服務庫,模塊耦合度減小、各模塊間邊界進一步清晰。在傳統(tǒng)項目開發(fā)中,可能會有一部分代碼會在多個模塊中頻繁地被用到,這種復用性很高的模塊常常被抽離出來作為公共代碼庫使用,當此功能要拓展功能時,單一代碼庫的規(guī)模只增不減,整個應用還需重新部署。而在微服務框架中,高復用模塊可作為單個服務獨立出來,可獨立運行、測試和部署。
微服務是一種架構理念而不是具體的框架項目,許多編程語言都可以實現,但有的語言對微服務開發(fā)有天生的優(yōu)勢,Golang便是之一。Golang本身十分輕便,運行效率極高,同時對并發(fā)編程有著原生的支持,從而能更好的利用多核處理器。這里介紹一種成熟的golang分布式微服務框架—go-zero。
Part 02
使用go-zero微服務框架的好處
- 輕松獲得支撐千萬日活服務的穩(wěn)定性;
- 內建級聯(lián)超時控制、限流、自適應熔斷、自適應降載等微服務治理能力,無需配置和額外代碼;
- 微服務治理中間件可無縫集成到其他現有框架使用;
- 極簡API描述一鍵生成各端代碼;
- 自動校驗客戶端請求參數合法性;
- 擁有大量微服務治理和并發(fā)工具包,社區(qū)生態(tài)優(yōu)秀。
go-zero架構圖
Part 03
熔斷原理及實現
熔斷在微服務中服務間非常常見,比如評論服務依賴審核服務而審核服務又依賴反垃圾服務,當評論服務調用審核服務時,審核服務又調用反垃圾服務,這時如果反垃圾服務宕機超時會導致審核服務一直等待,評論服務又在一直調用審核服務,這樣就會導致請求大量堆積導致所有服務宕機。
由此可見,在整個調用鏈中,中間某個環(huán)節(jié)出現異常會引起上游調用服務出現一系列問題,甚至導致整個調用鏈的服務都宕機。因此一個服務作為調用方調用另一個服務時,為了防止被調用服務出現問題進而導致調用服務出現問題,所有調用服務器需要進行自我保護,而常用的保護手段就是熔斷。
評論-審核-反垃圾服務調用圖
熔斷器原理:熔斷機制參考了日常生活中的保險絲的保護機制,電路超負荷運行時,保險絲會自動斷開,從而保證電路中的電器不受損害。服務中的熔斷機制指發(fā)起服務器調用時候,如果被調用方法返回的錯誤率超過閾值,那么將不會真正發(fā)起請求而是在調用方法時直接返回錯誤。
在熔斷器模式下,服務調用方為每一個調用服務維護一個狀態(tài)機,在此狀態(tài)機中有三個狀態(tài):
1.關閉(Closed):在此狀態(tài)下,我們需要一個計數器來記錄調用失敗的次數和總的請求次數,如果在某個時間窗口內,失敗的失敗率達到預設的閾值,則切換到斷開狀態(tài),此時開啟一個超時時間,當到達該時間則切換到半關閉狀態(tài),該超時時間是給了系統(tǒng)一次機會來修正導致調用失敗的錯誤,以回到正常的工作狀態(tài)。在關閉狀態(tài)下,調用錯誤是基于時間的,在特定的時間間隔內會重置,這能夠防止偶然錯誤導致熔斷器進入斷開狀態(tài)。
2. 打開(Open):在該狀態(tài)下,發(fā)起請求時會立即返回錯誤,一般會啟動一個超時計時器,當計時器超時后,狀態(tài)切換到半打開狀態(tài),也可以設置一個定時器,定期的探測服務是否恢復。
3. 半打開(Half-Open):在該狀態(tài)下,允許應用程序一定數量的請求發(fā)往被調用服務,如果這些調用正常,那么可以認為被調用服務已經恢復正常,此時熔斷器切換到關閉狀態(tài),同時需要重置計數。如果這部分仍有調用失敗的情況,則認為被調用方仍然沒有恢復,熔斷器會切換到打開狀態(tài),然后重置計數器,半打開狀態(tài)能夠有效防止正在恢復中的服務被突然大量請求再次打垮。
熔斷器狀態(tài)集?
Part 04
go-zero并發(fā)編程
在微服務開發(fā)中,api網管扮演對外提供restful api的角色,而api的數據往往以來其他服務,復雜的api更是會依賴多個甚至數十個服務,雖然單個被依賴服務的耗時一般較低但如果多個服務串行依賴的話那么整個api的耗時將會大大增加。
那么通過什么手段來優(yōu)化呢?我們首先想到的是通過并發(fā)來的方式來處理依賴,這樣就能降低整個依賴的耗時,Go基礎庫中為我們提供了 WaitGroup 工具用來進行并發(fā)控制,但實際業(yè)務場景中多個依賴如果有一個出錯我們期望能立即返回而不是等所有依賴都執(zhí)行完再返回結果,而且WaitGroup中對變量的賦值往往需要加鎖,每個依賴函數都需要添加Add和Done對于新手來說比較容易出錯。
基于以上的背景,go-zero框架中為我們提供了并發(fā)處理工具MapReduce,MapReduce是Google提出的一個軟件架構,用于大規(guī)模數據集的并行運算,go-zero中的MapReduce工具正是借鑒了這種架構思想,go-zero框架中的MapReduce工具主要用來對批量數據進行并發(fā)的處理,以此來提升服務的性能。
MapReduce原理圖