Nestjs 微服务实战 - 动态微服务创建链接
所有的微服务都需要做服务治理
服务治理包括(配置中心、服务发现、注册服务等等),常见的包括 Java 的 Nacos,这里不关注与服务治理,只说明,如何用 nest 网关,并且在网关层动态实现微服务注入
nestjs 官网的案例明显是偏向于手动注册微服务的,例如:
/** Model */
@Module({imports: [/** Model 中使用并注册 */ ClientsModule.register([{ name: 'MATH_SERVICE', transport: Transport.TCP },]),]...
});/** service / controller 使用 */
constructor(/** 通过 @Inject 装饰器只能挨个进行倒入,有多少服务倒入多少 */@Inject('MATH_SERVICE') private client: ClientProxy,
) {}
以上属于官网列出的例子,对于真正的微服务开发肯定是不够用的,因为服务并没有根据配置中心的配置进行动态变更倒入,这种情况下,假如某个服务很占用 CPU、内存导致荡机了,也无法进行动态扩展,只能去重启服务手动更改配置,而我需要的是完全动态,每个服务部署都独立部署出来,对于高CPU的服务进行动态扩展服务器,进行自动切换 ip 端口线路。
首先所有的服务都不要在 Model 中进行注册,建议全丢在 service / controller 中使用,我这里以 controller 为例:
import { All, Controller, Req, Res } from '@nestjs/common';
import { ClientProxyFactory, Transport } from '@nestjs/microservices';
import { createProxyServer } from 'http-proxy';/** 动态数组,这里后面要通过定时任务去配置中心拉取 */
const serviceList = [{name: 'user-center',host: '127.0.0.1',port: 65531,},
];@Controller()
export class AppController {/** 首先所有路由不管任何请求方式全部代理到这个方法上 */@All('*')async root(@Req() req, @Res() res): Promise<any> {/** 获取所有可获取的参数 */const { method, originalUrl, query, body, headers } = req;/** 根据 url 字符串切割一下获取,主要获取第一级和第二级路由 */const list = originalUrl.split('?')[0].split('/').filter((item: string) => item !== '');/** 所有,开头为 /api 的参数,并且路由大于并且等于 2 级以上的,基本都可以调用微服务 */if (list.length >= 2 && list[0] === 'api') {/** 微服务真正的地址,是三级路径 */const path = `/${list.slice(2).join('/')}`;/** 服务名称是二级目录 */const service = list[1];/** 查找服务名称是否存在 */const server = serviceList.find((item) => item.name === service);/** 服务存在 */if (server) {/** 错误执行 */const errorNext = (err: string) => {/** 地址错误 */if (err === 'There is no matching message handler defined in the remote service.') {/** 手动关闭服务链接 */this[service].close();/** 清楚链接,下次链接如果服务可用就触发重新链接 */this[service] = undefined;res.status(404);res.send({code: -1,msg: '地址错误',});} else {console.log(`其他错误: ${err}`);}};/** 当前 class 中找不到服务,需要创建服务 */if (!this[service]) {/** 动态创建服务链接 */this[service] = ClientProxyFactory.create({transport: Transport.TCP,options: {host: server.host,port: server.port,},});try {/** 链接服务 */await this[service].connect();/** 发送消息*/const data = this[service].send(/** 服务的接口地址是 { method = 请求方法, path = 等于相对路径 } */{ method, path },/** 把所有 http 的参数全部传递过去,让那边服务自己判断处理 */{ query, body, headers },);/** 接受流消息 */data.subscribe({/** 成功执行 next */next: (_res_: any) => {res.status(200);res.send(_res_);},/** 失败吧错误信息丢个 errorNext */error: (err: any) => errorNext(err),});} /** 服务存在,但是可能荡机了,又或者服务正在重启过程中 */ catch (err) {/** 手动关闭服务链接 */this[service].close();/** 清楚链接,下次链接如果服务可用就触发重新链接 */this[service] = undefined;res.status(503);res.send({code: -1,msg: '当前服务正在维护中',});}} /** 服务已存在 */ else {/** 发送消息*/const data = this[service].send(/** 服务的接口地址是 { method = 请求方法, path = 等于相对路径 } */{ method, path },/** 把所有 http 的参数全部传递过去,让那边服务自己判断处理 */{ query, body, headers },);/** 接受流消息 */data.subscribe({/** 成功执行 next */next: (_res_: any) => {res.status(200);res.send(_res_);},/** 失败吧错误信息丢个 errorNext */error: (err: any) => errorNext(err),});}} /** 未找到服务 */ else {res.status(404);res.send({code: -1,msg: '未找到对应的服务',});}} /** 反向代理到 admin 地址 */ else if (list.length >= 2 && list[0] === 'admin') {const proxy = createProxyServer({target: 'http://127.0.0.1:4000',changeOrigin: true,});proxy.on('error', () => {res.status(503);res.send({code: -1,msg: '当前服务正在维护中',});});proxy.web(req, res);} /** 反向代理到 nuxt ssr 前端页面地址 */ else {const proxy = createProxyServer({target: 'http://127.0.0.1:5000',changeOrigin: true,});proxy.on('error', () => {res.status(503);res.send({code: -1,msg: '当前服务正在维护中',});});proxy.web(req, res);}}
}
以上是我的核心逻辑部分,主要逻辑应该是一下步骤,
/** 1、创建服务 */
const proxy = ClientProxyFactory.create({transport: Transport.TCP,options: {host: '127.0.0.1',port: 65531,},
});/** 2、服务连接 */
await proxy.connect();/** 3、发送消息 */
const data = this[service].send(消息接口,附加数据,
);/** 4、接受流消息 */
data.subscribe({/** 成功消息 */next: (_res_: any) => {res.status(200);res.send(_res_);},/** 排错 */error: (err: any) => {},
});
相关文章:
Nestjs 微服务实战 - 动态微服务创建链接
所有的微服务都需要做服务治理 服务治理包括(配置中心、服务发现、注册服务等等),常见的包括 Java 的 Nacos,这里不关注与服务治理,只说明,如何用 nest 网关,并且在网关层动态实现微服务注入 …...

K8S部署pod状态CreateContainerConfigError问题解决
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
PyTorch 简单易懂的实现 CosineSimilarity 和 PairwiseDistance - 距离度量的操作
目录 torch.nn子模块Distance Functions解析 nn.CosineSimilarity 功能 主要参数 输入和输出的形状 使用示例 nn.PairwiseDistance 功能 主要参数 输入和输出的形状 使用示例 总结 torch.nn子模块Distance Functions解析 nn.CosineSimilarity torc…...
app加载不到aar中的so库
如何将so文件打入到aar包中 1 在main下面新建jniLibs目录并将so放进去 2 在android{}中添加 sourceSets {main {jniLibs.srcDir file(jni/)}}app引用不到aar中的so文件(巨坑,不去查谁知道啊) 在aar 的manifeset application标签中中添加 android:extractNativeLi…...

vue-springboot基于java的实验室安全考试系统
本系统为用户而设计制作实验室安全考试系统,旨在实现实验室安全考试智能化、现代化管理。本实验室安全考试管理自动化系统的开发和研制的最终目的是将实验室安全考试的运作模式从手工记录数据转变为网络信息查询管理,从而为现代管理人员的使用提供更多的…...

mysql+关掉密码过期
mysql关掉密码过期 要在MySQL中关闭密码过期功能,可以按照以下步骤进行操作: 登录到MySQL服务器。 使用管理员账户(如root)连接到数据库。 mysql -uroot -ppassword 运行以下命令来查看当前的密码过期设置: SHOW…...
实际项目中的环形缓冲区
在实际项目中,环形缓冲区的设计要比之前讲到的原型稍微复杂一些,需要一些接口函数来实现数据结构封装。GitHub上有个大帅哥写了一个轻量的环形缓冲区库,可以学习参考,也可以直接集成到自己的项目中,功能已经非常完善。…...

输出回文数-第11届蓝桥杯选拔赛Python真题精选
[导读]:超平老师的Scratch蓝桥杯真题解读系列在推出之后,受到了广大老师和家长的好评,非常感谢各位的认可和厚爱。作为回馈,超平老师计划推出《Python蓝桥杯真题解析100讲》,这是解读系列的第23讲。 输出回文数&#…...
内存溢出会导致模块测试正常,植入系统失败
前些天,遇到了一个问题:需要在系统中添加一个小功能,单独测试,然后植入系统。 代码使用了从网上下载的函数,模块单独运行,没有问题,但是放在系统中运行就会出问题。 不得已的情况下,…...
【taro react】 ---- QRCode 二维码生成
1. 需求分析 需要将输入的值转换为图片资源;由于只是单纯的展示,所以不需要很多比如加 logo 等复杂功能;不需要后端生成,直接前端操作;使用的第三方库尽可能小,功能单一;最后选择使用 qrcode-generator 库,只有 40kb。2. 使用第三方库 qrcode-generator 3. 转换 base…...

rk3566 armbian修复usb2.0并挂载U盘
文章目录 usb接口修复一 执行命令二 修改rk3566-panther-x2.dts⽂件三 查看是否识别 U盘格式化、挂载一 U盘格式化1.1 查看U盘1.2 查看U盘文件系统类型1.3 格式化为ext4系统 二 挂载U盘2.1 手动挂载2.2 自动挂载(可选) usb接口修复 一 执行命令 将位于…...

猫头虎博主第9期赠书活动:《YOLO目标检测》计算机AI视觉实战YOLO人工智能目标检测与跟踪图像处理深度学习图像检测书籍
博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接: 🔗 精选专栏: 《面试题大全》 — 面试准备的宝典!《IDEA开发秘籍》 — 提升你的IDEA技能!《100天精通Golang》…...
python 如何将英语单词翻译成中文
要将英语单词翻译成中文,可以使用 Python 的第三方库 googletrans。该库使用 Google Translate 提供的 API 来进行翻译。 首先,需要安装 googletrans 库。可以使用以下命令在终端或命令提示符中安装: pip install googletrans4.0.0-rc1然后…...

Linux_CentOS_7.9_MySQL_5.7配置数据库服务开机自启动之简易记录
前言: 作为运维保障,都无法准确预估硬件宕机的突发阶段,其生产数据实时在产出,那作为dba数据库服务的其重要性、必要性就突显而出。这里拿虚拟机试验做个配置记录,便于大家学习参考。 # 如出现服务器重启后登入报错无…...

js实现拖动盒子查看内容 内容拖动
一.分析实现过程 1.鼠标拖动的操作是,按下鼠标不松,拖动鼠标,就需要监听鼠标点击事件(onmousedown),鼠标拖动事件(onmousemove) 2.鼠标拖动事件的监听时机,是在按下鼠标之后监听的,所以鼠标拖动事件需要放在鼠标按下事…...

[C#]winform利用seetaface6实现C#人脸检测活体检测口罩检测年龄预测性别判断眼睛状态检测
【官方框架地址】 https://github.com/ViewFaceCore/ViewFaceCore 【算法介绍】 SeetaFace6是由中国科技公司自主研发的一款人脸识别技术,它基于深度学习算法,能够快速、准确地识别出人脸,并且支持多种应用场景,如门禁系统、移动…...
c++ execl 执行 重定向
#include <unistd.h>int main() {pid_t childPid fork(); // 创建子进程if (childPid 0) {// 子进程// 关闭标准输入、输出和错误流close(STDIN_FILENO);close(STDOUT_FILENO);close(STDERR_FILENO);// 打开要写入的文件int fd open("output.txt", O_WRONLY…...

uni-app中实现元素拖动
uni-app中实现元素拖动 1、代码示例 <template><movable-area class"music-layout"><movable-view class"img-layout" :x"x" :y"y" direction"all"><img :src"musicDetail.bgUrl" :class&…...
Java系列-Class.forName和ClassLoader.loadClass的区别
Class.forName 和 ClassLoader.loadClass 是 Java 中两种加载类的方式,它们的主要区别在于加载类的时机和对异常的处理。 1.Class.forName Class.forName 是一个静态方法,用于在运行时加载类。它返回一个 Class 对象,但在加载类的过程中&am…...
找不到模块 “path“ 或其相对应的类型声明
src别名的配置 在开发项目的时候文件与文件关系可能很复杂,因此我们需要给src文件夹配置一个别名 // vite.config.ts import {defineConfig} from vite import vue from vitejs/plugin-vue import path from path export default defineConfig({plugins: [vue()],r…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...

[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...