Node.js系列(4)--微服務架構實踐

Node.js微服務架構實踐 🔄

引言

微服務架構已成為構建大規模Node.js應用的主流選擇。本文將深入探討Node.js微服務架構的設計與實現,包括服務拆分、服務治理、通信機制等方面,幫助開發者構建可擴展的微服務系統。

微服務架構概述

Node.js微服務架構主要包括以下方面:

  • 服務拆分:業務領域劃分與服務邊界
  • 服務治理:服務注冊、發現與負載均衡
  • 通信機制:同步與異步通信方案
  • 數據管理:分布式事務與數據一致性
  • 可觀測性:監控、日志與鏈路追蹤

微服務架構實現

服務注冊中心

// 服務注冊中心
class ServiceRegistry {private static instance: ServiceRegistry;private services: Map<string, ServiceInfo[]>;private config: RegistryConfig;private healthChecker: HealthChecker;private constructor() {this.services = new Map();this.config = {checkInterval: 10000,timeoutThreshold: 30000};this.healthChecker = new HealthChecker(this.config);}// 獲取單例實例static getInstance(): ServiceRegistry {if (!ServiceRegistry.instance) {ServiceRegistry.instance = new ServiceRegistry();}return ServiceRegistry.instance;}// 注冊服務registerService(serviceInfo: ServiceInfo): void {const { name, version } = serviceInfo;const key = `${name}@${version}`;if (!this.services.has(key)) {this.services.set(key, []);}this.services.get(key)!.push(serviceInfo);console.log(`Service registered: ${key}`);// 啟動健康檢查this.healthChecker.addService(serviceInfo);}// 注銷服務deregisterService(serviceInfo: ServiceInfo): void {const { name, version } = serviceInfo;const key = `${name}@${version}`;const services = this.services.get(key);if (services) {const index = services.findIndex(s => s.instanceId === serviceInfo.instanceId);if (index !== -1) {services.splice(index, 1);console.log(`Service deregistered: ${key}`);// 停止健康檢查this.healthChecker.removeService(serviceInfo);}}}// 發現服務discoverService(name: string, version: string): ServiceInfo[] {const key = `${name}@${version}`;return this.services.get(key) || [];}// 更新服務狀態updateServiceStatus(serviceInfo: ServiceInfo,status: ServiceStatus): void {const { name, version } = serviceInfo;const key = `${name}@${version}`;const services = this.services.get(key);if (services) {const service = services.find(s => s.instanceId === serviceInfo.instanceId);if (service) {service.status = status;service.lastUpdateTime = Date.now();}}}// 獲取所有服務getAllServices(): Map<string, ServiceInfo[]> {return this.services;}
}// 健康檢查器
class HealthChecker {private config: RegistryConfig;private checkTimer: NodeJS.Timeout | null;private services: Set<ServiceInfo>;constructor(config: RegistryConfig) {this.config = config;this.checkTimer = null;this.services = new Set();}// 添加服務addService(serviceInfo: ServiceInfo): void {this.services.add(serviceInfo);if (!this.checkTimer) {this.startHealthCheck();}}// 移除服務removeService(serviceInfo: ServiceInfo): void {this.services.delete(serviceInfo);if (this.services.size === 0 && this.checkTimer) {this.stopHealthCheck();}}// 啟動健康檢查private startHealthCheck(): void {this.checkTimer = setInterval(() => {this.checkServices();}, this.config.checkInterval);}// 停止健康檢查private stopHealthCheck(): void {if (this.checkTimer) {clearInterval(this.checkTimer);this.checkTimer = null;}}// 檢查服務健康狀態private async checkServices(): Promise<void> {const registry = ServiceRegistry.getInstance();for (const service of this.services) {try {const status = await this.checkServiceHealth(service);registry.updateServiceStatus(service, status);} catch (error) {console.error(`Health check failed for service ${service.name}:`,error);registry.updateServiceStatus(service, 'unhealthy');}}}// 檢查單個服務健康狀態private async checkServiceHealth(service: ServiceInfo): Promise<ServiceStatus> {try {const response = await fetch(`${service.baseUrl}/health`,{timeout: this.config.timeoutThreshold});return response.ok ? 'healthy' : 'unhealthy';} catch (error) {return 'unhealthy';}}
}// 服務發現客戶端
class ServiceDiscoveryClient {private registry: ServiceRegistry;private loadBalancer: LoadBalancer;constructor() {this.registry = ServiceRegistry.getInstance();this.loadBalancer = new LoadBalancer();}// 獲取服務實例async getServiceInstance(name: string,version: string): Promise<ServiceInfo | null> {const services = this.registry.discoverService(name, version);// 過濾健康實例const healthyServices = services.filter(s => s.status === 'healthy');if (healthyServices.length === 0) {return null;}// 使用負載均衡選擇實例return this.loadBalancer.select(healthyServices);}// 調用服務async callService(name: string,version: string,path: string,options: RequestOptions = {}): Promise<any> {const service = await this.getServiceInstance(name, version);if (!service) {throw new Error(`No healthy service instance found: ${name}@${version}`);}try {const response = await fetch(`${service.baseUrl}${path}`,{...options,timeout: options.timeout || 5000});if (!response.ok) {throw new Error(`Service call failed: ${response.statusText}`);}return await response.json();} catch (error) {// 標記服務不健康this.registry.updateServiceStatus(service, 'unhealthy');throw error;}}
}// 負載均衡器
class LoadBalancer {private currentIndex: number;constructor() {this.currentIndex = 0;}// 選擇服務實例select(services: ServiceInfo[]): ServiceInfo {if (services.length === 0) {throw new Error('No services available');}// 輪詢算法const service = services[this.currentIndex];this.currentIndex = (this.currentIndex + 1) % services.length;return service;}
}// 服務網關
class ServiceGateway {private registry: ServiceRegistry;private discoveryClient: ServiceDiscoveryClient;private routeConfig: RouteConfig[];constructor(routeConfig: RouteConfig[]) {this.registry = ServiceRegistry.getInstance();this.discoveryClient = new ServiceDiscoveryClient();this.routeConfig = routeConfig;}// 啟動網關async start(port: number): Promise<void> {const app = express();// 配置中間件app.use(express.json());app.use(this.errorHandler.bind(this));// 注冊路由this.registerRoutes(app);// 啟動服務器app.listen(port, () => {console.log(`Gateway is running on port ${port}`);});}// 注冊路由private registerRoutes(app: express.Application): void {for (const route of this.routeConfig) {app.use(route.path,this.createProxyMiddleware(route));}}// 創建代理中間件private createProxyMiddleware(route: RouteConfig): express.RequestHandler {return async (req, res, next) => {try {const response = await this.discoveryClient.callService(route.service,route.version,req.path,{method: req.method,headers: req.headers as any,body: req.body});res.json(response);} catch (error) {next(error);}};}// 錯誤處理中間件private errorHandler(err: Error,req: express.Request,res: express.Response,next: express.NextFunction): void {console.error('Gateway error:', err);res.status(500).json({error: 'Internal Server Error',message: err.message});}
}// 接口定義
interface ServiceInfo {name: string;version: string;instanceId: string;baseUrl: string;status: ServiceStatus;lastUpdateTime: number;metadata?: Record<string, any>;
}interface RegistryConfig {checkInterval: number;timeoutThreshold: number;
}interface RouteConfig {path: string;service: string;version: string;
}interface RequestOptions extends RequestInit {timeout?: number;
}type ServiceStatus = 'healthy' | 'unhealthy';// 使用示例
async function main() {// 創建服務注冊中心const registry = ServiceRegistry.getInstance();// 注冊服務registry.registerService({name: 'user-service',version: '1.0.0',instanceId: 'user-1',baseUrl: 'http://localhost:3001',status: 'healthy',lastUpdateTime: Date.now()});// 創建服務網關const gateway = new ServiceGateway([{path: '/api/users',service: 'user-service',version: '1.0.0'}]);// 啟動網關await gateway.start(3000);// 創建服務發現客戶端const client = new ServiceDiscoveryClient();// 調用服務try {const result = await client.callService('user-service','1.0.0','/users',{ method: 'GET' });console.log('Service call result:', result);} catch (error) {console.error('Service call failed:', error);}
}main().catch(console.error);

最佳實踐與建議

  1. 服務設計

    • 遵循單一職責原則
    • 合理劃分服務邊界
    • 保持服務獨立性
    • 避免服務耦合
  2. 服務治理

    • 實現服務注冊發現
    • 配置健康檢查
    • 使用負載均衡
    • 實現熔斷降級
  3. 通信機制

    • 選擇合適協議
    • 處理通信異常
    • 實現重試機制
    • 保證消息可靠
  4. 數據管理

    • 實現分布式事務
    • 保證數據一致性
    • 處理并發訪問
    • 優化查詢性能
  5. 可觀測性

    • 收集服務指標
    • 實現鏈路追蹤
    • 聚合服務日志
    • 設置告警規則

總結

Node.js微服務架構需要考慮以下方面:

  1. 服務拆分與治理
  2. 通信機制與數據管理
  3. 監控與可觀測性
  4. 部署與運維支持
  5. 安全與性能優化

通過合理的微服務架構設計,可以提高系統的可擴展性和可維護性。

學習資源

  1. 微服務架構設計
  2. 服務治理實踐
  3. 分布式系統理論
  4. DevOps最佳實踐
  5. 云原生技術棧

如果你覺得這篇文章有幫助,歡迎點贊收藏,也期待在評論區看到你的想法和建議!👇

終身學習,共同成長。

咱們下一期見

💻

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/898719.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/898719.shtml
英文地址,請注明出處:http://en.pswp.cn/news/898719.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Docker逃逸

判斷是否再docker中 1.ls -a / (查看c根目錄查看是否有docker配置文件) 2.查看進程 如果在要逃逸到真實環境中&#xff1a; 特權模式進行docker逃逸&#xff1a;管理員執行eddocker run--privileg&#xff0c;如何判斷是否是特權模式&#xff08;&#xff09; 特權模式以…

Vite管理的Vue3項目中monaco editer的使用以及組件封裝

文章目錄 背景環境說明安裝流程以及組件封裝引入依賴封裝組件 外部使用實現效果 v-model實現原理 背景 做oj系統的時候,需要使用代碼編輯器,決定使用Monaco Editor&#xff0c;但是因為自身能力問題&#xff0c;讀不懂官網文檔&#xff0c;最終結合ai和網友的帖子成功引入&…

pdf文件分頁按需查看

pdf預覽本來打算粗暴點&#xff0c;一次性查看全部&#xff0c;但是一個pdf四五百頁導致手機端查看超出內存直接崩掉&#xff0c;崩掉會導致頁面瘋狂刷新&#xff0c;所以不得不進行優化 解決思路大致如下&#xff1a; canvas轉為blob格式以圖片的形式加載在頁面&#xff08;B…

算力100問?第92問:為什么各地熱衷建設算力中心?

目錄 1、宏觀分析 2、政府角度分析 3、投資者角度分析 在數字化浪潮中,各地對算力中心建設的熱情高漲,這一現象背后潛藏著諸多深層次的原因,涵蓋了經濟、科技、社會等多個維度,且彼此交織,共同驅動著這一發展趨勢。 1、宏觀分析 從經濟結構轉型的底層邏輯來看,全球經…

Redis 內存管理

Redis 內存管理 1. Redis 給緩存數據設置過期時間的作用 給緩存數據設置過期時間&#xff08;TTL, Time-To-Live&#xff09;有以下幾個重要作用&#xff1a; (1) 自動釋放內存 避免緩存數據無限增長&#xff0c;導致 Redis 內存溢出。例如&#xff0c;在 會話管理、短連接…

PyCharm中使用pip安裝PyTorch(從0開始僅需兩步)

無需 anaconda&#xff0c;只使用 pip 也可以在 PyCharm 集成環境中配置深度學習 PyTorch。 本文全部信息及示范來自 PyTorch 官網。 以防你是super小白&#xff1a; PyCharm 中的命令是在 Python Console 中運行&#xff0c;界面左下角豎排圖標第一個。 1. 安裝前置包 numpy …

掌握新編程語言的秘訣:利用 AI 快速上手 Python、Go、Java 和 Rust

網羅開發 &#xff08;小紅書、快手、視頻號同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企業從事人工智能項目研發管理工作&#xff0c;平時熱衷于分享各種編程領域的軟硬技能知識以及前沿技術&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…

如何理解java中Stream流?

在Java中&#xff0c;Stream 是 Java 8 引入的一個強大API&#xff0c;用于處理集合&#xff08;如 List、Set、Map 等&#xff09;數據的流式操作。它提供了一種聲明式、函數式的編程風格&#xff0c;可以高效地進行過濾、映射、排序、聚合等操作。 Stream 的核心概念 流&…

【Vitis AIE】FPGA快速部署ConvNet 示例MNIST數據集

AIE-ML 上的 MNIST ConvNet 版本&#xff1a;Vitis 2024.2 簡介 本教程在 AMD VersalTM 自適應 SoC AIE-ML 上實現了一個卷積神經網絡分類器&#xff0c;用于識別來自 MNIST 數據庫 的手寫數字。目標是說明如何將一個簡單的機器學習示例分區和向量化到 Versal AI 引擎。MNIS…

ubuntu桌面圖標異常——主目錄下的所有文件(如文檔、下載等)全部顯示在桌面

ubuntu桌面圖標異常 問題現象問題根源系統級解決方案方法一:全局修改(推薦多用戶環境)方法二:單用戶修改(推薦個人環境)操作驗證與調試避坑指南擴展知識參考文檔問題現象 主目錄文件異常顯示 用戶主目錄(如/home/user/)下的所有文件(如文檔、下載等)全部顯示在桌面,…

OceanBase 4.3.3 AP 解析:應用 RoaringBitmaps 類型處理海量數據的判重和基數統計

對于大數據開發人員而言&#xff0c;處理海量數據的判重操作和基數統計是常見需求&#xff0c;而 RoaringBitmap類型及其相關函數是當前非常高效的一種解決方案&#xff0c;許多大數據庫產品已支持RoaringBitmap類型。OceanBase 4.3.3版本&#xff0c;作為專為OLAP場景設計的正…

W25Qxx

概述 FLASH FLASH是一種是非易失性存儲器&#xff0c;即掉電后不會丟失數據&#xff0c;這和RAM&#xff08;隨機存儲器&#xff09;不同。 FLASH比起同作用的EEPROM有價格低的優點 FLASH的擦除操作是以扇區為單位的&#xff08;比起EEPROM來說操作較為不方便&#xff09; 芯片…

(滑動窗口)算法訓練篇11--力扣3.無重復字符的最長字串(難度中等)

目錄 1.題目鏈接&#xff1a;3.無重復字符的最長字符 2.題目描述&#xff1a; 3.解法(滑動窗口)&#xff1a; 1.題目鏈接&#xff1a;3.無重復字符的最長字符 2.題目描述&#xff1a; 給定一個字符串 s &#xff0c;請你找出其中不含有重復字符的 最長 子串 的長度。 示例…

深度學習1—Python基礎

深度學習1—python基礎 你的第一個程序 print(hello world and hello deep learning!)基本數據結構 空值 (None)&#xff1a;在 Python 中&#xff0c;None 是一個特殊的對象&#xff0c;用于表示空值或缺失的值。它不同于數字 0&#xff0c;因為 0 是一個有意義的數字&#…

記一次MyBatis分頁莫名其妙的失效,首次執行合適,后續執行分頁失效且異常

代碼幾乎一樣&#xff0c;為啥這個xml配置的就會出現莫名其妙的問題呢 org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{propertymybatis_plus_first, modeI…

網絡不可達

導致此問題原因較多&#xff0c;我只針對一種情況進行討論&#xff0c;如果和文中癥狀不同&#xff0c;另尋他處&#xff0c;或者死馬當活馬醫&#xff08;&#xff1f;&#xff09; 如需轉載&#xff0c;標記出處 癥狀&#xff1a; 1.ping命令網絡不可達 2.ifconfig中網卡en…

【AI News | 20250322】每日AI進展

AI Repos 1、DeTikZify 可以把草圖或圖形轉換成TikZ代碼的模型&#xff0c;可用來繪制復雜的科學圖表&#xff0c;輸入草圖或文字描述即可轉換成TikZ代碼。DeTikZify強大的地方在于它能理解圖表的語義信息&#xff0c; 能識別圖表中的不同組成部分及其含義&#xff0c;比如坐標…

Debian12生產環境配置筆記

在 Debian 12 上進行生產環境配置的詳細步驟&#xff0c;涵蓋軟件更新、基礎軟件安裝、Docker 及 Redis 部署&#xff0c;以及 Nginx 配置多個虛擬主機等內容。所有命令均以 root 用戶身份執行&#xff0c;無需添加 sudo 1. 更新軟件 首先&#xff0c;確保系統上的所有軟件包…

UE AI 模型自動生成導入場景中

打開小馬的weix 關注下 搜索“技術鏈” 回復《《動畫》》 快速推送&#xff1b; 拿到就能用輕松解決&#xff01;幫忙點個關注吧&#xff01;

【最后203篇系列】022 用Deepseek14b提取新聞事件

這算是之前一直想做的一件事&#xff0c;趁周末趕快做了。 業務意義&#xff1a;現實中有大量的輿情&#xff0c;這對我們的決策會有比較重要的作用 技術依賴&#xff1a; 1 模型基礎能力2 消息隊列3 異步獲取消息4 時間序列庫 1 模型基礎能力 大模型發展到現在&#xff0…