问题:文件重复
在微服务项目中,当有多个服务都需要使用 gRPC 通信时,每个服务目录中都会有 certs(证书文件)和 proto(协议文件)。如果有 10 个微服务,就需要维护 10 份证书和 proto 文件,这显然是不可接受的。
解决方案:pnpm workspace 共享
使用 pnpm workspace 来管理多个微服务项目,将共享资源统一存放在一个公共位置。
项目结构
microservices/
├── package.json # workspace 根配置
├── pnpm-workspace.yaml # workspace 定义
├── shared/ # 共享资源
│ ├── proto/ # 共享的 proto 文件
│ │ ├── hero.proto
│ │ └── user.proto
│ ├── certs/ # 共享的 SSL 证书
│ │ ├── ca.cer
│ │ ├── fullchain.cer
│ │ └── domain.key
│ └── generated/ # 生成的 TypeScript 代码
│ ├── hero.ts
│ └── user.ts
├── services/
│ ├── user-service/ # 用户微服务
│ │ ├── src/
│ │ └── package.json
│ ├── order-service/ # 订单微服务
│ │ ├── src/
│ │ └── package.json
│ └── gateway/ # 网关服务
│ ├── src/
│ └── package.json
└── libs/ # 共享库
└── shared-utils/
text
pnpm-workspace.yaml
packages:
- 'services/*'
- 'libs/*'
yaml
根 package.json
{
"name": "microservices",
"private": true,
"scripts": {
"proto:generate": "protoc --plugin=protoc-gen-ts_proto=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=./shared/generated -I ./shared/proto ./shared/proto/*.proto",
"dev:user": "pnpm --filter user-service dev",
"dev:order": "pnpm --filter order-service dev",
"dev:gateway": "pnpm --filter gateway dev",
"dev:all": "concurrently \"pnpm dev:user\" \"pnpm dev:order\" \"pnpm dev:gateway\""
},
"devDependencies": {
"grpc-tools": "^1.12.0",
"ts-proto": "^0.160.0",
"concurrently": "^8.0.0"
}
}
json
在各服务中引用共享资源
引用 proto 文件
// services/user-service/src/main.ts
import { join } from 'path';
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.GRPC,
options: {
package: 'user',
protoPath: join(__dirname, '../../../shared/proto/user.proto'),
// ...
},
},
);
typescript
引用生成的 TypeScript 类型
// services/user-service/src/user.controller.ts
import { User, UserServiceControllers } from '../../../shared/generated/user';
typescript
引用证书文件
// services/user-service/src/main.ts
const rootCert = fs.readFileSync(join(__dirname, '../../../shared/certs/ca.cer'));
typescript
为什么不使用 Monorepo
虽然 NestJS 的 Monorepo 模式也支持多应用管理,但在实际微服务开发中,使用 pnpm workspace 更灵活:
| 维度 | NestJS Monorepo | pnpm Workspace |
|---|---|---|
| 独立部署 | 可以,但需要共享 nest-cli.json | 每个服务完全独立 |
| 依赖管理 | 共享依赖版本 | 每个服务可以有独立依赖版本 |
| 适用场景 | 紧密耦合的微服务 | 松耦合的微服务 |
| CI/CD | 一次构建所有服务 | 每个服务独立构建 |
| 灵活性 | 受 NestJS 约束 | 完全自由 |
使用 pnpm workspace 的好处是:修改某个微服务时不需要把整个项目都跑起来,可以单独测试和部署。
↑