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…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
