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.mzph.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…