使用 Go Workspaces 管理系統服務:從單體架構到分散式架構的彈性實現

在這篇文章,我要跟大家分享一下我是怎麼使用 Go workspaces 來管理多個系統服務,並且實現單體架構和微服務架構之間的彈性切換。這其實是我這幾年在做支付和金融系統時的一些實戰經驗,當系統越來越大,很多架構上的決策就變得非常重要。這篇文章會幫大家解開一些疑惑,還會分享怎麼設計專案的檔案目錄結構,讓系統在擴展時變得更靈活好維護。

1. 為什麼用 Go workspaces?

大家可能都有過類似的經驗,當系統變得複雜的時候,不同服務之間的依賴關係和版本管理會讓人頭大。特別是當你把系統拆成很多微服務後,怎麼有效管理這些模組之間的依賴,不讓它們互相影響,就變得非常棘手。

Go 在 1.18 推出的 workspaces 功能,真的可以幫助解決這個問題。透過這個工具,我們可以把每個服務獨立出來成為一個 Go module,這樣每個模組的依賴關係都可以獨立管理,而且還可以更輕鬆地在單體架構和微服務之間切換。

2. 如何規劃檔案目錄結構

說到如何規劃一個專案的目錄結構,這其實是整個系統維護的核心。特別是當你要在單體和微服務架構間保持彈性時,規劃得當的目錄結構可以讓開發、測試和部署都變得更順利。

這是我常用的目錄結構範例,適合同時管理多個微服務或模組:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
project-root/

├── go.work # Go workspace 設定檔
├── go.work.sum # Go workspace 依賴管理檔
├── services/ # 所有系統服務的目錄
│ ├── user-service/ # 使用者服務
│ │ ├── cmd/
│ │ │ └── main.go
│ │ ├── internal/
│ │ ├── pkg/
│ │ └── go.mod
│ ├── order-service/ # 訂單服務
│ │ ├── cmd/
│ │ │ └── main.go
│ │ ├── internal/
│ │ ├── pkg/
│ │ └── go.mod
│ ├── payment-service/ # 支付服務
│ │ ├── cmd/
│ │ │ └── main.go
│ │ ├── internal/
│ │ ├── pkg/
│ │ └── go.mod
│ └── shared/ # 各服務共用的程式碼(例如工具函式)
│ ├── internal/
│ └── pkg/
├── Makefile # 管理建置和部署的腳本
└── README.md # 專案說明文件

這個結構讓我們可以把系統中的每個業務模組分別放在獨立的資料夾裡,每個模組都有自己的 go.mod 檔案,這樣每個模組的依賴就能各自管理,而且如果將來要把某個服務獨立出來運行或擴展,也會非常方便。

3. Go Workspace 的設定

要開始使用 Go Workspace,可以利用 Go 提供的 CLI 工具進行自動化的設定。

首先,進入專案的根目錄,並透過以下指令來初始化一個新的 workspace:

1
go work init

這條命令會在專案根目錄下建立一個 go.work 檔案,表示這是我們的 Go workspace 的起點。

接下來,我們可以使用 go work use 來將現有的模組(例如 user-serviceorder-servicepayment-service)加入到 workspace 裡面:

1
go work use ./services/user-service ./services/order-service ./services/payment-service

這會自動將這三個模組加入到 go.work 檔案中,這樣你的 workspace 檔案就會像這樣:

1
2
3
4
5
6
7
go 1.18

use (
./services/user-service
./services/order-service
./services/payment-service
)

這個流程讓我們可以快速管理多個模組,並確保這些模組在同一個 workspace 中協作開發,非常方便。

4. 實現單體和微服務架構的彈性切換

在實際的專案開發中,我們經常需要在 單體架構微服務架構 之間靈活切換,特別是系統在初期和後期的需求會有所不同。

單體架構的情境

在專案初期,如果你的團隊規模不大,或是系統還在快速迭代的階段,單體架構往往是個不錯的選擇。這樣的架構部署起來比較簡單,所有服務都會打包在一個應用內運行。

你可以在專案的 main.go 中把所有模組都匯入,像這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"services/user-service"
"services/order-service"
"services/payment-service"
)

func main() {
go user-service.Start()
go order-service.Start()
go payment-service.Start()

select {} // 避免 main goroutine 結束
}

然後,你只需要執行 go build,就能把整個應用打包成一個單一的可執行檔,部署也會變得很簡單。

微服務架構的情境

當系統越來越大,某些服務的負載可能會不斷增加,這時就需要把這些服務拆分成獨立的微服務。透過 Go workspace,我們可以輕鬆地把每個模組分開,變成獨立的服務來部署。

你只需要進到每個模組的資料夾,然後各自建置它們的可執行檔:

1
2
3
4
5
6
7
8
cd services/user-service
go build -o user-service

cd services/order-service
go build -o order-service

cd services/payment-service
go build -o payment-service

這樣一來,每個微服務可以分別部署在不同的服務器或容器裡,達到系統的彈性擴展。

5. 結語

透過 Go workspaces 和合理的檔案目錄結構設計,我們能夠輕鬆管理多個系統服務,並且可以在單體架構和微服務架構之間靈活切換。這不僅提升了開發效率,也讓我們在面對系統擴展時更加從容。希望這篇文章能夠讓你在處理多服務管理的時候,也能夠輕鬆應對不同的需求變化。

如果你剛好在做類似的專案,或是考慮將系統進行服務拆分,試試 Go workspaces,或許會讓你感到意外地好用!

相關文章

在 Spring Boot 使用 AOP 印日誌
技術

2021/06/26

建置 Log4j2
技術

2021/06/26