隨著應用程式規模的增長,採用微服務架構已成為常見的解決方案。本文將深入探討微服務架構中的測試、整合與資料管理,並以影片串流平臺 FlixTube 的開發過程為例,逐步說明如何在實務中應用這些技術。我們將涵蓋個別微服務的測試方法,包含環境變數的設定與執行模式的選擇,以及如何有效地整合新的微服務至既有系統中。此外,本文也將探討 HTTP 請求轉發的機制、Docker Compose 的應用,以及如何利用 MongoDB 建立與管理資料函式庫,並設定微服務的資料函式庫連線與路由。
個別微服務的測試
個別微服務的測試比整體應用程式的測試更為有效,因為我們可以快速地啟動和多載單個微服務,而不需要對整個應用程式進行操作。這樣可以大大提高開發和測試的效率。
在進行測試之前,我們需要設定環境變數來組態微服務。例如,設定連線埠號、儲存帳戶名稱和存取金鑰等。
export PORT=3000
export STORAGE_ACCOUNT_NAME=<儲存帳戶名稱>
export STORAGE_ACCESS_KEY=<存取金鑰>
或者,在Windows下:
set PORT=3000
set STORAGE_ACCOUNT_NAME=<儲存帳戶名稱>
set STORAGE_ACCESS_KEY=<存取金鑰>
注意,需要替換成實際的儲存帳戶名稱和存取金鑰。
執行微服務
執行微服務可以選擇生產模式或開發模式。生產模式下,可以使用以下命令:
cd chapter-4/example-2/azure-storage
npm start
或者,在開發模式下,可以使用nodemon進行實時多載:
npm run start:dev
這樣可以使得開發過程更加高效,因為我們可以在程式碼修改後立即看到效果,而不需要手動重啟微服務。
整合微服務
更新影片串流微服務是整合新微服務到應用程式中的第一步。之前,影片串流微服務從檔案系統載入測試影片。現在,我們將更新這個微服務,以便它可以委託載入影片給新的azure-storage微服務。
這樣做的目的是將關注點分離,使得影片串流微服務只負責串流影片給使用者,而不需要知道儲存的細節。
以下是更新後的影片串流微服務程式碼:
const express = require("express");
const http = require("http");
const PORT = process.env.PORT;
const VIDEO_STORAGE_HOST = process.env.VIDEO_STORAGE_HOST;
這段程式碼展示瞭如何將HTTP請求轉發給新的影片儲存微服務。
影片串流微服務的實作
在實作影片串流微服務時,我們需要使用 Node.js 的 http
模組來轉發 HTTP 請求。以下是實作的步驟:
載入 http 模組
首先,載入 Node.js 的 http
模組,以便我們可以轉發 HTTP 請求。
設定連線到影片儲存微服務
設定連線到影片儲存微服務的主機和埠號。這些資訊通常會儲存在環境變數中,以便於管理和佈署。
轉發 HTTP GET 請求
當收到對 /video
路由的 HTTP GET 請求時,轉發這個請求到影片儲存微服務。這包括設定轉發請求的主機、埠號、路徑、方法和標頭。
處理轉發請求的回應
當轉發請求的回應傳回時,將回應的狀態碼和標頭寫入原始請求的回應物件中。然後,使用 pipe
方法將轉發請求的回應資料流導向原始請求的回應物件中。
啟動伺服器
最後,啟動 Express 伺服器,並指定要監聽的埠號。
以下是實作上述步驟的程式碼範例:
const express = require('express');
const http = require('http');
const VIDEO_STORAGE_HOST = 'video-storage-host';
const VIDEO_STORAGE_PORT = 8080;
const PORT = 3000;
const app = express();
app.get('/video', (req, res) => {
const forwardRequest = http.request({
host: VIDEO_STORAGE_HOST,
port: VIDEO_STORAGE_PORT,
path: '/video?path=SampleVideo_1280x720_1mb.mp4',
method: 'GET',
headers: req.headers
}, (forwardResponse) => {
res.writeHeader(forwardResponse.statusCode, forwardResponse.headers);
forwardResponse.pipe(res);
});
req.pipe(forwardRequest);
});
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
});
內容解密:
在這個範例中,我們使用 http
模組來轉發 HTTP 請求。首先,載入 http
模組,並設定連線到影片儲存微服務的主機和埠號。然後,定義一個路由 /video
,當收到對這個路由的 HTTP GET 請求時,轉發這個請求到影片儲存微服務。最後,啟動 Express 伺服器,並指定要監聽的埠號。
圖表翻譯:
graph LR A[Client] -->|HTTP GET /video|> B[Express Server] B -->|Forward Request|> C[Video Storage Service] C -->|Response|> B B -->|Response|> A
在這個圖表中,Client 向 Express Server 傳送 HTTP GET 請求,Express Server 轉發這個請求到 Video Storage Service,Video Storage Service 處理請求並傳回回應,Express Server 將回應傳回給 Client。
微服務的資料管理
在微服務架構中,資料管理是一個非常重要的議題。每個微服務都需要存取和管理自己的資料,而這些資料可能來自不同的來源,例如資料函式庫、檔案系統或其他微服務。
轉發 HTTP 請求
在前面的例子中,我們使用 Node.js 內建的 HTTP 函式庫來轉發 HTTP 請求從一個微服務到另一個微服務。這個過程涉及到將請求轉發到目標微服務,然後將回應串流回給客戶端。
使用 Docker Compose 管理微服務
Docker Compose 是一個方便的工具,讓我們可以輕鬆地定義和管理多個容器。它允許我們將多個 Dockerfile 聚合成一個單一的檔案,從而簡化了微服務應用的管理。
增加新的微服務到 Docker Compose 檔案
當我們建立了一個新的微服務時,我們需要將它增加到 Docker Compose 檔案中。這樣,我們就可以使用 Docker Compose 來管理和啟動所有的微服務。
更新 Docker Compose 檔案
以下是更新的 Docker Compose 檔案,包含了新的 azure-storage 微服務:
version: '3'
services:
azure-storage:
image: azure-storage
build:
context:./azure-storage
dockerfile: Dockerfile
container_name: video-storage
ports:
- "4000:80"
environment:
- PORT=80
- STORAGE_ACCOUNT_NAME=${STORAGE_ACCOUNT_NAME}
- STORAGE_ACCESS_KEY=${STORAGE_ACCESS_KEY}
restart: "no"
video-streaming:
image: video-streaming
build:
context:./video-streaming
dockerfile: Dockerfile
container_name: video-streaming
ports:
- "4001:80"
environment:
在這個檔案中,我們定義了兩個微服務:azure-storage 和 video-streaming。每個微服務都有自己的 Dockerfile 和環境變數。
環境變數
在 Docker Compose 檔案中,我們使用環境變數來設定微服務的組態。例如,STORAGE_ACCOUNT_NAME 和 STORAGE_ACCESS_KEY 是用來設定 azure-storage 微服務的組態。
微服務容器化組態
在進行微服務的容器化組態時,我們需要定義每個服務的執行環境和相依性。以下是使用Docker Compose進行組態的示例:
組態檔案
我們可以透過docker-compose.yaml
檔案來定義微服務的組態。以下是增加新微服務到現有應用程式的組態範例:
version: '3'
services:
video-streaming:
ports:
- "80:80"
depends_on:
- video-storage
restart: no
video-storage:
ports:
- "80:80"
restart: no
在這個範例中,我們定義了兩個微服務:video-streaming
和video-storage
。每個微服務都有自己的容器,並且我們可以設定它們的埠號和相依性。
容器化微服務
使用Docker Compose,我們可以輕鬆地建立和管理多個容器。每個容器都可以執行一個獨立的微服務,例如:
video-streaming
微服務:負責處理影片串流的請求和回應。video-storage
微服務:負責儲存和管理影片檔案。
資料函式庫容器
除了微服務容器外,我們還需要一個資料函式庫容器來儲存和管理資料。例如,我們可以使用MongoDB作為資料函式庫:
services:
database:
image: mongo:latest
ports:
- "27017:27017"
restart: no
這個範例中,我們定義了一個名為database
的容器,使用最新版本的MongoDB映像檔,並將埠號27017對應到主機的埠號27017。
微服務之間的溝通
在微服務架構中,各個微服務之間需要溝通以實作業務邏輯。例如,video-streaming
微服務需要從video-storage
微服務中取得影片檔案。為了實作這種溝通,我們可以使用RESTful API或訊息佇列等技術。
微服務的設計與實踐
在微服務架構中,各個服務之間的溝通和協調是非常重要的。為了實作這一點,我們可以使用環境變數來組態微服務,以連線到Azure儲存帳戶。這樣做的好處是,可以讓微服務之間的溝通更加靈活和可擴充套件。
環境變數的設定
為了連線到Azure儲存帳戶,我們需要設定環境變數STORAGE_ACCOUNT_NAME
和STORAGE_ACCESS_KEY
。這些變數將被用來組態微服務,以連線到Azure儲存帳戶。
微服務之間的溝通
在微服務架構中,各個服務之間的溝通是非常重要的。為了實作這一點,我們可以使用容器名稱來連線微服務。例如,我們可以將容器名稱設定為video-storage
,以連線到影片儲存微服務。
設計理念
在設計微服務架構時,我們需要考慮到各個服務之間的溝通和協調。為了實作這一點,我們可以使用環境變數和容器名稱來組態微服務。這樣做的好處是,可以讓微服務之間的溝通更加靈活和可擴充套件。
測試微服務
為了確保微服務的正確性,我們需要進行測試。測試的方法包括使用Docker Compose來啟動多個容器,然後使用REST API來測試各個微服務。
測試影片串流微服務
為了測試影片串流微服務,我們可以使用REST API來請求影片。例如,我們可以使用curl
命令來請求影片:
curl http://localhost:4001/video
測試影片儲存微服務
為了測試影片儲存微服務,我們可以使用REST API來請求影片。例如,我們可以使用curl
命令來請求影片:
curl http://localhost:4000/video
圖表翻譯:
graph LR A[影片串流微服務] --> B[影片儲存微服務] B --> C[Azure儲存帳戶] C --> D[環境變數] D --> E[容器名稱] E --> F[REST API] F --> G[測試]
內容解密:
在上面的圖表中,我們可以看到影片串流微服務和影片儲存微服務之間的溝通。影片串流微服務使用REST API來請求影片,然後影片儲存微服務使用環境變數和容器名稱來連線到Azure儲存帳戶。最後,影片儲存微服務傳回影片給影片串流微服務。這個過程可以使用REST API來測試。
4.4.5 雲端儲存與叢集儲存
在這個階段,如果你對 Kubernetes 有所瞭解,你可能會想知道為什麼我們沒有使用 Kubernetes 卷來進行檔案儲存,而是選擇了雲端儲存。這是一個重要的設計決策,取決於你的專案、商業和客戶的需求。 我們選擇雲端儲存而不是叢集儲存,因為它簡單、在開發環境中可用、廉價且由雲端供應商管理。這些是雲端儲存的優點,也是我們常用的原因。此外,我們還沒有學習過 Kubernetes,所以我們不能在這個階段使用 Kubernetes 卷。 然而,有另一個重要的原因是我們通常選擇雲端儲存而不是叢集儲存。我們可以將檔案和資料儲存在 Kubernetes 叢集中,但我更喜歡我的生產叢集是無狀態的,這樣我就可以在不擔心丟失任何資料的情況下隨時銷毀和重建叢集。稍後,這將使我們能夠使用藍綠佈署來進行生產環境的更新,我們將在第 12 章中討論這個主題。
4.4.6 我們完成了什麼?
恭喜!我們現在有一個小型的微服務應用程式正在執行!這是一個很大的成就。使用 Docker Compose,我們建立了一個基礎結構,可以輕鬆地增加新的微服務並擴充套件我們的應用程式。花點時間拍拍自己的背——這是一個很大的里程碑! 我們完成了什麼?我們為我們的應用程式增加了檔案儲存功能。現在,我們的微服務可以將檔案儲存在外部雲端儲存中,這給了我們的應用程式一個地方來存放影片。你可能會想知道如何允許客戶上傳自己的影片。目前尚未實作影片上傳,但這將在第 10 章中實作。
4.5 增加資料函式庫到我們的應用程式
另一半的資料管理與資料函式庫有關。大多數應用程式需要某種形式的資料函式庫來儲存動態資料,FlixTube也不例外。 首先,我們需要為每個影片增加一些基本的資料儲存。我們將從使用資料函式庫開始,解決之前在影片串流微服務中硬編碼路徑的問題。
4.5.1 為什麼選擇 MongoDB?
MongoDB 是最受歡迎的 NoSQL 資料函式庫之一。使用 Docker 啟動 MongoDB 資料函式庫允許我們在幾乎瞬間內就有了一個可用的資料函式庫。我們只需要指定資料函式庫映像的名稱,Docker 就會從 Docker Hub 下載並在我們的開發電腦上啟動它。 MongoDB 易於使用,提供了一個靈活的資料函式庫來儲存結構化的資料,並且具有豐富的查詢 API。但是,有很多不同的資料函式庫可以輕鬆地使用 Docker 啟動,所以為什麼選擇 MongoDB?在我的經驗中,即使手動下載和安裝 MongoDB 也相對容易;現在有了 Docker,它變得更加容易。像任何資料函式庫一樣,我們可以使用 MongoDB 來儲存豐富的結構化資料。MongoDB 也以高效能和極高的可擴充套件性而聞名。
4.5.2 在開發環境中增加資料函式庫伺服器
我們將使用 Docker Compose 在開發環境中增加一個資料函式庫伺服器,方法與之前增加影片儲存微服務類別似。現在,在 example-3 中,我們將在 Docker Compose 檔案中增加一個新的容器來主持單一資料函式庫伺服器。我們只需要一個單一的伺服器,但我們可以在該伺服器上主持多個資料函式庫。這意味著我們將為未來做好準備,以便輕鬆地建立更多資料函式庫,同時增加更多微服務到我們的應用程式中。
微服務應用程式的Docker Compose檔案設定
在微服務架構中,Docker Compose是一種強大的工具,能夠幫助我們輕鬆地管理和啟動多個容器。以下是微服務應用程式的Docker Compose檔案設定範例:
version: '3'
services:
db:
image: mongo:7.0.0
container_name: db
ports:
- "27017:27017"
專案目錄結構
一個典型的微服務專案目錄結構如下:
Dockerfile
:定義容器的建置過程package-lock.json
和package.json
:Node.js專案的依賴包管理檔案src
:原始碼目錄index.js
:應用程式的入口檔案db-fixture
:資料函式庫測試資料目錄videos.json
:範例影片資料檔案
video-streaming
:影片串流微服務目錄
Docker Compose檔案解釋
Docker Compose檔案使用YAML格式定義。以下是檔案的解釋:
version
:指定Docker Compose檔案的版本services
:定義多個服務(容器)db
:定義一個名為db
的服務image
:指定使用的Docker映象(本例中為MongoDB 7.0.0)container_name
:指定容器的名稱ports
:指定容器的連線埠對映(本例中將主機的27017連線埠對映到容器的27017連線埠)
內容解密:
在這個範例中,我們定義了一個名為db
的服務,使用MongoDB 7.0.0的Docker映象。容器名稱為db
,並將主機的27017連線埠對映到容器的27017連線埠。這樣,我們就可以使用Docker Compose輕鬆地啟動和管理MongoDB容器。
圖表翻譯:
graph LR A[Docker Compose] -->|定義服務|> B[db] B -->|使用映象|> C[MongoDB 7.0.0] C -->|對映連線埠|> D[27017:27017]
在這個Mermaid圖表中,我們展示了Docker Compose如何定義服務、使用映象和對映連線埠。這個圖表幫助我們更好地理解Docker Compose檔案的結構和功能。
MongoDB 資料函式庫組態
在上面的組態檔中,我們新增了一個 MongoDB 資料函式庫容器。讓我們逐步分析這個組態:
image: azure-storage
和image: video-streaming
分別指定了 azure-storage 和 video-streaming 微服務的映象名稱。build
區塊指定了 Dockerfile 的路徑和內容。例如,context:./azure-storage
指定了 Dockerfile 的路徑為當前目錄下的 azure-storage 子目錄。container_name
指定了容器的名稱。例如,container_name: video-storage
將容器命名為 video-storage。ports
區塊指定了連線埠對映。例如,- "4001:80"
將容器內的 80 連線埠對映到宿主機的 4001 連線埠。environment
區塊指定了環境變數。例如,- PORT=80
將 PORT 環境變數設定為 80。restart
指定了容器的重啟策略。例如,restart: always
將容器設定為始終重啟。
MongoDB 組態詳細
MongoDB 組態包括以下幾個部分:
db
容器的組態:image: mongo
指定了 MongoDB 的映象名稱。container_name: db
將容器命名為 db。ports
區塊指定了連線埠對映。例如,- "4000:27017"
將 MongoDB 的標準連線埠 27017 對映到宿主機的 4000 連線埠。restart: always
將容器設定為始終重啟。
video-streaming
微服務的組態:environment
區塊指定了環境變數。例如,- DBHOST=mongodb://db:27017
將 DBHOST 環境變數設定為 MongoDB 的連線字串。
組態分析
在這個組態中,我們建立了一個 MongoDB 資料函式庫容器,並將其連線埠對映到宿主機的 4000 連線埠。這樣,其他容器就可以透過 27017 連線埠存取 MongoDB 資料函式庫。
同時,我們也組態了 video-streaming 微服務的環境變數,包括 DBHOST 和 DBNAME。這些變數將用於組態微服務與 MongoDB 資料函式庫的連線。
Mermaid 圖表
graph LR A[MongoDB] -->|27017|> B[video-streaming] B -->|DBHOST|> A C[宿主機] -->|4000|> A
圖表翻譯:
這個 Mermaid 圖表展示了 MongoDB 資料函式庫容器、video-streaming 微服務和宿主機之間的關係。MongoDB 容器暴露 27017 連線埠,video-streaming 微服務透過 DBHOST 環境變數連線到 MongoDB 資料函式庫。同時,宿主機可以透過 4000 連線埠存取 MongoDB 資料函式庫。
程式碼實作示例
from pymongo import MongoClient
# MongoDB 連線字串
DBHOST = "mongodb://db:27017"
# 建立 MongoDB 連線
client = MongoClient(DBHOST)
# 選擇資料函式庫
db = client["video-streaming"]
# 選擇集合
collection = db["videos"]
# 插入資料
collection.insert_one({"title": "示例影片", "url": "https://example.com/video"})
# 查詢資料
videos = collection.find()
# 列印查詢結果
for video in videos:
print(video["title"])
內容解密:
這個程式碼實作示例展示瞭如何使用 Python 連線到 MongoDB 資料函式庫,並進行基本的 CRUD(建立、讀取、更新、刪除)操作。首先,我們建立了一個 MongoDB 連線,然後選擇了資料函式庫和集合。接下來,我們插入了一條示例資料,然後查詢了所有資料並列印了查詢結果。
組態微服務以連線資料函式庫
為了讓微服務能夠連線資料函式庫,我們需要進行一些設定。首先,我們需要設定微服務使用的資料函式庫名稱。這個設定可以透過環境變數來實作。
增加資料函式庫到應用程式
在我們的主機作業系統(OS)上,我們已經將連線埠對映到 4000。這是一個任意的選擇,我們可以選擇任何數字,包括 27017。我更喜歡不使用 MongoDB 的標準連線埠,因為這可能會與我們在主機 OS 上執行的 MongoDB 例項發生衝突。
這是一個良好的設定。我們的應用程式可以透過標準連線埠與 MongoDB 互動,但我們也可以使用工具(稍後會看到)直接查詢和編輯我們的資料函式庫從我們的開發電腦。這對於開發非常有用,因為它給了我們直接與資料函式庫互動和查詢的能力。
更新影片串流媒體微服務以使用資料函式庫
我們已經在 Docker Compose 檔案中增加了環境變數以連線我們的影片串流媒體微服務到其資料函式庫。現在,我們需要更新微服務的程式碼以使用這些環境變數來建立資料函式庫連線。
以下程式碼示範瞭如何更新影片串流媒體微服務以使用資料函式庫:
const express = require("express");
const http = require("http");
const mongodb = require("mongodb");
const PORT = process.env.PORT;
const VIDEO_STORAGE_HOST = process.env.VIDEO_STORAGE_HOST;
const VIDEO_STORAGE_PORT = parseInt(process.env.VIDEO_STORAGE_PORT);
const DBHOST = process.env.DBHOST;
const DBNAME = process.env.DBNAME;
async function main() {
const client = new mongodb.MongoClient(DBHOST, VIDEO_STORAGE_PORT);
const db = client.db(DBNAME);
const app = express();
app.get("/video", async (req, res) => {
const videoId = new mongodb.ObjectId(req.query.id);
const videosCollection = db.collection("videos");
const videoRecord = await videosCollection.findOne({ _id: videoId });
if (!videoRecord) {
res.sendStatus(404);
return;
}
//...
});
}
在這個程式碼中,我們首先載入了 mongodb
函式庫,以便微服務可以連線到其資料函式庫。然後,我們建立了一個到資料函式庫的連線,並建立了一個 Express 應用程式。最後,我們定義了一個路由 /video
,它使用 mongodb
函式庫來查詢資料函式庫並傳回影片記錄。
圖表翻譯:
flowchart TD A[開始] --> B[載入 MongoDB 函式庫] B --> C[建立資料函式庫連線] C --> D[建立 Express 應用程式] D --> E[定義路由] E --> F[查詢資料函式庫] F --> G[傳回影片記錄]
這個圖表展示了微服務如何連線到資料函式庫、建立 Express 應用程式、定義路由、查詢資料函式庫和傳回影片記錄的過程。
微服務的資料函式庫連線與路由設定
在微服務架構中,資料函式庫的連線和路由設定是非常重要的。以下是如何設定微服務的資料函式庫連線和路由設定的範例。
從技術架構視角來看,本文逐步展示瞭如何構建一個根據微服務的影片串流應用程式,涵蓋了個別微服務測試、執行、整合,以及資料函式庫的引入和組態。透過環境變數的設定、Docker Compose 的運用,以及 Node.js 與 MongoDB 的整合,文章清晰地闡述了微服務間的溝通協作和資料管理策略。然而,目前方案僅關注單體資料函式庫,尚未涉及資料函式庫的橫向擴充套件和資料一致性等進階議題,這在高流量、高併發的實際應用場景中將成為潛在瓶頸。此外,錯誤處理和服務降級等機制也需進一步完善,以提升系統的穩定性和容錯能力。展望未來,隨著應用程式規模的擴大,引入服務發現、API 閘道器等元件將有助於簡化服務間的互動和管理複雜性。玄貓認為,逐步完善這些關鍵環節,才能充分釋放微服務架構的潛力,構建更具彈性、可擴充套件的應用程式。