在微服務架構中,每個微服務都需妥善管理自身的資料函式庫連線、API 路由和外部服務請求轉發。本文以 Node.js 和 Express 為例,示範如何設定資料函式庫連線、設計路由,以及轉發請求。首先,使用 db.connect()
建立與 MongoDB 的連線,並設定主機、連線埠、資料函式庫名稱和認證資訊。接著,利用 app.get()
等方法定義 API 路由,處理來自使用者端的 HTTP 請求,例如取得影片資料。此外,使用 http.request()
可以轉發請求到其他服務,例如影片儲存服務。在 Docker Compose 環境中,可以設定 MongoDB 服務,並透過環境變數將連線資訊傳遞給微服務。為了測試,可以使用 Studio 3T 等工具載入測試資料。最後,在生產環境中,務必設定適當的安全組態,例如 SSL/TLS 加密和防火牆規則,以確保資料函式庫的安全性和可靠性,並考量使用分散式資料函式庫或多個資料函式庫例項來提升高用性和擴充套件性。
資料函式庫連線設定
首先,需要設定微服務的資料函式庫連線。這可以透過設定資料函式庫的名稱、主機、連線埠和認證訊息來完成。例如:
const db = require('./db');
db.connect({
host: 'localhost',
port: 27017,
database: 'mydatabase',
user: 'myuser',
password: 'mypassword'
});
路由設定
接下來,需要設定微服務的路由。路由是用於處理HTTP請求的。例如,可以設定一個GET路由來查詢影片資料:
const express = require('express');
const app = express();
app.get('/video', async (req, res) => {
const videoId = req.query.videoId;
const video = await db.collection('videos').findOne({ _id: videoId });
if (!video) {
res.status(404).send('影片不存在');
} else {
res.send(video);
}
});
轉發請求
在某些情況下,需要轉發請求到其他服務。例如,可以使用http.request
方法來轉發請求:
const http = require('http');
const forwardRequest = http.request({
host: 'video-storage-host',
port: 8080,
path: `/video?path=${videoRecord.videoPath}`,
method: 'GET',
headers: req.headers
}, (forwardResponse) => {
res.writeHeader(forwardResponse.statusCode, forwardResponse.headers);
forwardResponse.pipe(res);
});
req.pipe(forwardRequest);
啟動服務
最後,需要啟動微服務。可以使用app.listen
方法來啟動服務:
app.listen(PORT, () => {
console.log(`服務啟動於連線埠${PORT}`);
});
完整範例
以下是完整的範例:
const express = require('express');
const app = express();
const db = require('./db');
db.connect({
host: 'localhost',
port: 27017,
database: 'mydatabase',
user: 'myuser',
password: 'mypassword'
});
app.get('/video', async (req, res) => {
const videoId = req.query.videoId;
const video = await db.collection('videos').findOne({ _id: videoId });
if (!video) {
res.status(404).send('影片不存在');
} else {
res.send(video);
}
});
const http = require('http');
const forwardRequest = http.request({
host: 'video-storage-host',
port: 8080,
path: `/video?path=${videoRecord.videoPath}`,
method: 'GET',
headers: req.headers
}, (forwardResponse) => {
res.writeHeader(forwardResponse.statusCode, forwardResponse.headers);
forwardResponse.pipe(res);
});
req.pipe(forwardRequest);
app.listen(PORT, () => {
console.log(`服務啟動於連線埠${PORT}`);
});
這個範例示範瞭如何設定微服務的資料函式庫連線、路由設定和轉發請求。
微服務資料管理
在微服務架構中,資料管理是一個至關重要的方面。每個微服務都需要存取和管理自己的資料,但也需要與其他微服務分享資料。這就需要一個統一的資料管理機制,以確保資料的一致性和完整性。
增加資料函式庫
為了實作資料管理,我們需要增加一個資料函式庫到我們的應用程式中。在這個例子中,我們使用 MongoDB 作為資料函式庫。首先,我們需要在 Docker Compose 檔案中增加 MongoDB 服務。
version: '3'
services:
video-streaming:
build:.
ports:
- "3000:3000"
depends_on:
- mongo
environment:
- DATABASE_URL=mongodb://mongo:27017/video-streaming
mongo:
image: mongo:4.4.3
ports:
- "4000:27017"
然後,我們需要更新 video-streaming 微服務以使用 MongoDB 資料函式庫。
const mongoose = require('mongoose');
mongoose.connect('mongodb://mongo:27017/video-streaming', { useNewUrlParser: true, useUnifiedTopology: true });
const videoSchema = new mongoose.Schema({
videoPath: String
});
const Video = mongoose.model('Video', videoSchema);
載入測試資料
為了測試我們的應用程式,我們需要載入一些測試資料到資料函式庫中。我們可以使用 Studio 3T 這個工具來載入資料。
{
"_id" : { "$oid": "5d9e690ad76fe06a3d7ae416" },
"videoPath" : "SampleVideo_1280x720_1mb.mp4"
}
測試應用程式
現在,我們可以測試我們的應用程式了。首先,我們需要啟動應用程式。
cd chapter-4/example-3
docker compose up --build
然後,我們可以使用瀏覽器來存取應用程式,並提供影片 ID 來播放影片。
生產環境中的資料函式庫
在生產環境中,我們需要確保資料函式庫的安全性和可靠性。這包括設定適當的安全組態,例如使用 SSL/TLS 加密和設定防火牆規則。
此外,我們需要確保資料函式庫的高用性和擴充套件性。這可以透過使用分散式資料函式庫或設定多個資料函式庫例項來實作。
微服務資料管理
在微服務架構中,資料管理是一個非常重要的方面。每個微服務都需要管理自己的資料,並且需要與其他微服務進行通訊以實作業務邏輯。在本章中,我們將討論如何使用 Docker Compose 管理微服務的資料,並且如何使用 MongoDB 作為資料函式庫。
增加資料函式庫
首先,我們需要增加一個資料函式庫到我們的應用程式中。這裡,我們使用 MongoDB 作為資料函式庫。使用 Docker Compose,可以很容易地增加一個 MongoDB 資料函式庫到我們的應用程式中。
version: '3'
services:
video-streaming:
build:.
ports:
- "8080:8080"
depends_on:
- mongo
environment:
- DATABASE_URL=mongodb://mongo:27017/video-streaming
mongo:
image: mongo:4.4.3
volumes:
- mongo-data:/data/db
volumes:
mongo-data:
在上面的 Docker Compose 組態檔案中,我們定義了兩個服務:video-streaming
和 mongo
。video-streaming
服務依賴於 mongo
服務,並且使用 DATABASE_URL
環境變數連線到 MongoDB 資料函式庫。
微服務之間的通訊
在微服務架構中,各個微服務之間需要進行通訊以實作業務邏輯。這裡,我們使用 HTTP 請求進行通訊。例如,video-streaming
微服務可以向 video-storage
微服務傳送 HTTP 請求,以取得影片檔案。
sequenceDiagram participant video-streaming participant video-storage video-streaming->>video-storage: HTTP GET /videos video-storage->>video-streaming: 傳回影片檔案
在上面的序列圖中,video-streaming
微服務向 video-storage
微服務傳送 HTTP GET 請求,以取得影片檔案。video-storage
微服務傳回影片檔案給 video-streaming
微服務。
資料函式庫設計
在設計資料函式庫時,我們需要考慮到各個微服務之間的關係,並且需要確保資料的一致性。這裡,我們使用 MongoDB 作為資料函式庫,並且使用集合(collection)來儲存資料。
{
"_id" : ObjectId("..."),
"name" : "影片檔案",
"url" : "https://example.com/video.mp4"
}
在上面的 JSON 檔案中,我們定義了一個集合,包含 _id
、name
和 url
三個欄位。這個集合可以用來儲存影片檔案的元資料。
圖表翻譯:
下面是本章中使用的 Mermaid 圖表:
sequenceDiagram participant video-streaming participant video-storage video-streaming->>video-storage: HTTP GET /videos video-storage->>video-streaming: 傳回影片檔案
這個圖表展示了 video-streaming
微服務和 video-storage
微服務之間的通訊過程。video-streaming
微服務向 video-storage
微服務傳送 HTTP GET 請求,以取得影片檔案。video-storage
微服務傳回影片檔案給 video-streaming
微服務。
內容解密:
在本章中,我們使用了 Docker Compose 和 MongoDB 來實作微服務的資料管理。Docker Compose 可以幫助我們管理多個容器,並且可以簡化微服務之間的通訊。MongoDB 是一個 NoSQL 資料函式庫,可以用來儲存和管理大量的資料。
透過這些知識,可以幫助您更好地設計和實作微服務架構的資料管理。同時,也可以幫助您瞭解如何使用 Docker Compose 和 MongoDB 來簡化微服務的開發和佈署。
結束和清除應用程式
當您完成了應用程式的開發和測試,想要將其停止並清除所有相關資源時,可以使用 docker compose down
命令。這個命令會停止並刪除所有由 docker-compose up
啟動的容器、網路和卷,讓您的開發環境還原到原始狀態。
開發環境
在開發過程中,您的電腦上可能會有多個容器和服務在執行。使用 docker compose down
可以確保所有不再需要的資源被適當地清除,避免資源浪費和混亂。
Docker Compose
Docker Compose 是一個用於定義和執行多容器 Docker 應用程式的工具。透過編寫 docker-compose.yml
檔案,您可以輕鬆地組態和管理複雜的微服務架構。
啟動應用程式
要啟動您的應用程式,請使用 docker-compose up --build
命令。這個命令不僅會啟動您的微服務,還會在必要時重新建構映像檔,確保您的應用程式始終是最新的。
微服務架構
微服務是一種軟體開發技術,將應用程式分解為多個小型、獨立的服務。每個服務負責一部分功能,並透過 API 或訊息佇列等機制進行通訊。這種架構可以提高開發效率、擴充套件性和容錯性。
執行命令
docker-compose up --build
: 啟動並建構您的應用程式。docker compose down
: 停止並清除您的應用程式。
圖表翻譯:
flowchart TD A[啟動應用程式] --> B[建構映像檔] B --> C[啟動容器] C --> D[微服務執行] D --> E[停止並清除] E --> F[環境還原]
圖表說明:
- 啟動應用程式:使用
docker-compose up --build
啟動您的微服務應用程式。 - 建構映像檔:如果必要,重新建構映像檔以確保應用程式是最新的。
- 啟動容器:啟動容器並執行您的微服務。
- 微服務執行:您的微服務現在正在容器中執行。
- 停止並清除:使用
docker compose down
停止並清除所有相關資源。 - 環境還原:您的開發環境現在還原到原始狀態,所有不再需要的資源被清除。
微服務之間的溝通
在微服務架構中,多個微服務之間的溝通是實作複雜行為和功能的關鍵。每個微服務負責自己的領域,簡單且功能單一,因此需要彼此之間進行溝通,以實作應用程式的功能。
本章將探討微服務之間溝通的不同方式,包括使用 HTTP 請求進行直接訊息傳遞、使用 RabbitMQ 進行間接訊息傳遞,以及如何選擇使用直接或間接訊息傳遞。
直接訊息傳遞
直接訊息傳遞是指兩個微服務之間直接進行 HTTP 請求,以實作溝通。這種方式簡單易行,但可能會導致微服務之間的耦合度增加。
使用 HTTP 請求進行直接訊息傳遞
在之前的章節中,我們已經看到過 HTTP 請求可以用於微服務之間的溝通。在本章中,我們將進一步探討使用 HTTP 請求進行直接訊息傳遞的方法。
間接訊息傳遞
間接訊息傳遞是指微服務之間不直接進行溝通,而是透過一個中介軟體(如 RabbitMQ)進行訊息傳遞。這種方式可以減少微服務之間的耦合度,提高系統的可擴充套件性和可維護性。
使用 RabbitMQ 進行間接訊息傳遞
RabbitMQ 是一個流行的訊息佇列系統,可以用於微服務之間的間接訊息傳遞。在本章中,我們將探討如何使用 RabbitMQ 進行間接訊息傳遞。
選擇訊息傳遞方式
在選擇訊息傳遞方式時,需要考慮微服務之間的耦合度、系統的可擴充套件性和可維護性等因素。直接訊息傳遞簡單易行,但可能會導致微服務之間的耦合度增加;間接訊息傳遞可以減少耦合度,但可能會增加系統的複雜性。
使用 Live Reload 進行應用程式級別的快速迭代
在開發微服務應用程式時,需要頻繁地更新和重啟應用程式,以實作快速迭代。Live Reload 是一個可以用於實作應用程式級別快速迭代的工具。在本章中,我們將探討如何使用 Live Reload 進行應用程式級別的快速迭代。
5.1 新工具和熟悉工具
本章介紹了 RabbitMQ 這個用於佇列訊息的軟體,幫助我們解耦微服務。我們將使用名為 amqplib 的 npm 套件來連線微服務到 RabbitMQ,以便它們可以傳送和接收訊息。同時,我們也會重新審視一些熟悉的工具,並更詳細地探討如何使用 HTTP 請求傳送訊息和升級開發環境以支援應用程式範圍內的即時重新載入。表 5.1 顯示了本章介紹的工具清單。
5.2 取得程式碼
若要跟隨本章的內容,您需要下載程式碼或使用 Git 克隆儲存函式庫,如下所示:
git clone <儲存函式庫位址>
如需 Git 安裝和使用的幫助,請參考第 2 章。如果您遇到程式碼問題,請在 GitHub 對儲存函式庫提出問題。 表 5.1 本章介紹的新工具和熟悉工具
工具 | 版本 | 目的 |
---|---|---|
Docker Compose | 24.0.5 | 讓我們可以組態、建構、執行和管理多個容器。 |
HTTP | 1.1 | 用於從一個微服務傳送直接(或同步)訊息到另一個微服務。 |
RabbitMQ | 3.12.4 | RabbitMQ 是我們用於傳送間接(或非同步)訊息從一個微服務到另一個微服務的訊息佇列軟體。 |
amqplib | 0.10.3 | 這個 npm 套件允許我們組態 RabbitMQ 和從 JavaScript 傳送和接收訊息。 |
5.3 讓微服務溝通
在本章的這個階段,我們有一個具有兩個微服務(視訊串流和視訊儲存)的應用程式。在前一章中,我們增加了資料儲存功能,因此現在視訊串流微服務具有資料函式庫,而視訊儲存微服務使用外部雲端儲存來儲存視訊檔案。圖 5.1 顯示了我們的應用程式目前的狀態。 微服務應用程式是由合作提供應用程式功能的服務所建構。若我們的微服務無法溝通,則我們的應用程式無法做太多事情!因此,微服務之間的溝通是建構微服務的關鍵部分,我們必須掌握溝通技巧。事實上,我們在第 4 章中已經使用 HTTP 請求進行視訊串流和視訊儲存微服務之間的溝通,雖然當時我們沒有深入探討,但這非常重要。沒有它,我們就會在第一道門檻上跌倒:將串流和儲存功能分離出來。
注意:我們的微服務必須合作以實作應用程式的功能,因此,它們之間的溝通以便合作是至關重要的。 在本章中,我們將向應用程式增加第三個微服務:歷史微服務。增加這個新微服務的目的是示範微服務之間的溝通。你可以在圖 5.2 中看到視訊串流微服務正在向歷史微服務傳送一串訊息。 圖 5.2 概念性地顯示了本章結束時我們的應用程式的狀態,但它並沒有顯示我們將增加的完整技術細節。為了獲得完整的圖景,我們需要了解不同風格的溝通以及…
內容解密:
上述內容介紹了 RabbitMQ 和 amqplib 的使用,以實作微服務之間的溝通。RabbitMQ 是一個訊息佇列軟體,允許我們傳送間接(或非同步)訊息,而 amqplib 是一個 npm 套件,允許我們從 JavaScript 組態 RabbitMQ 和傳送及接收訊息。
圖表翻譯:
graph LR A[視訊串流微服務] -->|傳送訊息|> B[歷史微服務] B -->|儲存歷史|> C[資料函式庫] C -->|傳回結果|> A
這個圖表顯示了視訊串流微服務向歷史微服務傳送訊息,歷史微服務然後儲存這些訊息到資料函式庫,並傳回結果給視訊串流微服務。
微服務之間的溝通
在前一章中,我們使用Docker Compose建立了兩個微服務和一個資料函式庫,同時也將外部雲端儲存整合到系統中。現在,我們將探討微服務之間的溝通方式。
歷史微服務簡介
為了示範微服務之間的溝通,我們引入了一個新的微服務:歷史微服務(history microservice)。這個微服務負責記錄使用者的觀看歷史。使用者可以檢視自己的觀看歷史,以便記住之前觀看過的影片或繼續觀看之前的影片。此外,我們也可以使用觀看歷史來為其他使用者提供影片推薦。
為了簡化示範,我們將暫時移除前一章中的影片儲存微服務(video-storage microservice),並還原影片串流微服務(video-streaming microservice)到第三章的版本。這個簡化只在本章中有效,之後我們將重新引入影片儲存微服務。
微服務之間的訊息傳遞
歷史微服務接收來自影片串流微服務的訊息串流,並將其記錄在自己的資料函式庫中。這個過程如圖5.3所示。影片串流微服務傳送「已觀看」(Viewed)訊息給歷史微服務,以通知其使用者已觀看了一個影片。
flowchart TD A[影片串流微服務] -->|傳送已觀看訊息|> B[歷史微服務] B -->|記錄觀看歷史|> C[資料函式庫]
內容解密:
A[影片串流微服務]
:負責串流影片給使用者的微服務。B[歷史微服務]
:負責記錄使用者觀看歷史的微服務。C[資料函式庫]
:歷史微服務用來儲存觀看歷史的資料函式庫。傳送已觀看訊息
:當使用者觀看一個影片時,影片串流微服務傳送「已觀看」訊息給歷史微服務。記錄觀看歷史
:歷史微服務接收到「已觀看」訊息後,將其記錄在自己的資料函式庫中。
圖表翻譯:
圖5.3展示了影片串流微服務和歷史微服務之間的溝透過程。當使用者觀看一個影片時,影片串流微服務傳送「已觀看」訊息給歷史微服務。歷史微服務接收到這個訊息後,將其記錄在自己的資料函式庫中。這個過程示範了微服務之間如何透過訊息傳遞來實作溝通和資料分享。
在下一節中,我們將更深入地探討微服務之間的溝通方式,包括不同型別的訊息傳遞和資料分享機制。
微服務之間的溝通:實作即時多載和訊息傳遞
在前面的章節中,我們建立了多個微服務,並使用Docker Compose來管理和啟動這些服務。然而,在過渡到使用Docker容器的過程中,我們失去了對程式碼的即時多載功能。這對於開發過程來說是一個巨大的瓶頸,因為我們需要不斷地重建映象和重新啟動應用程式來包含更新的程式碼。
為瞭解決這個問題,我們將升級Docker Compose檔案,以支援在開發電腦和容器之間分享程式碼。這樣,我們就可以使用nodemon來實作即時多載功能,當程式碼發生變化時,微服務將自動重啟。
實作即時多載
首先,我們需要修改Docker Compose檔案,以便將程式碼目錄從開發電腦分享到容器中。這樣,我們就可以在不需要重建映象的情況下更新程式碼。
version: '3'
services:
video-streaming:
build:./video-streaming
volumes:
-./video-streaming:/app
ports:
- "3000:3000"
depends_on:
- history
history:
build:./history
volumes:
-./history:/app
ports:
- "3001:3001"
接下來,我們需要在每個微服務中使用nodemon來實作即時多載功能。nodemon是一個可以自動重啟應用程式的工具,當程式碼發生變化時。
// video-streaming/index.js
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
// history/index.js
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3001, () => {
console.log('Server started on port 3001');
});
微服務之間的溝通
現在,我們已經實作了即時多載功能,讓我們來探討一下微服務之間的溝通問題。為了示範微服務之間的溝通,我們將建立一個新的微服務,稱為「歷史記錄」微服務,這個微服務將負責記錄使用者觀看影片的歷史。
當使用者觀看影片時,影片串流媒體微服務將傳送一個「已觀看」訊息給歷史記錄微服務,歷史記錄微服務將記錄下使用者觀看的影片。
sequenceDiagram participant VideoStreaming as "影片串流媒體" participant History as "歷史記錄" VideoStreaming->>History: 已觀看訊息 History->>History: 記錄使用者觀看歷史
內容解密:
- 我們使用Docker Compose來管理和啟動多個微服務。
- 我們使用nodemon來實作即時多載功能,當程式碼發生變化時,微服務將自動重啟。
- 我們建立了一個新的微服務,稱為「歷史記錄」微服務,負責記錄使用者觀看影片的歷史。
- 影片串流媒體微服務傳送一個「已觀看」訊息給歷史記錄微服務,歷史記錄微服務將記錄下使用者觀看的影片。
圖表翻譯:
- 圖表展示了影片串流媒體微服務和歷史記錄微服務之間的溝透過程。
- 當使用者觀看影片時,影片串流媒體微服務傳送一個「已觀看」訊息給歷史記錄微服務。
- 歷史記錄微服務接收到「已觀看」訊息後,將記錄下使用者觀看的影片。
從技術架構視角來看,本文介紹了微服務間的通訊方式,涵蓋了直接使用 HTTP 請求與間接利用 RabbitMQ 進行訊息傳遞的兩種模式。分析比較兩種方式,直接通訊的優勢在於簡潔易用,但服務間耦合度較高;而間接通訊透過訊息佇列解耦,提升了系統彈性與可維護性,但也增加了系統複雜度。技術限制方面,HTTP 請求的同步特性可能影響效能,而 RabbitMQ 的引入則需考量訊息可靠性與一致性等議題。實務上,應根據業務場景選擇合適的通訊模式,例如,對於即時性要求高的操作,HTTP 請求更為直接有效;而對於非同步處理的任務,RabbitMQ 則更具優勢。展望未來,隨著 Service Mesh 技術的發展,微服務間的通訊管理將更加便捷和高效,預期會出現更多創新的通訊模式和解決方案。玄貓認為,開發者應深入理解不同通訊模式的特性,並結合實際需求進行技術選型,才能構建出高效、可靠且易於維護的微服務架構。